Files
headless-login-demo/docs/headless-employee-login-flow.md
2026-04-13 15:20:54 +09:00

5.3 KiB

Headless 사번 로그인 로직

이 문서는 사용자가 데모 애플리케이션에서 사번과 비밀번호를 이용해 로그인할 때 발생하는 내부 OIDC (OpenID Connect) Headless 인증 흐름을 설명합니다.

핵심 개념

  • Headless Login: 사용자가 IdP(Identity Provider, Baron SSO)의 로그인 화면을 거치지 않고, RP(Relying Party, 데모 앱) 내에서 직접 아이디와 비밀번호를 입력받아 백채널(Back-channel)로 인증을 수행하는 방식입니다.
  • Client Assertion: 보안을 위해 데모 앱은 사번/비밀번호를 전송할 때 자신이 신뢰할 수 있는 앱임을 증명하는 JWT(client_assertion)를 생성하여 함께 전송합니다.

1. 사번 로그인 시퀀스 다이어그램

sequenceDiagram
    autonumber
    actor User as 사용자
    participant RP as 데모 앱 (RP)
    participant OIDC as Baron SSO (OIDC/Hydra)
    participant Auth as Baron SSO (Headless API)

    User->>RP: 1. 사번 / 비밀번호 입력 후 로그인 요청
    
    note over RP: [1단계: 신호 요청]
    RP->>OIDC: 2. OIDC Discovery 및 Authorization Request<br/>(GET /oauth2/auth?response_type=code...)
    OIDC-->>RP: 3. login_challenge 발급 및 302 Redirect
    
    note over RP: [2단계: 본인 인증]
    RP->>RP: 4. Private Key로 client_assertion (JWT) 생성
    RP->>Auth: 5. Headless 로그인 API 호출<br/>(POST /api/v1/auth/headless/password/login)<br/>[client_assertion, login_challenge, 사번, 비밀번호 포함]
    Auth-->>RP: 6. 인증 성공 및 리다이렉트 URL 반환
    
    note over RP: [3단계: 권한 획득]
    RP->>OIDC: 7. 리다이렉트 URL 추적 (Cookie 유지)
    OIDC-->>RP: 8. Consent 화면 (필요 시 자동 승인 API 호출)
    OIDC-->>RP: 9. 최종 Authorization Code 발급 (code=...)
    
    note over RP: [4단계: 인증키 발급]
    RP->>OIDC: 10. Token Endpoint 호출 (Authorization Code Grant)<br/>[client_assertion 포함]
    OIDC-->>RP: 11. id_token, access_token 발급
    
    note over RP: [5단계: 로그인 완료]
    RP->>RP: 12. id_token 검증 및 사용자 세션 생성
    RP-->>User: 13. 홈 화면 리다이렉트 및 로그인 성공

2. 단계별 상세 로직 설명

위 다이어그램의 주요 단계를 데모 애플리케이션(server.jsrunHeadlessSsoLogin 함수) 로직을 중심으로 설명합니다.

[1단계] 신호 요청 (Authorization Request)

  • 목적: SSO 서버와의 세션을 시작하고, 인증 컨텍스트를 식별할 수 있는 고유값(login_challenge)을 획득합니다.
  • 동작:
    1. OIDC Discovery를 통해 엔드포인트들을 가져옵니다.
    2. response_type=code, client_id, state, nonce 등을 포함하여 Authorization Endpoint(/oauth2/auth)로 fetch 요청(리다이렉트 수동 추적 모드)을 보냅니다.
    3. 응답 헤더의 Location에 포함된 login_challenge 값을 추출합니다.

[2단계] 본인 인증 (Headless Password Login)

  • 목적: 사용자가 입력한 자격 증명(사번, 비밀번호)을 SSO 서버에 직접 전달하여 인증을 승인받습니다.
  • 동작:
    1. RP의 **Private Key(keys.json)**를 사용하여 client_assertion JWT를 서명합니다. (이때 aud 값은 SSO 서버의 Headless API URL이어야 합니다.)
    2. POST /api/v1/auth/headless/password/login 엔드포인트로 JSON 페이로드를 전송합니다.
      {
        "client_id": "...",
        "login_challenge": "...",
        "loginId": "사번",
        "password": "비밀번호",
        "client_assertion": "..."
      }
      
    3. 인증이 성공하면 서버는 OIDC 로그인 흐름을 계속할 수 있는 redirectTo 주소를 반환합니다.
  • 목적: 인증 성공 후, OIDC 프로토콜에 따라 최종적으로 Authorization Code를 획득합니다.
  • 동작:
    1. 2단계에서 받은 redirectTo 주소를 따라가며 쿠키(Cookie)를 계속 유지시킵니다.
    2. 만약 경로 중에 정보 제공 동의(consent) 화면이 감지되면, 데모 앱이 사용자 대신 백그라운드에서 동의 API(POST /api/v1/auth/consent/accept)를 호출하여 자동 승인합니다.
    3. 최종적으로 URL에 code=...가 포함된 리다이렉트를 찾습니다.

[4단계] 인증키 발급 (Token Exchange)

  • 목적: 획득한 Authorization Code를 안전한 토큰들로 교환합니다.
  • 동작:
    1. Token Endpoint로 코드를 전송합니다.
    2. 이때도 보안을 위해 private_key_jwt 방식이 사용되므로, 새로 생성한 client_assertion을 요청 본문에 포함시킵니다.
    3. 검증이 완료되면 access_token과 사용자 정보가 담긴 id_token을 받게 됩니다.

[5단계] 로그인 완료 (Session Creation)

  • 목적: 받은 토큰을 검증하고, 브라우저가 인식할 수 있는 로컬 세션을 만듭니다.
  • 동작:
    1. jose 라이브러리를 통해 id_token의 서명을 검증하고 payload(사번, 이름, 부서 등)를 추출합니다.
    2. 추출된 사용자 정보를 express-sessionreq.session.user에 저장합니다.
    3. 클라이언트 브라우저에게 세션 쿠키를 발급하며 홈 화면(/home.html)으로 리다이렉트 시킵니다.