Files
llm-wiki/vault/20-evidence/official-docs/oauth2-proxy-nginx-integration-official.md
T

17 KiB

title, source_type, url, archive_url, status, confidence, tags, related_projects, related_branches, created, last_reviewed
title source_type url archive_url status confidence tags related_projects related_branches created last_reviewed
OAuth2 Proxy — Nginx Integration (Official Docs) official-doc https://oauth2-proxy.github.io/oauth2-proxy/configuration/integrations/nginx/ raw high
keycloak-patterns
p1a-edge-forward-auth
oauth2-proxy
nginx
auth_request
official-doc
keycloak-patterns
feature-keycloak-patterns
feature-keycloak-edge-forwardauth-no-google
feature-keycloak-nginx-auth-request-integration
feature-keycloak-oauth2-proxy-oidc-flow
2026-05-25 2026-07-17

OAuth2 Proxy — Nginx Integration (Official Docs)

Layer: raw/official-docs/ — oauth2-proxy 공식 문서 중 nginx auth_request 결합 가이드. P1A 패턴 토큰 sequence 2단계(/oauth2/auth 엔드포인트)와 7단계(헤더 주입)의 1차 근거.

Parent / 활용 branch (필수)

Branch 이 자료가 정당화하는 결정
raw/branch-notes/feature-keycloak-patterns keycloak-patterns root — edge 패턴에서 nginx auth_request + oauth2-proxy 결합이 정식 통합 방식이라는 사실
raw/branch-notes/feature-keycloak-edge-forwardauth-no-google P1A — /oauth2/auth 가 요청을 프록시하지 않고 202/401 만 반환하는 subrequest 패턴 채택 근거
raw/branch-notes/feature-keycloak-nginx-auth-request-integration nginx auth_request_set + X-Auth-Request-User/Email/Access-Token 변수 매핑 + error_page 401 = @oauth2_signin; 패턴의 공식 근거
raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow OIDC code flow 의 edge subrequest 단계 + access token forwarding (--pass-access-token) 결정 근거

컨텍스트 / 왜 저장했는지

P1A의 핵심 메커니즘인 "ingress에서 ForwardAuth subrequest → 202 또는 401 응답 → 사용자 헤더를 backend에 forward" 의 공식 패턴이 어떻게 표현되는지 raw로 보존.

출처 / Source

핵심 인용 / Key quotes (verbatim)

[§Nginx auth_request directive] "The Nginx auth_request directive allows Nginx to authenticate requests via the oauth2-proxy's /auth endpoint"

[§Endpoint behavior] "only returns a 202 Accepted response or a 401 Unauthorized response without proxying the request through" — endpoint expects: "2xx: Request is authenticated, allow access" and "401 or 403: Request is not authenticated, deny access"

[§Headers] "pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag" — example: "auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email"

[§Access token] "if you enabled --pass-access-token, this will pass the token to the backend: auth_request_set $token $upstream_http_x_auth_request_access_token"

[§Sign-in redirect] "When a 401 is returned, nginx triggers the error_page directive...returns a proper 302 redirect" — named location returns 302 /oauth2/sign_in?rd=$scheme://$host$request_uri

[§Large cookies] "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"

[§Configuring for use with the Nginx auth_request directive — 전체 nginx.conf 예제, location /oauth2/location = /oauth2/auth 두 block 분리] (2026-07-17 추가, 출처: docs/versioned_docs/version-7.15.x/configuration/integrations/nginx.md raw markdown, master branch)

  location /oauth2/ {
    proxy_pass       http://127.0.0.1:4180;
    proxy_set_header Host                    $host;
    proxy_set_header X-Real-IP               $remote_addr;
    proxy_set_header X-Auth-Request-Redirect $request_uri;
    # or, if you are handling multiple domains:
    # proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
  }
  location = /oauth2/auth {
    proxy_pass       http://127.0.0.1:4180;
    proxy_set_header Host             $host;
    proxy_set_header X-Real-IP        $remote_addr;
    proxy_set_header X-Forwarded-Uri  $request_uri;
    # nginx auth_request includes headers but not body
    proxy_set_header Content-Length   "";
    proxy_pass_request_body           off;
  }

(verbatim, elide 미적용 — controller 지정에 따라 코드 블록 완전성 보존을 위해 200자 elide 규칙의 예외로 전체 보존함)

[§Browser vs API Routes] (2026-07-17 추가) "Redirecting authentication failures (302 to /oauth2/sign_in) should only be used for browser-facing routes. API or machine clients should receive a plain 401/403 response without redirect."

[§API / Machine routes (no redirect)] (2026-07-17 추가, verbatim code block)

location /api/ {
  auth_request /oauth2/auth;
  error_page 401 =401;  # Pass through the 401 status
  proxy_pass http://backend/;
}

Claims Extracted / 추출된 주장

Claim ID Claim (이 자료가 직접 말하는 것) Evidence quote Strength Applies to Does not prove
O2PN-C1 nginx 의 auth_request 디렉티브를 통해 oauth2-proxy 의 /auth 엔드포인트로 인증을 위임할 수 있다 [§Nginx auth_request directive] "The Nginx auth_request directive allows Nginx to authenticate requests via the oauth2-proxy's /auth endpoint" official-vendor-doc nginx + oauth2-proxy 통합 모든 nginx 빌드에 auth_request 가 컴파일되어 있다는 뜻은 아님 (별도 module — nginx-auth-request-module-official.md 참조)
O2PN-C2 /oauth2/auth 엔드포인트는 요청을 upstream 으로 프록시하지 않고 오직 2xx (인증됨) 또는 401/403 (거부) 만 반환 [§Endpoint behavior] "only returns a 202 Accepted response or a 401 Unauthorized response without proxying the request through" — "2xx: Request is authenticated, allow access" / "401 or 403: Request is not authenticated, deny access" official-vendor-doc oauth2-proxy subrequest mode 정상 reverse-proxy mode (/oauth2/start, /oauth2/callback) 의 동작에 적용된다는 뜻 아님 — subrequest 전용
O2PN-C3 backend 로 X-User/X-Email 헤더 전달은 oauth2-proxy 가 --set-xauthrequest 플래그로 실행되어 응답 헤더 X-Auth-Request-User/X-Auth-Request-Email 을 내보낼 때 가능 [§Headers] "pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag" — "auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email" official-vendor-doc nginx → backend 사용자 신원 전달 nginx 가 backend 가 X-User 헤더를 신뢰해도 안전하다는 뜻 아님 — 헤더 spoofing 방지는 별도 (header-stripping 결정 필요)
O2PN-C4 --pass-access-token 활성화 시 access token 은 X-Auth-Request-Access-Token 응답 헤더로 노출되며 nginx auth_request_set 으로 backend 로 전달 가능 [§Access token] "if you enabled --pass-access-token, this will pass the token to the backend: auth_request_set $token $upstream_http_x_auth_request_access_token" official-vendor-doc edge 에서 backend 로 access token forwarding access token forwarding 이 RS audience validation 을 대체한다는 뜻은 아님 (별도 RS 측 검증)
O2PN-C5 401 응답 시 nginx 가 error_page 디렉티브로 named location 트리거 → 브라우저에 302 redirect (/oauth2/sign_in?rd=...) 반환 [§Sign-in redirect] "When a 401 is returned, nginx triggers the error_page directive...returns a proper 302 redirect" — return 302 /oauth2/sign_in?rd=$scheme://$host$request_uri official-vendor-doc 미인증 브라우저 요청 처리 XHR/API 요청에 302 redirect 반환이 적절하다는 뜻 아님 — API client 별도 처리 권장
O2PN-C6 일부 provider 의 cookie 는 4KB 한도를 초과해 oauth2-proxy 가 여러 part 로 분리하며, nginx 는 기본적으로 auth_request 응답에서 첫 번째 Set-Cookie 헤더만 복사한다 [§Large cookies] "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" official-vendor-doc 큰 토큰 (Keycloak refresh token 포함 세션 등) 처리 multi-part cookie 처리 nginx 코드의 정확한 lua/scripting 방식은 본 인용 범위 밖
O2PN-C7 공식 nginx.conf 예제는 oauth2-proxy 자체 endpoint(/oauth2/callback, /oauth2/start, /oauth2/sign_out 등)를 위한 prefix location block (location /oauth2/ { ... }, X-Auth-Request-Redirect 헤더 포함)과 auth_request 대상인 /oauth2/auth 를 위한 exact-match location block (location = /oauth2/auth { ... })을 별도의 두 block으로 분리해서 정의한다 [§전체 nginx.conf 예제] 위 "핵심 인용" §Configuring for use with the Nginx auth_request directive 의 verbatim 코드 블록 (location /oauth2/ { ... } + location = /oauth2/auth { ... } 두 block, line 26-42 of fetched raw markdown) official-vendor-doc D7 — oauth2-proxy 자체 endpoint 라우팅을 location /oauth2/ prefix block 으로, auth_request 대상을 location = /oauth2/auth exact block 으로 분리하는 결정 Negative finding: 공식 예제는 location = /oauth2/auth block 에 internal; directive 를 붙이지 않는다 (fetched 원문 전체에 internal 문자열 자체가 존재하지 않음 — grep 으로 확인). 즉 공식 예제만으로는 "이 location 을 외부에서 직접 호출 불가하게 격리해야 한다"는 하드닝을 증명하지 않는다 — 이는 사용자가 예제를 넘어 추가하는 보안 결정. 또한 이 예제는 standalone nginx 설정이며, ingress-nginx annotation 방식(K8s)에 그대로 적용된다는 뜻은 아니다
O2PN-C8 공식 nginx.conf 예제의 location = /oauth2/auth block 은 # nginx auth_request includes headers but not body 라는 인라인 주석과 함께 proxy_set_header Content-Length "";proxy_pass_request_body off; 두 directive 를 포함한다 [§전체 nginx.conf 예제] "# nginx auth_request includes headers but not body" / "proxy_set_header Content-Length "";" / "proxy_pass_request_body off;" (line 39-41 of fetched raw markdown) official-vendor-doc D6 — proxy_pass_request_body off + Content-Length "" 로 auth_request subrequest 의 body 전달을 차단하는 결정 원문은 "nginx 의 auth_request 메커니즘 자체가 subrequest 에 헤더는 포함하되 body 는 포함하지 않는다"는 사실만 명시한다. 원문은 "body 를 전달하면 POST endpoint 가 의도치 않게 오발동하거나 oauth2-proxy 의 CPU 사용량이 증가한다"는 인과관계를 말하지 않는다 — 이는 branch-note D6 의 Open Risk 컬럼에 있는 사용자 추론이며 이 quote 로 증명되지 않는다. 이 두 directive 를 생략해도 nginx auth_request 자체 동작(2xx/401 판정)에 문제가 생긴다고 원문이 말하는 것도 아니다 — 원문은 단지 공식 예제가 이 설정을 포함한다는 사실만 보여준다
O2PN-C9 공식 문서는 인증 실패 시 302 redirect (/oauth2/sign_in)를 browser-facing route 에만 사용해야 하며, API/machine client 는 redirect 없는 plain 401/403 응답을 받아야 한다고 명시한다. 이를 위한 별도 예시로 location /api/ { auth_request /oauth2/auth; error_page 401 =401; proxy_pass http://backend/; } 패턴(302 redirect 없이 401 status 를 그대로 pass-through)을 제공한다 [§Browser vs API Routes] "Redirecting authentication failures (302 to /oauth2/sign_in) should only be used for browser-facing routes. API or machine clients should receive a plain 401/403 response without redirect." + [§API / Machine routes (no redirect)] verbatim 코드 블록 (error_page 401 =401; # Pass through the 401 status) official-vendor-doc D9 — 인증 실패 응답의 route 별 분기(1차 근거) / D7 부가 참고. (2026-07-17: 본 claim 을 근거로 feature-keycloak-nginx-auth-request-integration 에 D9 가 신설됨 — 최초 작성 시점엔 D9 가 없어 "D7 부가" 로만 라벨돼 있었다) 이 섹션은 backend API route (예: /api/) 의 인증 실패 응답 정책을 다루는 것이지, oauth2-proxy 자체 endpoint 라우팅(location /oauth2/ prefix block 을 쓸지, callback/start/sign_out 을 internal 로 격리할지)의 근거는 아니다 — D7 의 핵심 근거는 O2PN-C7 이며, O2PN-C9 는 부가 참고 자료로만 D7 에 연결된다. 또한 이 자료 하나만으로 "모든 API 는 반드시 401 을 그대로 반환해야 한다"는 강제 규범이 존재한다는 뜻도 아니다 — 공식 문서는 권고(should)로 표현했을 뿐

Usage Boundaries / 적용 경계

  • 이 자료가 직접 증명하는 것:
    • O2PN-C1 ~ C6: nginx auth_request + oauth2-proxy /oauth2/auth 의 공식 통합 패턴, 응답 코드 의미, 헤더 매핑 변수명, 401 redirect 패턴, large cookie 한계
    • O2PN-C7: 공식 예제가 oauth2-proxy 자체 endpoint(/oauth2/ prefix)와 auth_request 대상(/oauth2/auth exact)을 별도 location block 으로 분리한다는 사실 — D7 의 라우팅 분리 결정의 1차 근거
    • O2PN-C8: 공식 예제가 location = /oauth2/auth block 에 proxy_set_header Content-Length "" + proxy_pass_request_body off 를 포함한다는 사실 (인과관계·이유는 증명 안 함) — D6 의 1차 근거
    • O2PN-C9: 공식 문서가 302 redirect 를 browser-facing route 에만 권고하고 API/machine client 는 plain 401/403 을 받아야 한다고 명시하는 사실 — D7 부가 참고
  • 이 자료가 증명하지 않는 것:
    • nginx auth_request 모듈이 모든 distribution 의 nginx 패키지에 컴파일되어 있는지 (별도 nginx-auth-request-module-official.md)
    • backend 가 X-User 헤더를 신뢰해도 안전한 보안 전제 (header-spoofing 방어는 별도 P1A 결정)
    • --pass-access-token 가 활성화된 환경에서 access token 의 audience 가 backend RS 와 일치할 것임 (audience validator 별도 RS 책임)
    • location = /oauth2/authinternal; 로 격리해야 한다는 것 (공식 예제에 internal 자체가 없음 — O2PN-C7 negative finding)
    • proxy_pass_request_body off 를 생략하면 POST 오발동이나 CPU 증가가 발생한다는 인과관계 (O2PN-C8 does-not-prove — 원문은 설정 사실만 보여줌)
    • "모든 API 는 반드시 401 을 그대로 반환해야 한다"는 강제 규범 (O2PN-C9 는 권고(should) 표현일 뿐)
  • 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
    • 사용하는 nginx 빌드에 auth_request 모듈 포함 여부 (nginx -V 2>&1 | grep auth_request)
    • P1A 의 Keycloak realm 에서 access token 크기가 4KB 를 넘는지 (refresh token 포함 cookie split 필요 여부)
    • edge 에서 forward 되는 X-User/X-Email 의 spoofing 방지를 위해 backend 가 edge 외부 traffic 을 차단하는지
    • location = /oauth2/auth 를 외부에서 직접 호출 불가하게 만들려면 internal; 등 별도 하드닝을 사용자가 직접 추가해야 함 (공식 예제 범위 밖)

메모 / Notes (내 프로젝트 해석)

본 섹션은 자료 직접 인용 아님. P1A 결정 컨텍스트 해석.

  • /oauth2/auth요청을 프록시하지 않음 이 핵심. 일반 reverse-proxy 모드(/oauth2/start, /oauth2/callback)와 구분.
  • 401 처리는 error_page 401 = @oauth2_signin; named location 패턴 사용 → 사용자 브라우저에 302 redirect 응답.
  • auth_request_set$upstream_http_x_auth_request_user 변수명은 oauth2-proxy 응답 헤더 X-Auth-Request-User 의 nginx 변수 표현.
  • (2026-07-17) O2PN-C7C9 추가 시 렌더링된 HTML 페이지(curl)와 GitHub raw markdown(docs/versioned_docs/version-7.15.x/configuration/integrations/nginx.md, master branch, edit-URL 로 경로 확인) 두 fetch 를 대조. 둘 다 "Browser vs API Routes" 섹션을 포함 — 선행 조사에서 제기된 "렌더링된 HTML 에는 없음" 불일치는 이번 재확인(2026-07-17 시점)에서는 재현되지 않음. raw markdown 을 self-grep 의 canonical 텍스트로 채택(기존 C1C6 인용의 backtick·markdown-link 표기 스타일과 일치하기 때문).
  • O2PN-C7/C8 의 nginx.conf 코드 블록은 200자 elide 규칙의 예외로 전체 verbatim 보존 — controller 지정 사항이며, 코드 config 블록을 elide 하면 기술적 완전성이 깨지기 때문.