--- title: RFC 7636 — Proof Key for Code Exchange by OAuth Public Clients (PKCE) source_type: official-doc url: https://datatracker.ietf.org/doc/html/rfc7636 archive_url: status: raw confidence: high tags: [keycloak-patterns, p2a-spa-resource-server, p3a-single-ec2, vanilla-js, oauth2, pkce, public-client, ietf-rfc] related_projects: [keycloak-patterns] related_branches: [feature-keycloak-patterns, feature-keycloak-internal-spa-direct-no-google, feature-keycloak-single-ec2-no-google, feature-keycloak-vanilla-js-spa-pkce, feature-keycloak-pkce-flow-stages] created: 2026-05-25 last_reviewed: 2026-05-27 --- # RFC 7636 — Proof Key for Code Exchange (PKCE) > Layer: `raw/official-docs/` — IETF RFC 7636 (Standards Track) 발췌. PKCE 메커니즘의 표준 정의. ## Parent / 활용 branch (필수) | Branch | 이 자료가 정당화하는 결정 | |---|---| | [[raw/branch-notes/feature-keycloak-patterns]] | keycloak-patterns root에서 SPA/native 등 public client 패턴이 PKCE를 의무로 채택하는 표준 근거 | | [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]] | P2A SPA Direct에서 client secret 없는 public client가 PKCE로 code interception을 방어하는 근거 | | [[raw/branch-notes/feature-keycloak-single-ec2-no-google]] | P3A 단일 EC2 vanilla JS 구현에서 PKCE flow가 baseline인 표준 근거 | | [[raw/branch-notes/feature-keycloak-vanilla-js-spa-pkce]] | vanilla JS SPA의 code_verifier 생성 / S256 challenge 변환 구현 근거 | | [[raw/branch-notes/feature-keycloak-pkce-flow-stages]] | PKCE flow의 (A)~(E) 단계별 분해와 verifier-challenge chain 설계 근거 | ## 컨텍스트 P2A (Internal SPA + Resource Server) 패턴의 SPA는 **public client** — client secret을 안전하게 보관할 방법이 없음. 따라서 authorization code 탈취 시 즉시 token 교환이 가능해지는 공격 surface를 막기 위해 PKCE가 의무. "왜 SPA에 PKCE를 강제로 켜야 하나"의 1차 근거. ## 출처 / Source - 원본 URL: https://datatracker.ietf.org/doc/html/rfc7636 - 아카이브 URL: (미수집) - 저자 / 조직: IETF — N. Sakimura (Nomura Research Institute), J. Bradley (Ping Identity), N. Agarwal (Google) - 발행일: 2015-09 (RFC 7636 Standards Track) - 관련: RFC 6749 (OAuth 2.0 Core), RFC 8252 (OAuth 2.0 for Native Apps), OAuth 2.1 draft - 마지막 확인일: 2026-05-27 (WebFetch 재검증 완료 — 5개 quote 중 4개 verbatim MATCH, 1개는 quote 스타일 차이만 있음) ## 핵심 인용 / Key quotes (verbatim) > [§1 Abstract/Introduction, 2026-05-27 verified MATCH] "OAuth 2.0 public clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack." > [§1.1 Protocol Flow, 2026-05-25 capture — quoting style 차이만] "The client creates and records a secret named the code_verifier and derives a transformed version t(code_verifier) (referred to as the code_challenge)." > [§1.1 Protocol Flow, 2026-05-27 verified verbatim with single-quote markers] "The client creates and records a secret named the 'code_verifier' and derives a transformed version 't(code_verifier)' (referred to as the 'code_challenge')." > [§4.2 Client Creates the Code Challenge, 2026-05-27 verified MATCH] "code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))" > [§1.1 Protocol Flow, 2026-05-27 verified MATCH] "The authorization server transforms code_verifier and compares it to t(code_verifier) from (B). Access is denied if they are not equal." > [§1.1 Protocol Flow, 2026-05-27 verified MATCH] "An attacker who intercepts the authorization code at (B) is unable to redeem it for an access token, as they are not in possession of the code_verifier secret." (2026-05-27 note: 원본 RFC 7636 §1.1 의 "(B)" 단계 인용 출처는 §4.6 이 아닌 §1.1 Protocol Flow 내부. 2026-05-25 capture 가 §4.6 으로 잘못 식별한 것을 본 재검증에서 정정.) ## Claims Extracted / 추출된 주장 | Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove | |---|---|---|---|---|---| | PKCE-RFC7636-C1 | OAuth 2.0 public client가 Authorization Code Grant 사용 시 authorization code interception attack에 취약 | [§1 Introduction] "OAuth 2.0 public clients utilizing the Authorization Code Grant are susceptible to the authorization code interception attack." | `official-standard` | OAuth 2.0 public client (SPA, native app 등 client secret을 안전하게 보관 불가한 client) | confidential client (server-side, client secret 보호 가능) 가 동일 공격에 취약하다는 뜻은 아님 — RFC 7636의 직접 scope는 public client | | PKCE-RFC7636-C2 | PKCE의 핵심 메커니즘: client가 비밀 `code_verifier`를 생성·기록하고, 변환 함수 `t()`를 적용한 `code_challenge`를 도출 | [§1.1 Protocol Flow] "The client creates and records a secret named the 'code_verifier' and derives a transformed version 't(code_verifier)' (referred to as the 'code_challenge')." | `official-standard` | PKCE를 적용하는 모든 OAuth client | `t()`의 구체적 선택지(plain vs S256)의 보안 동등성을 말하지 않음 — §4.2에서 별도 정의 | | PKCE-RFC7636-C3 | S256 method: `code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))` (단방향 SHA-256 해시 + URL-safe Base64) | [§4.2 Client Creates the Code Challenge] "code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))" | `official-standard` | S256 method를 선택한 client (RFC 권장) | plain method도 사용 가능하나 RFC가 S256을 권장하는 정확한 위험 모델 비교는 별도 인용 필요 | | PKCE-RFC7636-C4 | Authorization server는 token 교환 시 client가 제출한 `code_verifier`를 동일한 변환 `t()`로 처리하여 (B)단계의 `code_challenge`와 비교, 불일치 시 access 거부 | [§1.1 Protocol Flow] "The authorization server transforms code_verifier and compares it to t(code_verifier) from (B). Access is denied if they are not equal." | `official-standard` | PKCE를 강제하는 Authorization Server의 token endpoint | "거부" 응답의 정확한 error code / HTTP status는 본 인용 범위 밖 (RFC 6749 error mapping에 의존) | | PKCE-RFC7636-C5 | 공격자가 (B) 단계에서 authorization code를 가로채도 `code_verifier`가 없으면 access token으로 교환 불가 | [§1.1 Protocol Flow] "An attacker who intercepts the authorization code at (B) is unable to redeem it for an access token, as they are not in possession of the code_verifier secret." | `official-standard` | code interception 공격 모델 (악성 앱이 redirect URI 가로채는 시나리오) | `code_verifier` 자체가 client device 외부로 유출된 경우의 방어는 별도 — PKCE는 transport 단계 가로채기 방어만 | ## Usage Boundaries / 적용 경계 - **이 자료가 직접 증명하는 것**: - `PKCE-RFC7636-C1`~`C5`: PKCE 표준 메커니즘 (code_verifier/challenge 생성·검증, S256 공식, 위협 모델) - **이 자료가 증명하지 않는 것**: - PKCE가 confidential client에도 의무라는 점 (RFC 7636 범위는 public client. OAuth 2.1 draft / RFC 9700에서 확장 — 본 문서 범위 밖) - `code_verifier` 길이 (43~128 char) / 허용 문자 정확한 spec — 본 발췌 인용에 포함 안 됨, §4.1 참조 권고 - Keycloak이 client별 PKCE 강제 옵션을 어떻게 노출하는지 (Keycloak vendor 문서 참조) - Implicit flow의 PKCE 적용 불가 사실 (RFC 8252에서 다룸, 본 RFC 범위 밖) - **내 프로젝트에 적용하려면 추가 확인이 필요한 것**: - Keycloak realm/client 설정에서 "Proof Key for Code Exchange Code Challenge Method = S256" 강제 설정 위치 - vanilla JS SPA에서 `crypto.subtle.digest('SHA-256', ...)` + `base64url` encoding 호환성 (IE/구형 브라우저 미지원, modern only) - code_verifier를 sessionStorage에 둘 때 XSS 노출 위험과 single-page lifetime 일치성 ## P2A/P3A 함의 (내 프로젝트 해석) > 본 섹션은 자료 직접 인용이 아닌 패턴 결정 컨텍스트 해석. wiki 추출 시 `wiki/concepts/` 또는 `wiki/projects/` source-summary로 옮겨야 함. - `code_verifier`: 43~128 byte 길이의 `[A-Z][a-z][0-9]-._~` random string (§4.1). - Method: - `plain`: `code_challenge = code_verifier` — **권장 안 함**. - `S256`: `BASE64URL(SHA256(verifier))` — 표준 선택지. Keycloak도 client 설정에서 강제 가능. - 공격 시나리오 (mobile / SPA 공통): redirect URI를 가로채는 악성 앱/스크립트가 code를 캡처 → 정상 client보다 먼저 `/token` 호출. PKCE 없으면 토큰 발급, 있으면 verifier 불일치로 거부. - OAuth 2.1 draft는 PKCE를 **모든 client (confidential 포함)**에 의무화 — RFC 7636의 범위를 public client에서 전체로 확장. - ID 흐름 (Implicit)은 PKCE 적용 불가 — 그래서 RFC 8252 / OAuth 2.1에서 deprecated. ## 메모 / Notes - 2026-05-27 re-verification: WebFetch 재확인 완료. 5개 quote 모두 verbatim MATCH (C2 는 single-quote vs underscore quoting style 차이만 — 의미 동일하므로 official-standard 유지). C4/C5 의 anchor 가 §4.6/§1 가 아닌 §1.1 Protocol Flow 임을 정정. - code_verifier 길이/문자셋 규칙 (§4.1) 은 본 raw에 직접 인용으로 보관 안됨 — 후속 raw 또는 wiki/concepts 정리 시 추가 발췌 필요. ## Related / 관련 - 같은 주제 다른 official-doc: - [[raw/official-docs/security-oauth2-pkce-rfc-8252]] — RFC 8252가 native app에서 PKCE를 MUST로 의무화 - 인용하는 branch: - [[raw/branch-notes/feature-keycloak-patterns]] - [[raw/branch-notes/feature-keycloak-internal-spa-direct-no-google]] - [[raw/branch-notes/feature-keycloak-single-ec2-no-google]] - [[raw/branch-notes/feature-keycloak-vanilla-js-spa-pkce]] - [[raw/branch-notes/feature-keycloak-pkce-flow-stages]] - 인용한 wiki 요약: (미작성)