I have docker-compose configuration where my web-app and keycloak containers run on a private internal network. Any public access to these containers is via a nginx container that reverse-proxies as appropriate. Internally, my web-app will communicate directly to keycloak via its REST api at
http://keycloak:8080/auth/admin/..., i.e., the
hostname:port known within the docker network. This works like a charm, until ...
Recently I added support in my web-app's REST api to initiate a reset of a user's password using keycloak's
PUT /auth/admin/realms/{realm}/users/{uid}/execute-actions-email?client_id={client_id}&redirect_uri={redirect_uri}&lifespan=7200. My first problem was discovering that the generated link delivered in the email had this href:
http://keycloak:8080/auth/realms/{REALM}/login-actions/action-token?key={JWT}
Clearly, that host:port wouldn't work! It appears when generating the URI keycloak uses the connection information to generate the return URI rather than the client ID's root url. My initial fix was to set the
Host header (in the session used by the web-app) to the public domain, e.g., if my public domain is
example.com,
Host: example.com, then the link in the email becomes:
http://example.com/auth/realms/{REALM}/login-actions/action-token?key={JWT}
This worked great in my development environment where everything is over http. But in my production environment we use https to communicate with nginx which then reverse-proxies internally via http, so when keycloak receives the the request after the user clicks the link (http), nginx redirects the request to https and then I receive this error from keycloak:
We are sorry...
An error occurred, please login again through your application.Looking at keycloak logs I see this:
16:06:44,971 WARN [org.keycloak.events] (default task-6) type=EXECUTE_ACTION_TOKEN_ERROR, realmId=MyRealm, clientId=null, userId=d6884db2-4fd4-437c-a3b5-9fb01ab04eab, ipAddress=XX.XX.XX.XX, error=not_allowed, reason='Invalid token issuer. Expected 'https://example.com/auth/realms/MyRealm', but was 'http://example.com/auth/realms/MyRealm'', token_id=9ec60517-7b9e-4747-b23e-363d7272a559, action=execute-actionsLooking at the JWT, I see, in part:
{
"iss": "http://example.com/auth/realms/TaxCreditPortal",
"aud": "http://example.com/auth/realms/TaxCreditPortal",
}
And that seems to be the mismatch: the JWT has http, but the connection is coming over https.
I then tried setting the Host header to
example.com:443, but that didn't work either, I see this in the error:
Expected 'https://example.com/auth/realms/MyRealm', but was 'http://example.com:443/auth/realms/MyRealm''Surely, I can't be the first to attempt this. What am I doing wrong?!?!?
Thanks!