How to force users to login again after their session was closed in keycloak?
Hi!
I´m currently trying to set up Openresty as reverse proxy with Keycloak as IdP in Kubernetes.
Accessing the proxied service works as expected and I also can logout from the proxied service via
However, when I terminate the user's session in Keycloak, the user can still refresh and use the site. I want the user to have to log in again when the session is closed. How can i achieve this?
Environment
- openresty-version: openresty/1.21.4.1
- lua-resty-openidc version: 1.7.6-3
- OpenID Connect provider: Keycloak: 19.0.1 - Community
Expected behaviour
Users have to log in again, when their session is closed in Keycloak.
Actual behaviour
When i sign out all active sessions in Keycloak the user can still use and refresh the proxied site without logging in again.
Configuration and NGINX server log files
default.conf:
upstream backend {
server nginx-test:80;
}
server {
listen 8080;
root /opt/nginx/html;
resolver kube-dns.kube-system.svc.cluster.local;
# disabled caching so the browser won't cache the site
expires 0;
add_header Cache-Control private;
lua_ssl_verify_depth 2;
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.pem;
# log paths
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
access_by_lua_block {
local opts = {
redirect_uri = "/redirect_uri",
discovery = "<my-keycloak-url>/realms/<realm-name>/.well-known/openid-configuration",
client_id = "<client-id>",
client_secret = "<client_secret>",
scope = "openid",
redirect_uri_scheme = "https",
logout_path = "/logout",
redirect_after_logout_uri = "<my-keycloak-url>/realms/<realm-name>/protocol/openid-connect/logout",
redirect_after_logout_with_id_token_hint = false,
ssl_verify = true,
session_contents = { id_token = true},
}
local res, err = require("resty.openidc").authenticate(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
ngx.req.set_header("X-USER", res.id_token.sub)
}
location / {
proxy_pass http://backend;
# set headers
# https://www.keycloak.org/server/reverseproxy
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}
Client Settings in Keycloak:
Client authentication: On
Authorization: Off
Authentication flow:
- Standard flow: On
- Direct access grants: On
- Implicit flow: Off
- Service accounts roles: Off
- OAuth 2.0 Device Authorization Grant: Off
- OIDC CIBA Grant: Off
I appreciate any help!
authenticate doesn't normally check whether a token is revoked before it expires as this would have a major performance impact. The usual approach is to make token lifetimes really short so the window of time between token revocation and expiration becomes small. If you can not limit token life time to an acceptable value opts.refresh_session_interval may be another option which would check whether the login is still valid on a regular basis.
Thanks for your answer!
I'm not sure I completely understood the first suggested solution.
In Keycloak there is only an option to limit the lifespan for the access token and in the nginx.conf there are only options for the access token aswell.
Am I missing something or do I need an access_token in my session_contents to make use of the token lifetimes?
I have added the refresh_session_interval option to the local options. The user now has to log in again when opening a new tab with the protected web page after the session was terminated in Keycloak. However, the user can still use the protected page in an active tab.
What I meant with the first option was something like "limit the access token lifespan to two minutes and just accept a token could be used for the remaining max two minutes of its lifespan even after it has been revoked". This is often an acceptable compromise.
For the second option: when refresh_session_interval elapses lua-resty-openidc will trigger a so called "silent" authentication in which the client is redirected to the authorization endpoint with parameter prompt=none which is supposed to return a new authorization code if the OIDC provider still thinks the session is valid and an error otherwise. This implies the OIDC provider knows about the user's login state. Please don't assume anybody here would know anything specific to any OIDC provider.
If you use two different tabs that share the same lua-resty-openidc session cookie than I can not explain why a fresh tab should behave any different from an already existing one. What you may be seeing could be a timing issue. lua-resty-openidc will only trigger the silent authentication redirect once the configured interval has passed since the user has last been logged in. If you log out the user this period may not have expired, yet.
Thanks again now I get it!
I have set the refresh_session_interval = 60 and it seems like i was mistaken the user can still use the page.
nginx/error.log
2023/04/25 14:53:24 [error] 6#6: *299 [lua] openidc.lua:1098: authenticate(): unhandled request to the redirect_uri: /redirect_uri?error=login_required&state=c1f159c1e579b0bec23e8f2be60a91a8, client: 10.1.11.0, server: , request: "GET /redirect_uri?error=login_required&state=c1f159c1e579b0bec23e8f2be60a91a8 HTTP/1.1", host: "<public-url-of-my-proxied-service>"
2023/04/25 14:53:49 [error] 6#6: *547 [lua] openidc.lua:1098: authenticate(): unhandled request to the redirect_uri: /redirect_uri?error=login_required&state=7f5878339a2891c83fbe3f85e05a7dbe, client: 10.1.11.0, server: , request: "GET /redirect_uri?error=login_required&state=7f5878339a2891c83fbe3f85e05a7dbe HTTP/1.1", host: "<public-url-of-my-proxied-service>"
keycloak.log
2023-04-25 14:51:25,267 WARN [org.keycloak.services.managers.AuthenticationManager] (executor-thread-558) Some clients have been not been logged out for user <user> in testnginx realm: nginx
2023-04-25T14:51:45.644128121Z 2023-04-25 14:51:45,642 WARN [org.keycloak.protocol.oidc.utils.AcrUtils] (executor-thread-558) Invalid realm configuration (ACR-LOA map)
2023-04-25T14:54:45.757080442Z 2023-04-25 14:54:45,756 WARN [org.keycloak.events] (executor-thread-558) type=LOGIN_ERROR, realmId=be5515cd-0c52-473c-b0b8-3ca9905a0413, clientId=null, userId=null, ipAddress=10.18.1.208, error=invalid_request
2023-04-25 14:54:59,818 WARN [org.keycloak.protocol.oidc.utils.AcrUtils] (executor-thread-558) Invalid realm configuration (ACR-LOA map)
2023-04-25T14:55:40.179911220Z 2023-04-25 14:55:40,179 WARN [org.keycloak.protocol.oidc.utils.AcrUtils] (executor-thread-558) Invalid realm configuration (ACR-LOA map)
Seems like there is a issue with in keycloak configuration. I will investigate this further. Appreciate any suggestions!
The nginx logs look as if silent re-authentication failed - keycloak redirects back with a "login_required" error. This looks fine.
For this calls openidc.authenticate should return a non-nil errand your code should enter the branch that ends up sending a 403 status back to the client.