LabHub

Keycloak 과 기업 인증 · 애플리케이션 연동(리다이렉트·PKCE) · 실습

authorization code + PKCE 흐름 완주하기

LabHub 에서 이어서 보기

목표

authorization code + PKCE 흐름을 SDK 없이 처음부터 끝까지 수행하고, PKCE 와 state 가 각각 무엇을 막는지 실패 케이스로 확인한다.

왜 중요한가

OIDC 라이브러리를 쓰면 이 흐름은 함수 호출 두 번입니다. 그래서 무엇이 일어나는지 모르는 채로 쓰게 되고, 문제가 생기면 어디를 봐야 할지 모릅니다. 이 실습에서 각 단계를 손으로 하면 세 가지가 분명해집니다. 첫째, 인가 코드가 브라우저 URL 에 노출되지만 왜 그것만으로는 쓸모없는지. 둘째, code_verifier 를 모르면 왜 교환이 실패하는지 — 6번 스텝에서 직접 실패시켜 봅니다. 셋째, state 가 없으면 왜 공격자가 피해자를 자기 계정에 로그인시킬 수 있는지. 마지막 리프레시 회전까지 보면 실무에서 권장되는 조합(짧은 액세스 토큰 + 리프레시 회전)이 왜 블랙리스트 없이도 무효화 효과를 내는지 이해됩니다.

Keycloak 시작에 40~90초가 걸리므로 앞선 실습을 마치고 오면 대개 준비돼 있습니다.

단계

1. /root/pk/pkce.pycode_verifier(43~128자, URL 안전 문자)와 code_challenge 를 만들어 /root/pk/verifier.txt/root/pk/challenge.txt 에 각각 한 줄씩 저장한다.
2. /root/pk/authz_url.txt 에 인가 요청 URL 을 한 줄 적는다. 대상은 사전 임포트된 렐름 labhub 의 공개 클라이언트 web-app 이고 리다이렉트 URI 는 http://127.0.0.1:8161/callback 이다. response_type=code, client_id, redirect_uri, scope=openid, state, code_challenge, code_challenge_method=S256 이 모두 있어야 한다.
3. 쿠키 항아리를 유지하며 그 URL 을 GET 해 로그인 폼의 action URL 을 /root/pk/action.txt 에 저장한다. http 로 시작해야 한다.
4. 사용자 dev1 / 비밀번호 Dev1!pass 를 POST 해 리다이렉트 응답의 Location 에서 인가 코드를 뽑아 /root/pk/code.txt 에 저장한다. 20자 이상이어야 한다.
5. 토큰 엔드포인트에 grant_type=authorization_code, 코드, redirect_uri, client_id, code_verifier 를 보내 토큰을 받는다. /root/pk/tokens.jsonaccess_tokenrefresh_token 이 있어야 한다.
6. 새 인가 코드를 받아 틀린 code_verifier 로 교환을 시도한다. /root/pk/pkce_fail.jsonerrorinvalid_grant 여야 한다.
7. /root/pk/state_check.py 는 인자 두 개(보낸 state, 받은 state)를 받아 같으면 종료 코드 0, 다르면 1 로 끝난다. 일치·불일치 두 경우의 결과를 /root/pk/state.outmatch=ok mismatch=rejected 로 적는다.
8. 리프레시 토큰으로 갱신해 /root/pk/refresh.json 을 만든다. /root/pk/rotation.txtrotated=<true|false> 를 적는다. 판단 근거는 새 리프레시 토큰이 이전과 다른지이다.

참고

단계 8개

  1. code_verifier 와 challenge 만들기
  2. 인가 요청 URL 조립하기
  3. 로그인 폼의 action 추출하기
  4. 자격 증명 POST 해서 코드 받기
  5. 코드를 토큰으로 교환하기
  6. 틀린 verifier 로 실패 확인하기
  7. state 불일치 검증 구현하기
  8. 리프레시와 회전 확인하기