You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

oauth2-proxy与Keycloak集成后登出重定向失效问题排查

问题:Keycloak + oauth2-proxy登出后重定向失效

环境配置

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。

原因分析

  1. oauth2-proxy登出流程逻辑限制:BACKEND_LOGOUT_URL是oauth2-proxy在后端发起的请求,用于触发Keycloak的登出操作。Keycloak返回的重定向响应是发给oauth2-proxy的后端请求,而非直接返回给浏览器。oauth2-proxy完成后端登出后,会自行处理浏览器的重定向,不会转发Keycloak的重定向响应。

  2. 缺少登出后重定向配置:当前oauth2-proxy未设置OAUTH2_PROXY_POST_LOGOUT_REDIRECT_URI环境变量,导致登出后默认重定向到根路径/,而非期望的https://DOMAIN.de/welcome。

  3. BACKEND_LOGOUT_URL中的post_logout_redirect_uri参数无效:该参数仅作用于oauth2-proxy与Keycloak的后端交互,无法控制浏览器的最终跳转地址,因此即使配置了该参数,也不会影响用户看到的跳转结果。

解决建议

  1. 添加oauth2-proxy登出重定向配置:在oauth2-proxy的环境变量中加入:

    OAUTH2_PROXY_POST_LOGOUT_REDIRECT_URI: "https://DOMAIN.de/welcome"
    

    该参数将直接控制oauth2-proxy在完成后端登出后,引导浏览器跳转的目标地址。

  2. 清理无效参数:移除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的登出参数要求即可。

  3. 验证Keycloak客户端配置:确保Keycloak中oauth2-proxy客户端的Valid Post Logout Redirect URIs列表包含https://DOMAIN.de/welcome(手动访问正常说明该配置已存在,可再次确认)。

内容的提问来源于stack exchange,提问作者Flo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:52:02