I'm building an app that follows a microservice architecture – mainly to learn how to set up microservices the right way.
Right now, I'm running both Keycloak and my auth service in separate Docker containers, and both containers are in the same Docker network.
I'm intentionally not using docker-compose, and I'd like to keep it that way.
The goal:
Users should be able to log in via a /login route that redirects them to Keycloak. Once they’re authenticated, the access token is stored in a browser cookie. This setup works perfectly fine locally (when not running in Docker).
The issue starts when I run the app inside Docker:
The problem is I need to configure two different Keycloak URLs:
KEYCLOAK_URL=http://keycloak:8080
KEYCLOAK_PUBLIC_URL=http://localhost:8080
KEYCLOAK_URL is used by the backend (inside Docker) to talk to
KEYCLOAK_PUBLIC_URL is used by the browser to redirect users to Keycloak for login
I can’t use http://localhost:8080 in the container, because that points to the container itself. And I can’t use http://keycloak:8080 in the browser, because keycloak is not a valid public hostname.
This leads to an issuer mismatch problem: Keycloak issues tokens with iss=http://localhost:8080, but my backend talks to http://keycloak:8080.
❓My question:
What’s the best way to solve this, without splitting Dev and Prod logic or maintaining different configs? I want to keep high Dev/Prod parity – meaning, my development setup should reflect how it would work in production.
If you have tips, experience, or best practices for handling this kind of setup with Docker and Keycloak, I’d really appreciate your input! 🙏