//////

OAuth 2.1 BFF Session Architecture: PKCE, Refresh-Token Confinement, CSRF/State Binding, and Third-Party-Cookie Failure Modes

OAuth 2.1 계열의 browser app 인증에서 BFF(Backend-for-Frontend) session architecture는 “브라우저에 OAuth access token·refresh token을 보관하지 않고, same-origin backend가 OAuth client 역할과 token 보관을 맡으며, 브라우저에는 애플리케이션 session cookie만 노출하는” 패턴이다. 이 구조는 SPA가 localStorage/sessionStora

//////

Summary#

OAuth 2.1 계열의 browser app 인증에서 BFF(Backend-for-Frontend) session architecture는 “브라우저에 OAuth access token·refresh token을 보관하지 않고, same-origin backend가 OAuth client 역할과 token 보관을 맡으며, 브라우저에는 애플리케이션 session cookie만 노출하는” 패턴이다. 이 구조는 SPA가 localStorage/sessionStorage/IndexedDB 등에 token을 저장하는 위험과 refresh token 탈취 위험을 줄이지만, session cookie 기반 구조가 되므로 CSRF, session fixation, cookie scope, SameSite, third-party-cookie 차단, OAuth state/PKCE/redirect URI 검증 실패를 별도로 다뤄야 한다.

핵심 설계는 다음과 같다: browser → BFF는 first-party session cookie로 인증하고, BFF → Authorization Server는 authorization code flow를 사용하며, BFF가 confidential client라 하더라도 PKCE를 적용해 authorization code interception·mix-up 계열 위험을 줄인다. BFF는 refresh token을 서버 측 vault/DB/HSM/KMS 경계 안에 보관하고, 브라우저에는 refresh token을 절대 전달하지 않는다. OAuth callback에서는 state를 단순 random 값이 아니라 browser session, redirect target, issuer/client configuration, PKCE verifier record와 결합해 검증해야 한다. OIDC를 함께 쓰는 경우 nonce는 ID Token replay·substitution 방어 목적으로 별도 검증한다.

Third-party-cookie failure mode는 특히 “silent refresh”와 “embedded login iframe”에서 중요하다. 브라우저가 third-party cookies를 차단하면 SPA가 hidden iframe으로 Authorization Server 세션을 재사용해 token을 조용히 갱신하는 방식은 실패하거나 불안정해진다. BFF 패턴은 애플리케이션 도메인의 first-party session cookie를 중심으로 동작하므로 이 실패 모드를 완화할 수 있지만, Authorization Server가 별도 사이트에 있고 front-channel redirect가 필요한 한, 로그인 UX·SSO UX·iframe 기반 세션 확인 기능은 브라우저 cookie 정책 변화의 영향을 받을 수 있다.

Key Points#

  • BFF의 보안 경계
  • 브라우저는 OAuth token holder가 아니라 애플리케이션 session holder로 취급한다.
  • access token과 refresh token은 BFF 또는 BFF 뒤의 token service에만 저장한다.
  • 브라우저 JavaScript가 access token·refresh token을 읽을 수 없게 하는 것이 핵심이다.
  • BFF가 API 호출을 대신 수행하거나, 내부 API에 token을 붙여 proxy한다.
  • session cookie는 HttpOnly, Secure, 적절한 SameSite, 제한된 Path/Domain, 짧은 idle timeout/absolute timeout 정책을 가져야 한다.

  • OAuth 2.1 방향성과 browser app

  • OAuth 2.1 방향성은 implicit flow와 resource owner password credentials 같은 과거 패턴을 제거하고 authorization code flow + PKCE를 중심으로 정리한다.
  • browser-based app guidance는 token을 browser storage에 보관하는 위험을 강조하며, BFF/token-mediating backend 같은 서버 보조 패턴을 더 안전한 선택지로 다룬다.
  • BFF가 confidential client라 해도 PKCE는 defense-in-depth로 유용하다. code가 front-channel을 통과하고 callback endpoint가 노출되는 이상, authorization code injection·interception·mix-up 방어를 PKCE와 state 검증에 의존하는 구간이 남는다.

  • PKCE 구현 계약

  • code_verifier는 충분히 랜덤해야 하며, authorization attempt별로 1회성으로 생성한다.
  • 가능한 경우 code_challenge_method=S256만 허용하고 plain downgrade를 피한다.
  • BFF는 code_verifier를 서버 측 transient store에 저장하고, browser에는 원문을 노출하지 않는다.
  • code_verifier record는 state, browser session id, redirect URI, issuer, client id, 생성 시각, 만료 시각과 함께 묶어 저장한다.
  • callback 처리 후에는 verifier/state record를 즉시 폐기해 replay와 다중 탭 혼선을 줄인다.

  • Refresh-token confinement

  • refresh token은 browser에 내려보내지 않는다.
  • BFF 내부에서도 refresh token은 평문 로그, analytics, crash report, client-visible error에 절대 포함하지 않는다.
  • 저장 시 envelope encryption, KMS/HSM, DB column-level encryption, token hash/fingerprint, access control, audit log를 고려한다.
  • refresh token rotation 또는 sender-constrained refresh token을 사용하면 탈취·재사용 탐지에 도움이 된다.
  • rotation reuse가 감지되면 정상 client retry와 attacker replay를 완벽히 구분할 수 없으므로, token family 폐기와 재인증 정책을 명확히 해야 한다.
  • BFF scale-out 환경에서는 refresh race를 막기 위해 per-session lock, token family 상태 전이, idempotency window, 짧은 grace policy를 신중히 설계해야 한다.

  • CSRF와 state binding

  • BFF 구조는 OAuth token 탈취 위험을 줄이지만, cookie-based session으로 전환되는 만큼 CSRF 방어가 필수다.
  • 애플리케이션 API에는 SameSite cookie만 믿지 말고 CSRF token, double-submit pattern, origin/referer 검증, Fetch Metadata header 검증 등을 threat model에 맞게 결합한다.
  • OAuth authorization request의 state는 callback CSRF 방어의 핵심이다.
  • state는 단순 random nonce가 아니라 다음 항목에 bind하는 것이 안전하다:
    • pre-login browser session 또는 login transaction id
    • code_verifier record
    • expected issuer / authorization server
    • client id
    • redirect URI
    • post-login return URL
    • 생성 시각과 짧은 만료 시간
  • return URL을 state 안에 직접 넣거나 신뢰하면 open redirect로 이어질 수 있으므로 allowlist 또는 server-side handle 방식을 사용한다.

  • OIDC noncestate의 분리

  • state는 주로 OAuth callback CSRF 및 authorization response binding에 사용된다.
  • nonce는 OIDC ID Token replay/substitution 방어에 사용된다.
  • 둘을 같은 난수에서 파생할 수는 있어도 검증 목적과 검증 위치는 분리해야 한다.
  • ID Token을 사용하는 경우 issuer, audience, expiry, nonce, signature, key id/JWKS rotation 처리를 함께 검증한다.

  • Third-party-cookie failure modes

  • hidden iframe silent refresh는 Authorization Server cookie가 third-party context로 취급될 때 실패할 수 있다.
  • Safari ITP, Firefox ETP, Chrome의 third-party-cookie 제한/단계적 폐지 정책은 iframe 기반 SSO 확인, prompt=none, silent token renewal을 불안정하게 만든다.
  • BFF는 애플리케이션 도메인의 first-party session cookie를 사용하므로 SPA token silent refresh보다 안정적일 수 있다.
  • 그러나 사용자가 Authorization Server와 상호작용해야 하는 login redirect, federated logout, IdP session check iframe, cross-site SSO UX는 여전히 browser cookie policy의 영향을 받는다.
  • SameSite 설정이 너무 엄격하면 OAuth redirect callback에서 session correlation cookie가 누락될 수 있고, 너무 느슨하면 CSRF 표면이 커진다.
  • 일반적으로 OAuth login transaction correlation cookie는 redirect 흐름을 고려해 SameSite=Lax 또는 별도 짧은 수명 cookie를 검토하고, cross-site iframe 의존은 줄이는 방향이 안전하다.

  • Failure-mode checklist

  • 브라우저 localStorage에 refresh token 저장.
  • BFF가 access token을 JSON으로 브라우저에 반환.
  • state를 검증하지 않거나, session과 bind하지 않음.
  • state record를 여러 로그인 시도에서 재사용.
  • callback의 code를 PKCE verifier와 정확히 매칭하지 않음.
  • redirect URI를 prefix/wildcard로 느슨하게 비교.
  • issuer/client metadata mix-up을 검증하지 않음.
  • refresh token rotation reuse detection이 token family 단위로 작동하지 않음.
  • silent refresh iframe을 핵심 세션 유지 메커니즘으로 가정.
  • SameSite 설정 변경 후 OAuth callback correlation이 깨짐.
  • BFF API가 cookie 인증만 있고 CSRF 방어가 없음.
  • logout이 BFF session, refresh token, upstream IdP session의 범위를 혼동함.

Cautions#

  • 현재 실행 환경에는 사용자가 지시한 WebSearch/WebFetch 도구가 제공되지 않아, 실제 공개 웹 검색 결과 선택 및 원문 fetch 검증을 수행할 수 없었다. 아래 내용은 공개 표준·BCP·브라우저 문서로 알려진 URL을 기반으로 한 capsule 초안이다.
  • OAuth 2.1은 OAuth 2.0 관련 RFC와 security BCP를 통합·정리하는 방향의 사양이므로, 구현 시점에는 사용하는 draft/RFC 버전과 authorization server의 실제 지원 범위를 확인해야 한다.
  • BFF가 항상 SPA보다 “자동으로 안전하다”는 뜻은 아니다. token exposure 위험은 줄지만, cookie session, CSRF, server-side token vault, proxy authorization, logout propagation, operational compromise 위험이 새로 생긴다.
  • PKCE는 authorization code interception 방어에 강하지만 XSS, compromised BFF, open redirect, malicious browser extension, IdP compromise, weak session cookie 설정을 해결하지 않는다.
  • SameSite cookie 동작은 브라우저·버전·redirect 방식·top-level navigation 여부에 따라 차이가 있을 수 있다. OAuth callback correlation cookie 설계는 실제 대상 브라우저에서 테스트해야 한다.
  • Third-party-cookie 차단은 silent refresh와 iframe 기반 SSO 확인을 불안정하게 만들지만, 모든 redirect 기반 로그인 자체가 차단된다는 의미는 아니다. top-level redirect 기반 authorization code flow는 일반적으로 iframe silent refresh보다 호환성이 높다.
  • Refresh token rotation에서 reuse를 탐지해도 정상 클라이언트의 중복 요청·네트워크 재시도·공격자 replay를 완벽히 구분할 수 없다. 재인증, grace window, token family revoke 범위는 제품 보안 정책으로 명시해야 한다.
  • 이 초안은 특정 vendor SDK의 behavior를 일반화하지 않는다. Auth0, Okta, Microsoft Entra, Cognito 등은 BFF·SPA·refresh token 정책에 서로 다른 제한과 확장을 둘 수 있다.

Sources#

  • https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/
  • https://datatracker.ietf.org/doc/draft-ietf-oauth-browser-based-apps/
  • https://www.rfc-editor.org/rfc/rfc7636
  • https://www.rfc-editor.org/rfc/rfc6749
  • https://www.rfc-editor.org/rfc/rfc9700
  • https://openid.net/specs/openid-connect-core-1_0.html
  • https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
  • https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html

Sagwan Revalidation 2026-07-30T10:37:01Z#

  • verdict: ok
  • note: BFF·PKCE·토큰 격리·CSRF/3PC 위험 설명은 현재도 유효함

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1