Keycloak and Spring Boot web app in dockerized environment
Asked Answered
F

2

14

Consider the following environment:

  • one docker container is keycloak
  • another docker container is our web app that uses keycloak for authentication

The web app is a Spring Boot application with "keycloak-spring-boot-starter" applied. In application.properties:

keycloak.auth-server-url = http://localhost:8028/auth

A user accessing our web app will be redirected to keycloak using the URL for the exposed port of the keycloak docker container. Login is done without problems in keycloak and the user (browser) is redirected to our web app again. Now, the authorization code needs to be exchanged for an access token. Hence, our web app (keycloak client) tries to connect to the same host and port configured in keycloak.auth-server-url. But this is a problem because the web app resides in a docker container and not on the host machine, so it should rather access http://keycloak:8080 or something where keycloak is the linked keycloak docker container.

So the question is: How can I configure the keycloak client to apply different URLs for browser redirection and access token endpoints?

Frenzy answered 26/7, 2019 at 5:23 Comment(1)
Duplicate: #50671234Southwestwardly
P
11

There used to be another property auth-server-url-for-backend-requests but was removed by pull request #2506 as a solution to issue #2623 on Keycloak's JIRA. In the description of this issue, you'll find the reasons why and possible workarounds: that should be solved at the DNS level or by adding entries to the host file.

So there is not much you can do in the client configuration, unless you change the code and make your own version of the adapter, but there is something you can do at the Docker level. For this to work properly, first I suggest you use a fully qualified domain name instead of localhost for the public hostname, as you would in production anyway, eg. keycloak.mydomain.com. You can use a fake one (not registered in DNS servers) if you just add it to the host's /etc/hosts file (or Windows equivalent) as an alias next to localhost.

Then, if you are using Docker Compose, you can set aliases (alternative hostnames) for the keycloak service on the docker network to which the containers are connected (see doc: Compose File reference / Service configuration reference / networks / aliases). For example:

version: "3.7"

services:
  keycloak:
    image: jboss/keycloak
    networks:
      # Replace 'mynet' with whatever user-defined network you are using or want to use
      mynet:
        aliases:
          - keycloak.mydomain.com

  webapp:
    image: "nginx:alpine"
    networks:
      - mynet

networks:
  mynet:

If you are just using plain Docker, you can do the equivalent with --alias flag of docker network connect command (see doc: Container networking / IP address and hostname).

Perse answered 28/7, 2019 at 17:26 Comment(4)
Thank you for the answer. While I am testing this approach I have to expose the keycloak port on 8080 to my docker host because the port must be same for access from browser and from my webapp. So I need to assume this port is always available on the docker host, or do I miss something?Frenzy
Yes, I was assuming the same port be used in both cases (access from browser outside or from webapp docker container). You could use different ports, eg. by putting the webapp behind a reverse-proxy that rewrites "Location" headers (eg. Nginx + http_proxy_module's proxy_redirect directive) to just change the keycloak server port (and nothing else) in the proxied redirect responses from the webapp, but I'm not sure whether Keycloak will accept getting code/token on one port, then reusing it on another. To be tested.Perse
This is perfect for testing a compose environment on your local machine with keycloak. Thank you!Chaff
To make testing for non techies even easier if set up an dns entry like localhost.mydomain.com pointing to 127.0.0.1 - as long as people are online it works without modifying their /etc/hosts fileSaari
C
0

Accepted version doesn't work on Quarkus releases of Keycloak.

In the latest Keycloak version you are able to set Frontend URL in the realm settings, but that won't work, because Spring Security will throw an error that issuer provided in the configuration isn't matching the one specified Issue on Spring Security Github.

Just for local development you can use network_mode: service:[service name] option. Not recommended for production environment.

version: "3"

services: 
  localhost:
    image: alpine:latest
    command: sleep infinity
    ports:
      - "8080:8080"
      - "1234:1234"
  keycloak:
    image: quay.io/keycloak/keycloak:latest
    network_mode: "service:localhost"
    ...
    other options
    ...
  web-app:
    network_mode: "service:localhost"
    environment:
      PORT: 1234
      KEYCLOAK_URL: http://localhost:8080
    ...
    other options
    ...

That way, web-app and keycloak containers are able to request each other using localhost. localhost container exposes ports to the host network, so you are able to access Keycloak and your application. That way - url used by your app internally and url used in your browser in the login flow are the same and it works.

Crinose answered 7/6 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.