forked from baron/baron-sso
5.0 KiB
5.0 KiB
DevFront OIDC 인증 흐름 및 무한 루프 해결 보고
이 문서는 devfront 개발자 포털의 OIDC 인증 구현 방식, 무한 루프 문제의 원인 및 해결 방법, 그리고 클라이언트 자동 등록 원리에 대해 설명합니다.
1. DevFront 로그인 동작 플로우 (OIDC Authorization Code Flow)
시퀀스 다이어그램
sequenceDiagram
actor User
participant DF as DevFront (RP)
participant HY as Ory Hydra (OP)
participant UF as UserFront (Login UI)
participant KR as Ory Kratos (Identity)
User->>DF: 로그인 버튼 클릭
DF->>HY: 인증 요청 (/oauth2/auth)
HY->>UF: 로그인 UI 리다이렉트
UF->>User: 로그인 페이지 표시
User->>UF: 자격 증명 입력 (Email/PW)
UF->>KR: 인증 수행
KR-->>UF: 인증 성공 (Session 생성)
UF->>HY: 로그인 승인 요청
HY->>User: 권한 동의(Consent) 화면 표시
User->>HY: '허용' 클릭
HY-->>DF: 인증 코드와 함께 리다이렉트 (/callback?code=...)
DF->>HY: 토큰 교환 요청 (Code -> ID/Access Token)
HY-->>DF: 토큰 발급
Note over DF: [FIX] 백엔드 /api/me 호출 대신<br/>ID Token에서 프로필 정보 직접 추출
DF->>User: 대시보드 및 프로필 표시
단계별 설명
-
인증 요청 (Login Request):
- 사용자가
devfront(localhost:5174)의 로그인 버튼을 클릭합니다. react-oidc-context라이브러리가 Hydra의/oauth2/auth엔드포인트로 사용자를 리다이렉트합니다.- 이때 클라이언트 ID(
devfront), 리다이렉트 URI, Scope 등을 파라미터로 전달합니다.
- 사용자가
-
사용자 인증 (Authentication):
- Hydra는 현재 세션이 없음을 확인하고, 설정된 로그인 UI(
userfront)로 사용자를 보냅니다. - 사용자는
userfront에서 아이디/비밀번호를 입력하여 Kratos를 통해 인증을 마칩니다.
- Hydra는 현재 세션이 없음을 확인하고, 설정된 로그인 UI(
-
권한 동의 (Consent):
- 인증이 완료되면 Hydra는 사용자에게
devfront앱이 요청한 권한(openid, profile, email 등)을 허용할지 묻는 Consent 화면을 띄웁니다. - 사용자가 '허용'을 누르면 Hydra는
devfront가 신뢰할 수 있는 앱임을 기록합니다.
- 인증이 완료되면 Hydra는 사용자에게
-
인증 코드 전달 및 토큰 교환 (Callback):
- Hydra는 사용자를
devfront의 콜백 페이지(http://localhost:5174/callback?code=...)로 보냅니다. devfront는 이 코드를 Hydra의 토큰 엔드포인트로 보내 ID Token과 Access Token을 발급받습니다.
- Hydra는 사용자를
-
사용자 정보 로드 (Profile Recovery):
devfront는 발급받은 ID Token의 Payload를 디코딩하여 사용자 이름, 이메일 등의 프로필 정보를 즉시 화면에 렌더링합니다.
2. 클라이언트 자동 등록의 원리
사용자가 직접 devfront를 클라이언트로 등록하지 않았음에도 로그인이 가능한 이유는 인프라 설정 파일인 compose.ory.yaml에 정의된 init-rp 컨테이너 덕분입니다.
init-rp 서비스의 역할
- Ory 스택(Kratos, Hydra, Keto)이 모두 정상 가동된 직후 실행됩니다.
- Hydra Admin API를 호출하여 서비스 운영에 필수적인 기본 클라이언트들을 자동으로 생성합니다.
자동 등록된 devfront 명세
hydra clients create
--endpoint http://hydra:4445
--id devfront
--grant-types authorization_code,refresh_token
--response-types code
--scope openid,offline_access,profile,email
--token-endpoint-auth-method none \ # Public Client (PKCE 사용)
--callbacks http://localhost:5174/callback;
이 설정으로 인해 devfront라는 ID의 클라이언트가 미리 존재하게 되며, localhost:5174로의 리다이렉션이 안전하게 허용됩니다.
3. 무한 루프 문제 해결 분석
발생 원인 (Problem)
devfront가 로그인 성공 후 사용자 정보를 가져오기 위해 백엔드 API인/api/v1/user/me를 호출했습니다.- 이 API는 백엔드 세션 쿠키를 기반으로 동작하도록 설계되어 있었습니다.
- 하지만 브라우저 보안 정책(SameSite/Cross-Domain)으로 인해
localhost에서 보낸 요청에는sso-test.hmac.kr도메인의 쿠키가 포함되지 않았습니다. - 결과: 백엔드는 401 Unauthorized를 반환 ->
devfront는 401을 받으면 다시 로그인을 시도하도록 구현되어 있어 무한 루프가 발생했습니다.
해결 방법 (Solution)
- 쿠키 의존성 제거:
AppLayout.tsx에서 백엔드 호출(fetchMe)을 삭제했습니다. - ID Token 직접 활용: 이미 OIDC 인증 성공 시점에 전달받은 **ID Token(
auth.user.profile)**에 필요한 모든 사용자 정보가 들어있으므로, 이를 직접 사용하도록 수정했습니다. - 표준 RP 구조 확립: 이제
devfront는 백엔드의 세션 쿠키를 전혀 사용하지 않으며, API 요청 시에도Authorization: Bearer <token>헤더를 사용하여 정당한 권한을 증명합니다.