oauth2-proxy与Keycloak集成后登出重定向失效问题排查
环境配置
Docker Compose配置
keycloak: build: . #image: quay.io/keycloak/keycloak:24.0.2 environment: KC_HOSTNAME: ${KC_HOSTNAME:-DOMAIN.de} KC_PROXY: edge KC_HTTP_RELATIVE_PATH: /auth PROXY_ADDRESS_FORWARDING: true KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} command: start ports: - '8080:8080' depends_on: - postgres_db user: root # Run the container with root user *This solved the issue!* oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0-alpine environment: OAUTH2_PROXY_BACKEND_LOGOUT_URL: "https://DOMAIN.de/auth/realms/master/protocol/openid-connect/logout?post_logout_redirect_uri=https://DOMAIN.de/welcome&id_token_hint={id_token}" OAUTH2_PROXY_PROVIDER: keycloak-oidc OAUTH2_PROXY_CLIENT_ID: oauth2-proxy OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET} OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET} OAUTH2_PROXY_EMAIL_DOMAINS: "*" OAUTH2_PROXY_EXTRA_JWT_ISSUER: "https://DOMAIN.de/auth/realms/master=asdf-client-credential" OAUTH2_PROXY_HTTP_ADDRESS: "0.0.0.0:4180" OAUTH2_PROXY_OIDC_ISSUER_URL: "https://DOMAIN.de/auth/realms/master" OAUTH2_PROXY_PASS_ACCESS_TOKEN: true OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER: true OAUTH2_PROXY_SET_AUTHORIZATION_HEADER: true OAUTH2_PROXY_PASS_USER_HEADERS: true OAUTH2_PROXY_REDIRECT_URL: "https://DOMAIN.de/oauth2/callback" OAUTH2_PROXY_REVERSE_PROXY: true OAUTH2_PROXY_SCOPE: "openid profile email" OAUTH2_PROXY_SET_XAUTHREQUEST: true OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS: true OAUTH2_PROXY_SSL_INSECURE_SKIP_VERIFY: false OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: true OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST: 'true' OAUTH2_PROXY_SKIP_AUTH_HEADER: 'true' ports: - "4180:4180" depends_on: - keycloak
Nginx配置
server { add_header 'X-Debug-Headers' '$http_x_auth_request_access_token'; #error_log /var/log/nginx/debug.log debug; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name mythicaltable.top www.mythicaltable.top; # managed by Certbot add_header 'Content-Security-Policy' 'upgrade-insecure-requests'; add_header X-Frame-Options SAMEORIGIN; add_header X-XSS-Protection "1; mode=block"; add_header x-auth-request-access-token "$http_x_auth_request_access_token"; proxy_busy_buffers_size 512k; proxy_buffers 4 512k; proxy_buffer_size 256k; include /etc/nginx/mime.types; location /auth/ { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Port $server_port; } location /welcome { proxy_pass http://localhost:4000/welcome; } location / { proxy_pass http://localhost:4000; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Auth-Request-Redirect $request_uri; auth_request /oauth2/auth; error_page 401 = /oauth2/sign_in; auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email; proxy_set_header Accept-Encoding *; proxy_set_header X-User $user; proxy_set_header X-Email $email; auth_request_set $token $upstream_http_x_auth_request_access_token; proxy_set_header X-Access-Token $token; auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; # When using the --set-authorization-header flag, some provider's cookies can exceed the 4kb # limit and so the OAuth2 Proxy splits these into multiple parts. # Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response, # so if your cookies are larger than 4kb, you will need to extract additional cookies manually. auth_request_set $auth_cookie_name_upstream_1 $upstream_cookie_auth_cookie_name_1; # Extract the Cookie attributes from the first Set-Cookie header and append them # to the second part ($upstream_cookie_* variables only contain the raw cookie content) if ($auth_cookie ~* "(; .*)") { set $auth_cookie_name_0 $auth_cookie; set $auth_cookie_name_1 "auth_cookie_name_1=$auth_cookie_name_upstream_1$1"; } # Send both Set-Cookie headers now if there was a second part if ($auth_cookie_name_upstream_1) { add_header Set-Cookie $auth_cookie_name_0; add_header Set-Cookie $auth_cookie_name_1; } } location /oauth2/ { proxy_pass http://oauth2_proxy; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; } }
问题描述
通过DOMAIN.de/oauth2/sign_out登出时,后端Keycloak会话已成功清除,但浏览器未重定向至post_logout_redirect_uri指定的https://DOMAIN.de/welcome;手动访问Keycloak的登出URL(替换{id_token}为实际值)可正常跳转;移除BACKEND_LOGOUT_URL中的id_token_hint参数会触发Keycloak报错;Keycloak已配置Backchannel logout会话必填,登出URL设置为https://DOMAIN.de/oauth2/sign_out。
原因分析
oauth2-proxy登出流程逻辑限制:
BACKEND_LOGOUT_URL是oauth2-proxy在后端发起的请求,用于触发Keycloak的登出操作。Keycloak返回的重定向响应是发给oauth2-proxy的后端请求,而非直接返回给浏览器。oauth2-proxy完成后端登出后,会自行处理浏览器的重定向,不会转发Keycloak的重定向响应。缺少登出后重定向配置:当前oauth2-proxy未设置
OAUTH2_PROXY_POST_LOGOUT_REDIRECT_URI环境变量,导致登出后默认重定向到根路径/,而非期望的https://DOMAIN.de/welcome。BACKEND_LOGOUT_URL中的post_logout_redirect_uri参数无效:该参数仅作用于oauth2-proxy与Keycloak的后端交互,无法控制浏览器的最终跳转地址,因此即使配置了该参数,也不会影响用户看到的跳转结果。
解决建议
添加oauth2-proxy登出重定向配置:在oauth2-proxy的环境变量中加入:
OAUTH2_PROXY_POST_LOGOUT_REDIRECT_URI: "https://DOMAIN.de/welcome"该参数将直接控制oauth2-proxy在完成后端登出后,引导浏览器跳转的目标地址。
清理无效参数:移除
BACKEND_LOGOUT_URL中的post_logout_redirect_uri参数,修改为:OAUTH2_PROXY_BACKEND_LOGOUT_URL: "https://DOMAIN.de/auth/realms/master/protocol/openid-connect/logout?id_token_hint={id_token}"保留
id_token_hint以满足Keycloak的登出参数要求即可。验证Keycloak客户端配置:确保Keycloak中
oauth2-proxy客户端的Valid Post Logout Redirect URIs列表包含https://DOMAIN.de/welcome(手动访问正常说明该配置已存在,可再次确认)。
内容的提问来源于stack exchange,提问作者Flo

