1

I am deploying Keycloak and a Spring Boot application in two different docker containers, and Keycloak is securing the application.

The problem is that the user logs in via the browser, and so they see the Keycloak server on an address like localhost:8080, while the Spring Boot application is running on a docker container next to it and so sees the service on a host like keycloak_service.

The Spring Boot application receives a token from the user that Keycloak gave him and sees that it's signed by localhost:8080 but it was expecting it to be signed by keycloak_service. It then gives the error 15:29:12.062 [http-nio-29000-exec-8] ERROR o.k.a.r.AdapterRSATokenVerifier - Didn't find publicKey for kid: b4A5E3xbvc-ulr-w_u38p7aHRZIi9O36Na7I8r_L76M

So far I have been using a temporary fix of having the application use the host networking stack so that it can see keycloak at localhost:8080. I will eventually need to change this though as I need other features of the docker bridge networks.

There are various other hacky solutions to the problem I could use, but I can't help but feel this shouldn't be a difficult problem. I can't be the only one running a spring boot app alongside a Keycloak instance in containers. I would have thought the natural solution would be to tell Spring Boot that it can talk to keycloak on keycloak_service but that the same Keycloak instance is also known as localhost:8080 to some clients and it should accept tokens signed by that as well. Is this possible to do? If not, is there any other normal solution to this problem?

J Person
  • 1,099
  • 1
  • 10
  • 15

2 Answers2

2

Your issue here is that you need to get Keycloak properly accessible externally, not only inside the server itself. The docker container ids like keycloak_service are valid for internal service communication, but here you've got the browser requesting the url, so there's no point on using it.

For my concrete case, I had a nginx proxy configured for this job, assigning the server two names, but proxy forwarding to the port I was interested in.

As an example, imagine you call your server myapp.com and auth.myapp.com. Then let's suppose you publish the port 8080 for your keycloak server and 8081 for your application. You'd need to configure nginx kind of this way:

server {
  server_name myapp.com;
  location / {
    proxy_pass http://127.0.0.1:8081;
  }
}
server {
  server_name auth.myapp.com;
  location / {
    proxy_pass http://127.0.0.1:8080;
  }
}

After that, you set up your client to work with auth.myapp.com. Also don't forget to configure keycloak to work behind a proxy (you might need to rebuild the docker image with the proper configuration).

See also:

Aritz
  • 30,971
  • 16
  • 136
  • 217
-1

As I don't have the reputation for adding comments I am going this way.

I have a similar setup as @Xtreme Biker has described above, but still my app cannot communicate with keycloak by using the server_name configured in the nginx config. I am able to call myapp.com from my browser which then redirects to auth.myapp.com (keycloak) for login. After successful login keycloak redirects back to myapp.com with a valid authorization_code (as I can see while debugging). Then myapp.com tries to exchange the authorization_code by calling http://auth.myapp.com/auth/realms/my-relam/protocol/openid-connect/token but it is not able to connect and fails with: java.net.ConnectException: Connection refused (Connection refused).

Anyone having similar issues found a solution for that?

Soner
  • 213
  • 3
  • 9