TL;DR

  • SSO 소셜 로그인 시스템 구축 가이드의 핵심 개념과 실무 적용 포인트를 함께 정리한 글이다.
  • SSO 소셜 로그인 시스템 구축 가이드를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.
  • 원문 전체는 아래 상세 내용에 그대로 포함했다.

1. 개념

SSO 소셜 로그인 시스템 구축 가이드의 핵심 개념과 실무 적용 포인트를 함께 정리한 글이다.

2. 배경

SSO 소셜 로그인 시스템 구축 가이드가 등장한 배경과 문제 상황을 이해하는 데 도움이 된다.

3. 이유

SSO 소셜 로그인 시스템 구축 가이드를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.

4. 특징

SSO 소셜 로그인 시스템 구축 가이드의 특징, 장단점, 적용 포인트를 원문에서 자세히 확인할 수 있다.

5. 상세 내용

SSO 소셜 로그인 시스템 구축 가이드

1. SSO의 등장 배경과 역사

1.1 비밀번호 피로 (Password Fatigue)

┌─────────────────────────────────────────────────────────────────────────────┐
│                    비밀번호 피로 (Password Fatigue)                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  현대인의 계정 현실:                                                       │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────┐               │
│  │  평균적인 사용자가 관리하는 계정 수: 80~100개            │               │
│  │  기억할 수 있는 비밀번호 수: 3~5개                       │               │
│  │  비밀번호 재사용률: 약 65%                               │               │
│  │  비밀번호 관련 보안 사고: 전체 침해의 81% (Verizon DBIR) │               │
│  └─────────────────────────────────────────────────────────┘               │
│                                                                             │
│  결과적으로 발생하는 문제:                                                 │
│                                                                             │
│  사용자 측:                                                                │
│  ├── 동일 비밀번호 여러 사이트에 재사용 → 한 곳 유출 시 전체 위험          │
│  ├── "비밀번호 찾기" 반복 → 서비스 이탈 (전환율 하락)                      │
│  ├── 복잡한 비밀번호 정책 → 포스트잇에 적어놓기                            │
│  └── 가입 피로 → "회원가입 너무 귀찮아서 그냥 안 쓸래"                     │
│                                                                             │
│  서비스 측:                                                                │
│  ├── 비밀번호 저장/관리 부담 (해싱, 솔팅, 정책 관리)                       │
│  ├── 고객센터 문의의 20~30%가 비밀번호 관련                                │
│  ├── Credential Stuffing 공격 대응 비용                                    │
│  └── 회원가입 전환율 저하 (가입 폼이 길수록 이탈률 증가)                   │
│                                                                             │
│  해결책의 진화:                                                            │
│  ├── 1단계: SSO (한 번 로그인으로 여러 서비스)                             │
│  ├── 2단계: 소셜 로그인 (이미 가진 계정으로 가입)                          │
│  ├── 3단계: Passwordless (비밀번호 자체를 없앰)                            │
│  └── 4단계: Passkeys (생체인식 기반, 2024~현재)                            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 SSO 프로토콜의 역사적 발전

┌─────────────────────────────────────────────────────────────────────────────┐
│                    SSO 프로토콜 발전 타임라인                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1988  Kerberos (MIT Project Athena)                                       │
│  ├── 해결한 문제: 네트워크상에서 비밀번호가 평문으로 전송되는 위험         │
│  ├── 핵심 기술: 대칭키 암호화, 티켓 기반 인증                              │
│  ├── 구조: KDC(Key Distribution Center) → TGT → Service Ticket            │
│  ├── 한계: 같은 네트워크(Realm) 내에서만 동작, 웹에 부적합                 │
│  └── 현재: Windows Active Directory의 기본 인증 프로토콜로 여전히 사용     │
│                                                                             │
│  2002  SAML 1.0 → 2005 SAML 2.0 (OASIS)                                   │
│  ├── 해결한 문제: 웹 기반 크로스 도메인 SSO                                │
│  ├── 핵심 기술: XML 기반 Assertion, HTTP Redirect/POST Binding             │
│  ├── 구조: SP(Service Provider) ←→ IdP(Identity Provider)                  │
│  ├── 한계: XML 복잡성, 모바일/API 환경에 부적합, 무거운 메타데이터         │
│  └── 현재: 기업 환경(Okta, Azure AD, ADFS)에서 여전히 광범위 사용         │
│                                                                             │
│  2007  OAuth 1.0 (Twitter + Google 주도)                                   │
│  ├── 해결한 문제: 제3자 앱에 비밀번호 없이 API 접근 권한 위임              │
│  ├── 핵심 기술: 서명 기반 인증 (HMAC-SHA1)                                 │
│  ├── 한계: 서명 계산이 복잡, 구현 어려움, 모바일 지원 부족                 │
│  └── 현재: 사실상 사용되지 않음 (Twitter도 OAuth 2.0으로 이전)             │
│                                                                             │
│  2012  OAuth 2.0 (RFC 6749, IETF)                                          │
│  ├── 해결한 문제: 간단한 권한 위임 프레임워크                              │
│  ├── 핵심 기술: Bearer Token, Authorization Code, 다양한 Grant Type        │
│  ├── 핵심 변화: 서명 제거 → HTTPS 필수, 단순화된 토큰 교환                 │
│  ├── 한계: "인가(Authorization)" 전용, "인증(Authentication)" 표준 부재    │
│  └── 현재: 거의 모든 API 접근 제어의 기반                                  │
│                                                                             │
│  2014  OpenID Connect (OIDC, OpenID Foundation)                            │
│  ├── 해결한 문제: OAuth 2.0 위에 표준 인증 레이어 추가                     │
│  ├── 핵심 기술: ID Token(JWT), UserInfo Endpoint, Discovery                │
│  ├── 구조: OAuth 2.0 + Identity Layer = 인증 + 인가 동시 해결              │
│  └── 현재: 소셜 로그인의 사실상 표준 (Google, Kakao, Apple 등)             │
│                                                                             │
│  진행중  OAuth 2.1 (IETF Draft)                                            │
│  ├── 해결할 문제: OAuth 2.0의 레거시 Grant Type 정리, 보안 강화            │
│  ├── 주요 변경: PKCE 필수화, Implicit Grant 제거, Password Grant 제거      │
│  ├── Refresh Token Rotation 권장 → 필수                                    │
│  └── 상태: 2024년 기준 Draft 단계, 2025~2026 최종 표준화 목표              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

1.3 기업 SSO vs 소셜 로그인

┌─────────────────────────────────────────────────────────────────────────────┐
│                    기업 SSO vs 소셜 로그인 비교                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────────┬──────────────────────────────┐           │
│  │      기업 SSO (Enterprise)  │      소셜 로그인 (Social)    │           │
│  ├──────────────────────────────┼──────────────────────────────┤           │
│  │ 프로토콜: SAML 2.0 주력     │ 프로토콜: OAuth 2.0 + OIDC   │           │
│  │ IdP: Okta, Azure AD, ADFS  │ IdP: Google, Kakao, Naver    │           │
│  │ 대상: 임직원                │ 대상: 일반 사용자 (B2C)      │           │
│  │ 관리: IT 부서가 중앙 관리   │ 관리: 사용자 자율 선택       │           │
│  │ 계정: 회사가 생성/관리      │ 계정: 사용자가 이미 보유     │           │
│  │ 목적: 사내 시스템 통합 인증 │ 목적: 가입 편의성 + 전환율   │           │
│  │ 보안: MFA 강제, 정책 관리   │ 보안: Provider에 위임        │           │
│  │ 사례: Jira+Confluence+Slack │ 사례: 쇼핑몰, 커뮤니티, 앱   │           │
│  └──────────────────────────────┴──────────────────────────────┘           │
│                                                                             │
│  이 문서의 초점:                                                           │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  소셜 로그인 시스템 구축 (B2C 서비스)                       │           │
│  │  ├── OAuth 2.0 + OIDC 기반                                 │           │
│  │  ├── Kakao, Google, Naver, Apple Provider 연동              │           │
│  │  ├── 백엔드 아키텍처 + DB 설계 + 보안                      │           │
│  │  └── 프로덕션 수준의 구현 가이드                            │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2. 핵심 프로토콜 상세 분석

2.1 OAuth 2.0 (RFC 6749) - 4가지 Grant Type

Authorization Code Grant (서버 앱 - 가장 안전)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Authorization Code Grant Flow                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  사용 시나리오: 서버 사이드 웹 애플리케이션 (Spring Boot, Django 등)        │
│  보안 수준: 최고 (client_secret이 서버에만 존재)                           │
│                                                                             │
│  User          Browser         App Server        Auth Server                │
│   │               │                │                  │                     │
│   │ 1. 로그인     │                │                  │                     │
│   │──────────────>│                │                  │                     │
│   │               │ 2. GET /login  │                  │                     │
│   │               │───────────────>│                  │                     │
│   │               │                │                  │                     │
│   │               │ 3. 302 Redirect                   │                     │
│   │               │<───────────────│                  │                     │
│   │               │ Location: auth-server/authorize   │                     │
│   │               │   ?response_type=code             │                     │
│   │               │   &client_id=abc123               │                     │
│   │               │   &redirect_uri=https://app/cb    │                     │
│   │               │   &scope=openid email profile     │                     │
│   │               │   &state=xyz789                   │                     │
│   │               │                │                  │                     │
│   │               │ 4. 인증 페이지 ──────────────────>│                     │
│   │<──────────────│ (로그인 + 동의 화면)              │                     │
│   │               │                │                  │                     │
│   │ 5. ID/PW 입력 │                │                  │                     │
│   │──────────────>│───────────────────────────────────>│                     │
│   │               │                │                  │                     │
│   │               │ 6. 302 Redirect (code 포함)       │                     │
│   │               │<──────────────────────────────────│                     │
│   │               │ Location: https://app/cb          │                     │
│   │               │   ?code=AUTH_CODE_HERE             │                     │
│   │               │   &state=xyz789                   │                     │
│   │               │                │                  │                     │
│   │               │ 7. GET /cb?code=...               │                     │
│   │               │───────────────>│                  │                     │
│   │               │                │                  │                     │
│   │               │                │ 8. POST /token   │                     │
│   │               │                │   code=AUTH_CODE  │                     │
│   │               │                │   client_id=abc   │                     │
│   │               │                │   client_secret=  │                     │
│   │               │                │   grant_type=     │                     │
│   │               │                │   authorization_  │                     │
│   │               │                │   code            │                     │
│   │               │                │─────────────────>│                     │
│   │               │                │                  │                     │
│   │               │                │ 9. Token Response│                     │
│   │               │                │<─────────────────│                     │
│   │               │                │  {               │                     │
│   │               │                │   access_token,  │                     │
│   │               │                │   refresh_token, │                     │
│   │               │                │   id_token,      │                     │
│   │               │                │   expires_in     │                     │
│   │               │                │  }               │                     │
│   │               │                │                  │                     │
│   │               │ 10. 로그인 완료│                  │                     │
│   │               │<───────────────│                  │                     │
│   │<──────────────│ (세션 쿠키)    │                  │                     │
│                                                                             │
│  핵심 보안 포인트:                                                         │
│  ├── code는 일회용 + 짧은 수명 (보통 30초~10분)                            │
│  ├── client_secret은 서버→서버 통신에서만 사용 (브라우저 노출 없음)         │
│  ├── state 파라미터로 CSRF 공격 방지                                       │
│  └── Token 교환은 Back-Channel (서버 간 직접 통신)                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Implicit Grant (SPA - 현재 비권장)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Implicit Grant (비권장 - OAuth 2.1에서 제거 예정)              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  과거 SPA(Single Page Application)를 위해 설계됨                           │
│                                                                             │
│  특징:                                                                     │
│  ├── Code 교환 과정 없이 Access Token을 URL Fragment로 직접 반환           │
│  │   예: https://app.com/callback#access_token=xyz&token_type=bearer       │
│  ├── client_secret 불필요 (SPA는 secret을 안전하게 보관 불가)              │
│  └── Refresh Token 미지원                                                  │
│                                                                             │
│  비권장 이유:                                                              │
│  ├── Token이 URL에 노출 → 브라우저 히스토리, Referer 헤더로 유출 위험      │
│  ├── Token 탈취 시 바로 사용 가능 (추가 검증 없음)                         │
│  ├── Refresh Token 없어서 사용자 경험 나쁨 (자주 재로그인)                 │
│  └── PKCE가 등장하면서 SPA도 Authorization Code + PKCE 사용 가능           │
│                                                                             │
│  현재 권장: Authorization Code + PKCE (아래 참조)                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Client Credentials Grant (서버 to 서버)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Client Credentials Grant                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  사용 시나리오: 마이크로서비스 간 통신, 배치 작업, 관리 API 호출            │
│  특징: 사용자 개입 없음, 애플리케이션 자체가 인증                           │
│                                                                             │
│  App Server                              Auth Server                       │
│      │                                       │                             │
│      │ POST /token                           │                             │
│      │   grant_type=client_credentials       │                             │
│      │   client_id=service-a                 │                             │
│      │   client_secret=secret123             │                             │
│      │   scope=api:read                      │                             │
│      │──────────────────────────────────────>│                             │
│      │                                       │                             │
│      │ { access_token: "...", expires_in }   │                             │
│      │<──────────────────────────────────────│                             │
│                                                                             │
│  소셜 로그인에서의 활용:                                                   │
│  ├── 카카오 Admin API 호출 (사용자 목록 조회, 메시지 발송 등)              │
│  ├── Provider의 서버 관리 API 접근                                        │
│  └── 사용자 인증과는 무관 (앱 자체의 권한)                                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Resource Owner Password Credentials Grant (레거시)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Resource Owner Password Grant (레거시 - 사용 금지)             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  사용자의 ID/비밀번호를 직접 받아서 토큰 교환                              │
│                                                                             │
│  POST /token                                                               │
│    grant_type=password                                                     │
│    username=user@example.com                                               │
│    password=secret123                                                      │
│    client_id=my-app                                                        │
│                                                                             │
│  왜 사용하면 안 되는가:                                                    │
│  ├── 앱이 사용자 비밀번호에 직접 접근 → OAuth의 근본 목적에 반함            │
│  ├── 피싱 공격과 구분 불가능                                               │
│  ├── MFA 지원 불가                                                         │
│  └── OAuth 2.1에서 공식 제거                                               │
│                                                                             │
│  유일한 예외: 자사 앱이 자사 인증 서버를 사용하는 마이그레이션 과도기       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 OAuth 2.1 (진행 중인 표준)

┌─────────────────────────────────────────────────────────────────────────────┐
│              OAuth 2.1 - OAuth 2.0의 진화                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  목표: OAuth 2.0 + 보안 Best Practice를 하나의 표준으로 통합               │
│  상태: IETF Draft (2024~2026, draft-ietf-oauth-v2-1)                       │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  OAuth 2.0 → OAuth 2.1 주요 변경사항                        │           │
│  ├─────────────────────────────────────────────────────────────┤           │
│  │                                                             │           │
│  │  1. PKCE 필수화                                             │           │
│  │     - 모든 Authorization Code 요청에 PKCE 필수              │           │
│  │     - SPA뿐 아니라 서버 앱도 포함                           │           │
│  │     - code_verifier + code_challenge (S256)                 │           │
│  │                                                             │           │
│  │  2. Implicit Grant 제거                                     │           │
│  │     - response_type=token 더 이상 지원하지 않음             │           │
│  │     - SPA는 Authorization Code + PKCE 사용                  │           │
│  │                                                             │           │
│  │  3. Resource Owner Password Grant 제거                      │           │
│  │     - grant_type=password 더 이상 지원하지 않음             │           │
│  │                                                             │           │
│  │  4. Refresh Token 보안 강화                                 │           │
│  │     - Sender-Constrained 또는 Rotation 필수                 │           │
│  │     - 한 번 사용된 Refresh Token은 무효화                   │           │
│  │                                                             │           │
│  │  5. Bearer Token 전송 방식 제한                             │           │
│  │     - Authorization 헤더만 허용                             │           │
│  │     - URL 쿼리 파라미터 전송 금지                           │           │
│  │                                                             │           │
│  │  6. Redirect URI Exact Match                                │           │
│  │     - 와일드카드 Redirect URI 금지                          │           │
│  │     - 정확한 URI 매칭만 허용                                │           │
│  │                                                             │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  실무 영향:                                                                │
│  ├── 신규 구현: OAuth 2.1 기준으로 구현하면 됨                             │
│  ├── 기존 시스템: PKCE 추가, Implicit/Password Grant 비활성화              │
│  └── 대부분의 Provider(Google, Kakao)는 이미 2.1 수준 지원                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.3 OpenID Connect (OIDC)

┌─────────────────────────────────────────────────────────────────────────────┐
│              OpenID Connect = OAuth 2.0 + Identity Layer                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  핵심 개념:                                                                │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  OAuth 2.0 = "이 앱이 당신의 데이터에 접근해도 될까요?"     │           │
│  │              (인가 = Authorization = 권한 위임)             │           │
│  │                                                             │           │
│  │  OIDC      = "당신이 누구인지 알려주세요"                   │           │
│  │              (인증 = Authentication = 신원 확인)             │           │
│  │                                                             │           │
│  │  OIDC = OAuth 2.0 + ID Token + UserInfo + Discovery        │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  OIDC가 추가하는 것:                                                       │
│                                                                             │
│  1. ID Token (JWT)                                                         │
│     ├── 사용자 신원 정보를 담은 서명된 JWT                                 │
│     ├── Access Token과 함께 발급                                           │
│     ├── 클라이언트가 직접 검증 가능 (서버 호출 불필요)                     │
│     └── Claims: sub, iss, aud, exp, iat, nonce, email, name 등            │
│                                                                             │
│  2. UserInfo Endpoint                                                      │
│     ├── GET /userinfo (Access Token으로 호출)                              │
│     ├── ID Token보다 상세한 사용자 정보 반환                               │
│     └── 예: 프로필 사진, 생년월일, 전화번호 등                             │
│                                                                             │
│  3. Discovery Document                                                     │
│     ├── GET /.well-known/openid-configuration                              │
│     ├── Provider의 모든 엔드포인트, 지원 기능을 자동 발견                  │
│     └── 클라이언트 자동 설정에 활용                                        │
│                                                                             │
│  4. 표준 Scope                                                             │
│     ├── openid (필수) - OIDC 요청임을 표시                                │
│     ├── profile - 이름, 사진 등                                            │
│     ├── email - 이메일 주소                                                │
│     ├── phone - 전화번호                                                   │
│     └── address - 주소                                                     │
│                                                                             │
│  Discovery Document 예시:                                                  │
│  {                                                                         │
│    "issuer": "https://kauth.kakao.com",                                    │
│    "authorization_endpoint": "https://kauth.kakao.com/oauth/authorize",    │
│    "token_endpoint": "https://kauth.kakao.com/oauth/token",                │
│    "userinfo_endpoint": "https://kapi.kakao.com/v1/oidc/userinfo",         │
│    "jwks_uri": "https://kauth.kakao.com/.well-known/jwks.json",            │
│    "scopes_supported": ["openid", "profile", "account_email"],             │
│    "response_types_supported": ["code"],                                   │
│    "id_token_signing_alg_values_supported": ["RS256"]                      │
│  }                                                                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.4 PKCE (Proof Key for Code Exchange, RFC 7636)

┌─────────────────────────────────────────────────────────────────────────────┐
│              PKCE - Authorization Code Interception 방지                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  문제: SPA/모바일 앱은 client_secret을 안전하게 보관할 수 없음             │
│  해결: 매 요청마다 동적으로 생성하는 일회용 키 쌍으로 code 탈취 방지       │
│                                                                             │
│  동작 원리:                                                                │
│                                                                             │
│  Client                              Auth Server                           │
│    │                                     │                                 │
│    │ 1. code_verifier 생성 (랜덤 문자열) │                                 │
│    │    "dBjftJeZ4CVP-mB92K27uhbUJU1p..."│                                 │
│    │                                     │                                 │
│    │ 2. code_challenge 계산              │                                 │
│    │    = BASE64URL(SHA256(code_verifier))│                                 │
│    │    "E9Melhoa2OwvFrEMTJguCHaoeK1t..." │                                 │
│    │                                     │                                 │
│    │ 3. /authorize                       │                                 │
│    │    ?code_challenge=E9Mel...          │                                 │
│    │    &code_challenge_method=S256       │                                 │
│    │──────────────────────────────────── >│                                 │
│    │                                     │ (Auth Server가                  │
│    │                                     │  code_challenge를 저장)         │
│    │ 4. code 반환                        │                                 │
│    │<──────────────────────────────────── │                                 │
│    │                                     │                                 │
│    │ 5. POST /token                      │                                 │
│    │    code=AUTH_CODE                    │                                 │
│    │    code_verifier=dBjftJeZ4CVP...    │                                 │
│    │──────────────────────────────────── >│                                 │
│    │                                     │ (Auth Server가                  │
│    │                                     │  SHA256(code_verifier)          │
│    │                                     │  == 저장된 code_challenge       │
│    │                                     │  검증)                          │
│    │                                     │                                 │
│    │ 6. Token 발급 (검증 성공 시)        │                                 │
│    │<──────────────────────────────────── │                                 │
│                                                                             │
│  왜 안전한가:                                                              │
│  ├── 공격자가 code를 탈취해도 code_verifier가 없으면 Token 교환 불가       │
│  ├── code_challenge → code_verifier 역산 불가 (SHA256 단방향 해시)         │
│  ├── 매 요청마다 새로운 verifier 생성 → 재사용 공격 불가                   │
│  └── OAuth 2.1에서 모든 클라이언트(서버 앱 포함)에 필수화                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.5 JWT 토큰 구조와 종류

┌─────────────────────────────────────────────────────────────────────────────┐
│              JWT 토큰의 3가지 종류와 역할                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┬──────────────────┬──────────────────┬──────────────────┐ │
│  │              │  Access Token    │  ID Token        │  Refresh Token   │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 목적         │ API 접근 권한    │ 사용자 신원 증명 │ Access Token     │ │
│  │              │ (인가)           │ (인증)           │ 갱신용           │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 발급 시점    │ Token 교환 시    │ Token 교환 시    │ Token 교환 시    │ │
│  │              │                  │ (OIDC scope 시)  │                  │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 수명         │ 짧음 (1시간~)    │ 짧음 (5분~1시간) │ 김 (2주~2개월)   │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 전송 대상    │ Resource Server  │ Client App       │ Auth Server      │ │
│  │              │ (API 서버)       │ (검증용)         │ (갱신 요청 시)   │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 저장 위치    │ 메모리/httpOnly  │ 검증 후 폐기     │ 서버 DB/Redis    │ │
│  │              │ 쿠키             │ (저장 불필요)    │ (암호화 저장)    │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ JWT 여부     │ Provider마다     │ 항상 JWT         │ Opaque 또는 JWT  │ │
│  │              │ 다름             │                  │                  │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 검증 방식    │ 서명 검증 또는   │ 서명 검증        │ Auth Server가    │ │
│  │              │ Introspection    │ (JWKS 사용)      │ 직접 검증        │ │
│  └──────────────┴──────────────────┴──────────────────┴──────────────────┘ │
│                                                                             │
│  JWT 구조: Header.Payload.Signature                                        │
│                                                                             │
│  Header:   { "alg": "RS256", "typ": "JWT", "kid": "key-id-123" }          │
│  Payload:  { "sub": "12345", "iss": "https://...", "exp": 1709500000, ...} │
│  Signature: RS256(base64(header) + "." + base64(payload), private_key)     │
│                                                                             │
│  중요한 만료 정책 (Provider별):                                            │
│  ├── Access Token:  Google 1시간, Kakao 6시간, Naver 1시간                 │
│  ├── Refresh Token: Google 6개월, Kakao 2개월, Naver 1년                   │
│  └── ID Token:      보통 5분~1시간 (검증 후 즉시 폐기 권장)                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3. 카카오 로그인 상세 분석

3.1 Kakao Developers 플랫폼 구조

┌─────────────────────────────────────────────────────────────────────────────┐
│              카카오 로그인 구현을 위한 사전 설정                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1단계: Kakao Developers (developers.kakao.com) 앱 생성                    │
│  ├── 내 애플리케이션 → 애플리케이션 추가하기                               │
│  ├── 앱 이름, 사업자명 입력                                                │
│  └── 앱 생성 완료 시 4가지 키 발급:                                        │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  키 종류              용도                 노출 가능 여부   │           │
│  ├─────────────────────────────────────────────────────────────┤           │
│  │  REST API 키         서버 OAuth 인증       공개 가능        │           │
│  │  (= client_id)       (Authorization Code)  (client_id)      │           │
│  │                                                             │           │
│  │  JavaScript 키       웹 프론트엔드         공개 가능        │           │
│  │                      (Kakao JS SDK)        (도메인 제한)    │           │
│  │                                                             │           │
│  │  Native App 키       모바일 앱             공개 가능        │           │
│  │                      (iOS/Android SDK)     (패키지 제한)    │           │
│  │                                                             │           │
│  │  Admin 키            서버 관리 API         절대 비공개      │           │
│  │  (= client_secret급)  (사용자 관리 등)     (서버에만 보관)  │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  2단계: 플랫폼 등록                                                        │
│  ├── 웹: 사이트 도메인 등록 (예: https://myapp.com)                        │
│  ├── Android: 패키지명 + 키 해시 등록                                      │
│  └── iOS: 번들 ID 등록                                                     │
│                                                                             │
│  3단계: Redirect URI 등록                                                  │
│  ├── 카카오 로그인 → 활성화 ON                                             │
│  ├── Redirect URI 추가: https://myapp.com/oauth/kakao/callback             │
│  ├── 개발 환경: http://localhost:8080/oauth/kakao/callback                  │
│  └── 등록되지 않은 URI로는 인가 코드 발급 불가 (보안)                      │
│                                                                             │
│  4단계: Client Secret 발급 (선택이지만 강력 권장)                          │
│  ├── 보안 → Client Secret → 코드 생성                                     │
│  ├── 활성화 상태: 사용함                                                   │
│  └── Token 요청 시 client_secret 파라미터 필수                             │
│                                                                             │
│  5단계: 동의 항목 설정                                                     │
│  ├── 필수 동의 / 선택 동의 / 이용 중 동의 설정                            │
│  └── 비즈앱 전환 시 추가 항목 사용 가능                                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.2 카카오 로그인 OAuth 2.0 흐름 (Authorization Code Grant)

┌─────────────────────────────────────────────────────────────────────────────┐
│              카카오 로그인 전체 흐름 (상세)                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  User        Browser       Our Server      kauth.kakao.com  kapi.kakao.com │
│   │            │               │                 │               │         │
│   │ 1. "카카오  │               │                 │               │         │
│   │  로그인"   │               │                 │               │         │
│   │───────────>│               │                 │               │         │
│   │            │ 2. GET /auth/ │                 │               │         │
│   │            │    kakao      │                 │               │         │
│   │            │──────────────>│                 │               │         │
│   │            │               │                 │               │         │
│   │            │ 3. 302 Redirect                 │               │         │
│   │            │<──────────────│                 │               │         │
│   │            │               │                 │               │         │
│   │            │ 4. GET /oauth/authorize         │               │         │
│   │            │   ?client_id={REST_API_KEY}     │               │         │
│   │            │   &redirect_uri={CALLBACK_URL}  │               │         │
│   │            │   &response_type=code           │               │         │
│   │            │   &scope=profile_nickname       │               │         │
│   │            │         account_email            │               │         │
│   │            │   &state={CSRF_TOKEN}           │               │         │
│   │            │────────────────────────────────>│               │         │
│   │            │               │                 │               │         │
│   │ 5. 카카오  │               │                 │               │         │
│   │  로그인    │               │                 │               │         │
│   │  + 동의    │               │                 │               │         │
│   │<───────────│ 로그인/동의 화면                │               │         │
│   │            │               │                 │               │         │
│   │ 6. 로그인  │               │                 │               │         │
│   │  완료      │               │                 │               │         │
│   │───────────>│───────────────────────────────>│               │         │
│   │            │               │                 │               │         │
│   │            │ 7. 302 Redirect                 │               │         │
│   │            │   ?code={AUTHORIZATION_CODE}    │               │         │
│   │            │   &state={CSRF_TOKEN}           │               │         │
│   │            │<────────────────────────────────│               │         │
│   │            │               │                 │               │         │
│   │            │ 8. GET /oauth/kakao/callback    │               │         │
│   │            │   ?code=...&state=...           │               │         │
│   │            │──────────────>│                 │               │         │
│   │            │               │                 │               │         │
│   │            │               │ 9. POST /oauth/token            │         │
│   │            │               │   grant_type=authorization_code │         │
│   │            │               │   client_id={REST_API_KEY}      │         │
│   │            │               │   client_secret={SECRET}        │         │
│   │            │               │   redirect_uri={CALLBACK_URL}   │         │
│   │            │               │   code={AUTHORIZATION_CODE}     │         │
│   │            │               │────────────────>│               │         │
│   │            │               │                 │               │         │
│   │            │               │ 10. Token Response               │         │
│   │            │               │<────────────────│               │         │
│   │            │               │  {                               │         │
│   │            │               │   "access_token": "xxx",         │         │
│   │            │               │   "token_type": "bearer",        │         │
│   │            │               │   "refresh_token": "yyy",        │         │
│   │            │               │   "expires_in": 21599,           │         │
│   │            │               │   "refresh_token_expires_in":    │         │
│   │            │               │     5183999,                     │         │
│   │            │               │   "scope": "profile_nickname     │         │
│   │            │               │     account_email"               │         │
│   │            │               │  }                               │         │
│   │            │               │                 │               │         │
│   │            │               │ 11. GET /v2/user/me              │         │
│   │            │               │   Authorization: Bearer {AT}    │         │
│   │            │               │─────────────────────────────────>│         │
│   │            │               │                 │               │         │
│   │            │               │ 12. User Info Response           │         │
│   │            │               │<─────────────────────────────────│         │
│   │            │               │  {                               │         │
│   │            │               │   "id": 123456789,               │         │
│   │            │               │   "kakao_account": {             │         │
│   │            │               │     "email": "user@kakao.com",   │         │
│   │            │               │     "profile": {                 │         │
│   │            │               │       "nickname": "홍길동",      │         │
│   │            │               │       "profile_image_url": "..." │         │
│   │            │               │     }                            │         │
│   │            │               │   }                              │         │
│   │            │               │  }                               │         │
│   │            │               │                 │               │         │
│   │            │ 13. 서비스 자체 세션 생성       │               │         │
│   │            │   + JWT 발급                    │               │         │
│   │            │<──────────────│                 │               │         │
│   │<───────────│ 로그인 완료   │                 │               │         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.3 동의 항목 (Scopes)

┌─────────────────────────────────────────────────────────────────────────────┐
│              카카오 동의 항목 (2025~2026 기준)                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────┬──────────┬──────────────┬──────────────────────┐ │
│  │ 동의 항목            │ 동의 유형│ 필요 앱 유형 │ scope 파라미터       │ │
│  ├──────────────────────┼──────────┼──────────────┼──────────────────────┤ │
│  │ 닉네임               │ 필수/선택│ 개인앱       │ profile_nickname     │ │
│  │ 프로필 사진           │ 필수/선택│ 개인앱       │ profile_image        │ │
│  │ 카카오계정 이메일     │ 필수/선택│ 개인앱       │ account_email        │ │
│  │ 성별                 │ 선택     │ 비즈앱       │ gender               │ │
│  │ 연령대               │ 선택     │ 비즈앱       │ age_range            │ │
│  │ 생일                 │ 선택     │ 비즈앱       │ birthday             │ │
│  │ 출생연도             │ 선택     │ 비즈앱       │ birthyear            │ │
│  │ CI (본인인증)        │ 필수     │ 비즈앱       │ account_ci           │ │
│  │ 전화번호             │ 선택     │ 비즈앱       │ phone_number         │ │
│  │ 배송지               │ 선택     │ 비즈앱       │ shipping_address     │ │
│  │ 카카오톡 채널 추가   │ 선택     │ 비즈앱       │ talk_message         │ │
│  │ 친구 목록            │ 선택     │ 비즈앱       │ friends              │ │
│  └──────────────────────┴──────────┴──────────────┴──────────────────────┘ │
│                                                                             │
│  주의사항:                                                                 │
│  ├── 필수 동의: 사용자가 거부하면 로그인 자체가 불가                       │
│  ├── 선택 동의: 사용자가 거부해도 로그인 가능 (데이터 null)                │
│  ├── 이용 중 동의: 로그인 후 특정 기능 사용 시 추가 동의 요청              │
│  ├── 이메일 제공 여부는 사용자에 따라 다름 (카카오 가입 방식에 따라)       │
│  └── 비즈앱은 사업자등록번호 필수 (개인 개발자는 개인앱만 가능)            │
│                                                                             │
│  이메일 주의사항 (중요!):                                                  │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  카카오 계정에 이메일이 없는 사용자가 존재!                  │           │
│  │  ├── 전화번호만으로 가입한 사용자                            │           │
│  │  ├── 이메일을 등록하지 않은 사용자                           │           │
│  │  ├── email 필드가 null로 올 수 있음                         │           │
│  │  └── 이메일 기반 계정 통합 시 반드시 null 처리 필요          │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.4 토큰 관리

┌─────────────────────────────────────────────────────────────────────────────┐
│              카카오 토큰 수명과 갱신 정책                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │ Token 유형       │ 수명         │ 비고                      │           │
│  ├──────────────────┼──────────────┼───────────────────────────┤           │
│  │ Access Token     │ 6시간        │ REST API 호출용           │           │
│  │                  │ (21,599초)   │ Android/iOS: 12시간       │           │
│  │                  │              │ JavaScript: 2시간         │           │
│  ├──────────────────┼──────────────┼───────────────────────────┤           │
│  │ Refresh Token    │ 2개월        │ Access Token 갱신용       │           │
│  │                  │ (5,183,999초)│ 만료 1개월 전부터         │           │
│  │                  │              │ 갱신 시 자동 연장         │           │
│  ├──────────────────┼──────────────┼───────────────────────────┤           │
│  │ ID Token         │ Access Token │ OIDC scope 요청 시 발급   │           │
│  │ (OIDC)           │ 과 동일      │                           │           │
│  └──────────────────┴──────────────┴───────────────────────────┘           │
│                                                                             │
│  Refresh Token 갱신 흐름:                                                  │
│                                                                             │
│  Our Server                        kauth.kakao.com                         │
│      │                                  │                                  │
│      │  POST /oauth/token               │                                  │
│      │    grant_type=refresh_token       │                                  │
│      │    client_id={REST_API_KEY}       │                                  │
│      │    client_secret={SECRET}         │                                  │
│      │    refresh_token={REFRESH_TOKEN}  │                                  │
│      │─────────────────────────────────>│                                  │
│      │                                  │                                  │
│      │  Response:                       │                                  │
│      │  {                               │                                  │
│      │   "access_token": "new_at",      │                                  │
│      │   "expires_in": 21599,           │                                  │
│      │   "refresh_token": "new_rt",     │ ← 만료 1개월 이내일 때만        │
│      │   "refresh_token_expires_in":    │    새 RT 발급, 아니면 미포함     │
│      │     5183999                      │                                  │
│      │  }                               │                                  │
│      │<─────────────────────────────────│                                  │
│                                                                             │
│  갱신 전략 (서버 구현):                                                    │
│  ├── Access Token 만료 전 자동 갱신 (만료 10분 전)                         │
│  ├── API 호출 시 401 응답 → 즉시 Refresh → 재시도                          │
│  ├── Refresh Token 갱신 응답에 new_rt가 있으면 DB 업데이트                 │
│  └── Refresh Token도 만료되면 → 사용자 재로그인 유도                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.5 카카오톡 채널 연결 및 비즈앱

┌─────────────────────────────────────────────────────────────────────────────┐
│              비즈앱 vs 개인앱                                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────┬──────────────────────────┐                   │
│  │       개인앱             │       비즈앱             │                   │
│  ├──────────────────────────┼──────────────────────────┤                   │
│  │ 사업자등록 불필요        │ 사업자등록번호 필수      │                   │
│  │ 기본 동의 항목만 사용    │ 확장 동의 항목 사용 가능 │                   │
│  │ (닉네임, 프로필, 이메일) │ (성별, 연령, CI 등)      │                   │
│  │ 카카오톡 채널 연동 불가  │ 카카오톡 채널 연동 가능  │                   │
│  │ 메시지 API 제한          │ 카카오톡 메시지 전송 가능│                   │
│  │ 개발/테스트 용도         │ 상용 서비스 용도         │                   │
│  └──────────────────────────┴──────────────────────────┘                   │
│                                                                             │
│  CI/DI (본인인증):                                                         │
│  ├── CI (Connecting Information): 주민등록번호 기반 고유 식별자            │
│  │   └── 모든 서비스에서 동일한 값 → 중복 가입 방지                        │
│  ├── DI (Duplication Information): 서비스별 고유 식별자                     │
│  │   └── 같은 사람이라도 서비스마다 다른 값                                │
│  ├── 카카오 계정에 본인인증(PASS, 카카오톡 인증 등) 완료 시 제공           │
│  └── 비즈앱 + 추가 심사 필요                                              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.6 카카오 OIDC 지원

┌─────────────────────────────────────────────────────────────────────────────┐
│              카카오 OIDC (ID Token 발급)                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  카카오는 2022년부터 OIDC를 지원하여 ID Token(JWT) 발급이 가능             │
│                                                                             │
│  활성화 방법:                                                              │
│  ├── Kakao Developers → 카카오 로그인 → OpenID Connect 활성화 ON          │
│  └── scope에 "openid" 추가                                                │
│                                                                             │
│  인가 코드 요청 시:                                                        │
│  GET https://kauth.kakao.com/oauth/authorize                               │
│    ?client_id={REST_API_KEY}                                               │
│    &redirect_uri={CALLBACK_URL}                                            │
│    &response_type=code                                                     │
│    &scope=openid profile_nickname account_email                            │
│    &nonce={RANDOM_NONCE}   ← OIDC 리플레이 공격 방지                      │
│                                                                             │
│  Token 응답에 id_token이 추가됨:                                           │
│  {                                                                         │
│    "access_token": "...",                                                  │
│    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",                 │
│    "refresh_token": "..."                                                  │
│  }                                                                         │
│                                                                             │
│  ID Token 디코딩 결과:                                                     │
│  {                                                                         │
│    "iss": "https://kauth.kakao.com",                                       │
│    "aud": "{REST_API_KEY}",                                                │
│    "sub": "123456789",          ← 카카오 회원번호                          │
│    "iat": 1709500000,                                                      │
│    "exp": 1709521600,                                                      │
│    "nonce": "{요청 시 보낸 nonce}",                                        │
│    "nickname": "홍길동",                                                   │
│    "email": "user@kakao.com"                                               │
│  }                                                                         │
│                                                                             │
│  OIDC 사용 장점:                                                           │
│  ├── /v2/user/me API 호출 없이 ID Token으로 기본 정보 확인 가능            │
│  ├── Token 자체 검증 가능 (JWKS로 서명 검증)                               │
│  ├── nonce로 리플레이 공격 방지                                            │
│  └── 표준 OIDC 라이브러리 그대로 활용 가능                                 │
│                                                                             │
│  JWKS 엔드포인트: https://kauth.kakao.com/.well-known/jwks.json            │
│  Discovery: https://kauth.kakao.com/.well-known/openid-configuration       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4. Provider별 비교 (Google, Naver, Apple, Kakao)

4.1 종합 비교표

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 Provider 비교 (2025~2026 기준)                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────┬──────────────┬──────────────┬──────────────┬──────────────┐  │
│  │ 항목     │ Kakao        │ Google       │ Naver        │ Apple        │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 프로토콜 │ OAuth 2.0    │ OAuth 2.0    │ OAuth 2.0    │ OAuth 2.0    │  │
│  │          │ + OIDC       │ + OIDC       │ (OIDC 미지원)│ + OIDC       │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ AT 만료  │ 6시간        │ 1시간        │ 1시간        │ 10분         │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ RT 만료  │ 2개월        │ 6개월        │ 1년          │ 무기한       │  │
│  │          │ (1개월 전    │ (미사용 시   │              │ (Revoke 시   │  │
│  │          │  갱신 시     │  6개월 후    │              │  만료)       │  │
│  │          │  자동 연장)  │  만료)       │              │              │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ PKCE     │ 미지원       │ 지원 (권장)  │ 미지원       │ 지원 (권장)  │  │
│  │          │ (client_     │              │              │              │  │
│  │          │  secret 사용)│              │              │              │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ ID Token │ 지원 (OIDC)  │ 지원 (기본)  │ 미지원       │ 지원 (기본)  │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 필수     │ 없음         │ openid       │ 없음         │ openid       │  │
│  │ scope    │ (openid 선택)│              │              │ name email   │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 이메일   │ 있을 수도    │ 거의 항상    │ 항상 제공    │ 제공 (Hide   │  │
│  │ 제공     │ 없을 수도    │ 제공         │ (필수 동의)  │  My Email    │  │
│  │          │ (null 가능)  │              │              │  옵션 있음)  │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 사용자ID │ 숫자 (long)  │ 문자열 (sub) │ 문자열       │ 문자열 (sub) │  │
│  │ 형태     │ 예: 12345678 │ 예: "1102.." │ 예: "abcd.." │ 예: "001.."  │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 고유     │ 카카오톡 채널│ One Tap,     │ 네이버 페이  │ Private      │  │
│  │ 특징     │ 연결, CI/DI  │ FedCM,       │ 연동, 스마트 │ Email Relay, │  │
│  │          │ 본인인증     │ GIS          │ 스토어 연동  │ App Store    │  │
│  │          │              │              │              │ 필수 규정    │  │
│  ├──────────┼──────────────┼──────────────┼──────────────┼──────────────┤  │
│  │ 한국     │ 1위          │ 3위          │ 2위          │ 4위          │  │
│  │ 점유율   │ (약 50%+)    │ (약 15%)     │ (약 25%)     │ (약 10%)     │  │
│  └──────────┴──────────────┴──────────────┴──────────────┴──────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.2 Google Sign-In (One Tap, FedCM, GIS)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Google Identity Services (GIS) 아키텍처                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Google의 로그인 생태계 (2022년 이후 통합):                                │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  Google Identity Services (GIS)                             │           │
│  │                                                             │           │
│  │  ├── Sign In with Google (버튼 방식)                        │           │
│  │  │   ├── 기존 "Google 로그인" 버튼의 진화                   │           │
│  │  │   ├── Authorization Code Flow 또는 ID Token 직접 반환    │           │
│  │  │   └── 커스텀 버튼 또는 Google 제공 버튼 사용             │           │
│  │  │                                                          │           │
│  │  ├── One Tap                                                │           │
│  │  │   ├── 페이지 구석에 작은 팝업으로 로그인 제안            │           │
│  │  │   ├── 이미 Google 로그인 상태면 원클릭 로그인            │           │
│  │  │   ├── ID Token을 직접 반환 (credential callback)         │           │
│  │  │   ├── 전환율 극대화 (사용자 마찰 최소화)                 │           │
│  │  │   └── FedCM API 기반으로 전환 중 (Chrome 117+)           │           │
│  │  │                                                          │           │
│  │  └── Automatic Sign-In                                      │           │
│  │      ├── 이전에 로그인한 사용자 자동 로그인                 │           │
│  │      ├── 세션 만료 후 재방문 시 자동 복원                   │           │
│  │      └── 사용자 명시적 로그아웃 시까지 유지                 │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  FedCM (Federated Credential Management) API:                              │
│  ├── Chrome 브라우저의 네이티브 로그인 UI 제공                             │
│  ├── 3rd-party 쿠키 없이 소셜 로그인 지원 (Privacy Sandbox)               │
│  ├── 브라우저가 직접 IdP와 통신하여 credential 제공                       │
│  ├── iframe/redirect 없는 로그인 UX                                       │
│  └── 2025~2026: Google One Tap이 FedCM 기반으로 전환 중                   │
│                                                                             │
│  서버 사이드 처리 (ID Token 직접 수신 방식):                               │
│                                                                             │
│  // Google One Tap은 ID Token을 직접 POST로 전달                           │
│  // Authorization Code 교환 과정이 불필요한 경우도 있음                    │
│  POST /auth/google/callback                                                │
│  Body: { "credential": "eyJhbGciOiJSUzI1NiI..." }  ← ID Token             │
│                                                                             │
│  서버에서:                                                                 │
│  1. Google JWKS로 ID Token 서명 검증                                       │
│  2. iss, aud, exp 클레임 검증                                              │
│  3. sub(사용자 ID), email, name 추출                                       │
│  4. 서비스 자체 세션/JWT 발급                                              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.3 Naver Login

┌─────────────────────────────────────────────────────────────────────────────┐
│              네이버 로그인 특징                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  프로토콜: OAuth 2.0 (OIDC 미지원, ID Token 없음)                          │
│  Developer: developers.naver.com                                           │
│                                                                             │
│  인가 코드 요청:                                                           │
│  GET https://nid.naver.com/oauth2.0/authorize                              │
│    ?response_type=code                                                     │
│    &client_id={CLIENT_ID}                                                  │
│    &redirect_uri={CALLBACK_URL}                                            │
│    &state={CSRF_TOKEN}                                                     │
│                                                                             │
│  토큰 요청:                                                               │
│  POST https://nid.naver.com/oauth2.0/token                                 │
│    grant_type=authorization_code                                           │
│    &client_id={CLIENT_ID}                                                  │
│    &client_secret={CLIENT_SECRET}                                          │
│    &code={AUTH_CODE}                                                       │
│    &state={CSRF_TOKEN}                                                     │
│                                                                             │
│  사용자 정보 조회:                                                         │
│  GET https://openapi.naver.com/v1/nid/me                                   │
│  Authorization: Bearer {ACCESS_TOKEN}                                      │
│                                                                             │
│  응답:                                                                     │
│  {                                                                         │
│    "resultcode": "00",                                                     │
│    "message": "success",                                                   │
│    "response": {                                                           │
│      "id": "UNIQUE_NAVER_ID",      ← 네이버 고유 식별자                    │
│      "email": "user@naver.com",                                            │
│      "name": "홍길동",                                                     │
│      "nickname": "길동이",                                                 │
│      "profile_image": "https://...",                                       │
│      "age": "20-29",                                                       │
│      "gender": "M",                                                        │
│      "birthday": "01-01",                                                  │
│      "mobile": "010-1234-5678"                                             │
│    }                                                                       │
│  }                                                                         │
│                                                                             │
│  네이버 특이사항:                                                          │
│  ├── OIDC 미지원 → ID Token 없음 → 반드시 /nid/me API 호출 필요           │
│  ├── 이메일은 항상 제공됨 (네이버 계정 = 이메일)                           │
│  ├── 생년월일, 성별, 전화번호 등 비교적 풍부한 프로필                      │
│  ├── Access Token 갱신 시 Refresh Token이 바뀌지 않음 (고정)               │
│  └── 검수 요청: 로그인 연동 후 검수 요청 필요 (미검수 시 개발자만 사용)    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.4 Apple Sign In

┌─────────────────────────────────────────────────────────────────────────────┐
│              Apple Sign In 특징 (다른 Provider와의 핵심 차이)                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  App Store 필수 규정 (매우 중요!):                                         │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  iOS 앱에서 3rd-party 소셜 로그인(Google, Kakao, Naver 등) │           │
│  │  을 하나라도 제공하면, Apple Sign In도 반드시 제공해야 함   │           │
│  │                                                             │           │
│  │  → 미준수 시 App Store 심사 거절                            │           │
│  │  → 2019년 WWDC에서 발표, 2020년부터 강제                    │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  Apple만의 고유 특징:                                                      │
│                                                                             │
│  1. Private Email Relay (Hide My Email)                                    │
│     ├── 사용자가 실제 이메일 대신 Apple 릴레이 이메일 선택 가능            │
│     ├── 형태: "abc123@privaterelay.appleid.com"                            │
│     ├── Apple이 중계하여 실제 이메일로 전달                                │
│     ├── 서비스는 실제 이메일을 알 수 없음                                  │
│     └── 이메일 기반 계정 통합 시 주의 필요!                                │
│                                                                             │
│  2. 사용자 이름은 첫 로그인에서만 제공                                     │
│     ├── 첫 인증 시: { name: "홍길동", email: "..." }                       │
│     ├── 이후 인증 시: { email: "..." } (name 없음!)                        │
│     ├── 첫 응답에서 반드시 이름을 저장해야 함                              │
│     └── 놓치면 Apple Developer에서 앱 연결 해제 후 재시도 필요             │
│                                                                             │
│  3. JWT Client Secret                                                      │
│     ├── 다른 Provider: 고정 client_secret 문자열 사용                      │
│     ├── Apple: client_secret을 직접 JWT로 생성해야 함                      │
│     │   ├── Private Key (.p8 파일) 다운로드                                │
│     │   ├── Team ID, Key ID, Client ID로 JWT 생성                         │
│     │   └── 만료 시간 6개월 이내                                           │
│     └── 매번 갱신하거나, 코드로 자동 생성 로직 필요                        │
│                                                                             │
│  4. 앱 vs 웹 차이                                                          │
│     ├── iOS 앱: AuthenticationServices 프레임워크 (네이티브)               │
│     ├── 웹: REST API 기반 OAuth 2.0 흐름                                   │
│     └── 웹에서는 appleid.apple.com/auth/authorize 사용                     │
│                                                                             │
│  서버 구현 시 주의사항:                                                    │
│  ├── ID Token 검증: Apple JWKS (appleid.apple.com/auth/keys)              │
│  ├── sub 값이 사용자 고유 ID (Team 단위로 고유)                            │
│  ├── Private Email Relay 설정: Apple Developer에서 도메인/이메일 등록      │
│  └── Token Revocation: 사용자 탈퇴 시 Apple에 revoke 요청 필수            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5. 백엔드 서버가 하는 일 (단계별)

5.1 전체 아키텍처 흐름

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 백엔드 처리 전체 흐름                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                                                                      │  │
│  │  1. OAuth 클라이언트 등록                                            │  │
│  │     └─ 각 Provider 개발자 콘솔에서 client_id, client_secret 발급     │  │
│  │                                                                      │  │
│  │  2. Authorization URL 생성                                           │  │
│  │     └─ state (CSRF 방지) + nonce (리플레이 방지) + PKCE 생성         │  │
│  │     └─ state를 서버 세션 또는 Redis에 저장                           │  │
│  │                                                                      │  │
│  │  3. 사용자를 Provider 로그인 페이지로 Redirect                       │  │
│  │     └─ 302 Redirect to kauth.kakao.com/oauth/authorize              │  │
│  │                                                                      │  │
│  │  4. Callback에서 Authorization Code 수신                             │  │
│  │     └─ state 검증 (저장된 값과 일치하는지 확인)                      │  │
│  │     └─ code 추출                                                    │  │
│  │                                                                      │  │
│  │  5. Code → Token 교환 (Server-to-Server)                             │  │
│  │     └─ POST to Provider의 /token 엔드포인트                         │  │
│  │     └─ client_secret 포함 (Back-Channel, 브라우저 미경유)            │  │
│  │                                                                      │  │
│  │  6. Token 검증                                                       │  │
│  │     └─ ID Token이 있으면 JWKS로 서명 검증                           │  │
│  │     └─ iss, aud, exp, nonce 클레임 검증                             │  │
│  │                                                                      │  │
│  │  7. 사용자 정보 조회                                                 │  │
│  │     └─ Access Token으로 Provider의 UserInfo API 호출                 │  │
│  │     └─ 또는 ID Token에서 직접 추출 (OIDC 지원 Provider)             │  │
│  │                                                                      │  │
│  │  8. 신규/기존 회원 판별 + 계정 매핑                                  │  │
│  │     └─ provider + provider_user_id로 social_accounts 테이블 조회     │  │
│  │     └─ 없으면: JIT Provisioning (자동 회원가입)                      │  │
│  │     └─ 있으면: 기존 사용자 정보 업데이트                             │  │
│  │                                                                      │  │
│  │  9. 서비스 자체 JWT 발급 (세션 생성)                                  │  │
│  │     └─ 서비스용 Access Token + Refresh Token 발급                    │  │
│  │     └─ Provider의 Token과 별개! (서비스 자체 인증 체계)              │  │
│  │                                                                      │  │
│  │  10. Provider Refresh Token 저장                                     │  │
│  │      └─ 암호화하여 DB 저장 (추후 Provider API 호출 필요 시 사용)     │  │
│  │                                                                      │  │
│  │  11. 로그아웃 + 세션 무효화                                          │  │
│  │      └─ 서비스 세션/JWT 무효화                                       │  │
│  │      └─ 필요 시 Provider 로그아웃 API 호출                           │  │
│  │                                                                      │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5.2 서비스 자체 토큰 vs Provider 토큰

┌─────────────────────────────────────────────────────────────────────────────┐
│              토큰 이중 구조 이해하기                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  흔한 실수: Provider의 Access Token을 그대로 서비스 인증에 사용            │
│                                                                             │
│  올바른 구조:                                                              │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │                                                             │           │
│  │  Provider Token (Kakao/Google/Naver)                        │           │
│  │  ├── 목적: Provider의 API 호출용 (사용자 정보 조회 등)      │           │
│  │  ├── 수명: Provider가 결정 (6시간, 1시간 등)                │           │
│  │  ├── 저장: 서버 DB (암호화)                                 │           │
│  │  └── 용도: 로그인 시 사용자 정보 조회, 이후 거의 사용 안 함 │           │
│  │                                                             │           │
│  │  서비스 자체 Token (우리 서버 발급)                          │           │
│  │  ├── 목적: 우리 서비스의 인증/인가                          │           │
│  │  ├── 수명: 우리가 결정 (AT: 30분, RT: 2주 권장)             │           │
│  │  ├── 저장: AT → httpOnly 쿠키 또는 메모리, RT → 서버 DB     │           │
│  │  └── 용도: 모든 API 요청의 인증 수단                        │           │
│  │                                                             │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  왜 자체 토큰이 필요한가:                                                  │
│  ├── Provider Token은 Provider API 호출에만 사용 가능                      │
│  ├── 우리 서비스의 권한 체계(RBAC 등)를 토큰에 담을 수 없음                │
│  ├── Provider마다 Token 형식/수명이 달라 통일된 인증 불가                  │
│  ├── Provider 장애 시에도 우리 서비스는 정상 동작해야 함                   │
│  └── 다중 Provider 지원 시 하나의 통일된 인증 체계 필요                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

6. 회원가입 구성 패턴

6.1 DB 스키마 설계

-- ============================================================
-- 소셜 로그인 DB 스키마 (PostgreSQL)
-- ============================================================

-- 1. 사용자 테이블 (서비스 자체 계정)
CREATE TABLE users (
    id              BIGSERIAL PRIMARY KEY,
    email           VARCHAR(255) UNIQUE,           -- 이메일 (null 가능: 카카오)
    email_verified  BOOLEAN DEFAULT FALSE,         -- 이메일 인증 여부
    nickname        VARCHAR(100),                  -- 표시 이름
    profile_image   VARCHAR(500),                  -- 프로필 사진 URL
    role            VARCHAR(20) DEFAULT 'USER',    -- USER, ADMIN, MODERATOR
    status          VARCHAR(20) DEFAULT 'ACTIVE',  -- ACTIVE, SUSPENDED, DELETED
    onboarding_done BOOLEAN DEFAULT FALSE,         -- 추가 정보 수집 완료 여부
    last_login_at   TIMESTAMP WITH TIME ZONE,
    created_at      TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at      TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    deleted_at      TIMESTAMP WITH TIME ZONE       -- 소프트 삭제
);

-- 2. 소셜 계정 연동 테이블
CREATE TABLE social_accounts (
    id                  BIGSERIAL PRIMARY KEY,
    user_id             BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    provider            VARCHAR(20) NOT NULL,       -- KAKAO, GOOGLE, NAVER, APPLE
    provider_user_id    VARCHAR(255) NOT NULL,       -- Provider별 고유 사용자 ID
    provider_email      VARCHAR(255),                -- Provider에서 받은 이메일
    provider_nickname   VARCHAR(100),                -- Provider에서 받은 닉네임
    provider_profile    VARCHAR(500),                -- Provider에서 받은 프로필 URL
    connected_at        TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    last_used_at        TIMESTAMP WITH TIME ZONE DEFAULT NOW(),

    -- provider + provider_user_id 조합으로 유일성 보장
    UNIQUE (provider, provider_user_id)
);

-- 인덱스: 로그인 시 빠른 조회
CREATE INDEX idx_social_accounts_provider_uid
    ON social_accounts (provider, provider_user_id);

-- 인덱스: 사용자별 연동된 소셜 계정 조회
CREATE INDEX idx_social_accounts_user_id
    ON social_accounts (user_id);

-- 3. Refresh Token 저장 테이블 (Provider 토큰)
CREATE TABLE provider_tokens (
    id                  BIGSERIAL PRIMARY KEY,
    social_account_id   BIGINT NOT NULL REFERENCES social_accounts(id) ON DELETE CASCADE,
    access_token        TEXT NOT NULL,               -- 암호화 저장 (AES-256)
    refresh_token       TEXT,                        -- 암호화 저장 (AES-256)
    token_type          VARCHAR(20) DEFAULT 'bearer',
    access_expires_at   TIMESTAMP WITH TIME ZONE,
    refresh_expires_at  TIMESTAMP WITH TIME ZONE,
    scope               VARCHAR(500),
    updated_at          TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 4. 서비스 자체 Refresh Token 테이블
CREATE TABLE service_refresh_tokens (
    id              BIGSERIAL PRIMARY KEY,
    user_id         BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token_hash      VARCHAR(255) NOT NULL UNIQUE,   -- SHA-256 해시 저장
    device_info     VARCHAR(255),                   -- User-Agent 또는 디바이스 정보
    ip_address      INET,
    expires_at      TIMESTAMP WITH TIME ZONE NOT NULL,
    revoked         BOOLEAN DEFAULT FALSE,
    revoked_at      TIMESTAMP WITH TIME ZONE,
    created_at      TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 인덱스: 토큰 검증 시 빠른 조회
CREATE INDEX idx_service_rt_token_hash
    ON service_refresh_tokens (token_hash) WHERE revoked = FALSE;

-- 인덱스: 사용자별 세션 관리
CREATE INDEX idx_service_rt_user_id
    ON service_refresh_tokens (user_id) WHERE revoked = FALSE;

-- 5. 로그인 이력 테이블 (감사/보안)
CREATE TABLE login_history (
    id              BIGSERIAL PRIMARY KEY,
    user_id         BIGINT REFERENCES users(id),
    provider        VARCHAR(20),                    -- KAKAO, GOOGLE, EMAIL 등
    success         BOOLEAN NOT NULL,
    failure_reason  VARCHAR(100),
    ip_address      INET,
    user_agent      VARCHAR(500),
    created_at      TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 파티셔닝 또는 TTL 정책 권장 (90일 보관 등)
CREATE INDEX idx_login_history_user_created
    ON login_history (user_id, created_at DESC);

6.2 신규 가입 vs 기존 회원 판별 로직

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 시 회원 판별 플로우차트                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Provider로부터 사용자 정보 수신                                           │
│  (provider="KAKAO", provider_user_id="123456", email="a@b.com")            │
│                                                                             │
│  ┌─────────────────────────────────┐                                      │
│  │ social_accounts에서              │                                      │
│  │ provider + provider_user_id 조회 │                                      │
│  └───────────────┬─────────────────┘                                      │
│                  │                                                         │
│          ┌───────┴───────┐                                                │
│          │               │                                                │
│       있음 ✓          없음 ✗                                              │
│          │               │                                                │
│          ▼               ▼                                                │
│  ┌───────────────┐  ┌────────────────────────────┐                        │
│  │ 기존 회원      │  │ email이 null인가?           │                        │
│  │ 로그인 처리    │  └──────────┬─────────────────┘                        │
│  │               │             │                                          │
│  │ - last_used_at│     ┌───────┴───────┐                                  │
│  │   업데이트    │     │               │                                  │
│  │ - 프로필 동기화│   null           이메일 있음                           │
│  │ - 서비스 JWT  │     │               │                                  │
│  │   발급        │     ▼               ▼                                  │
│  └───────────────┘  ┌──────────┐  ┌────────────────────┐                  │
│                     │ 신규 가입 │  │ users에서 같은      │                  │
│                     │ 바로 진행 │  │ email 조회          │                  │
│                     │          │  └──────────┬─────────┘                  │
│                     │ - users  │             │                            │
│                     │   생성   │     ┌───────┴───────┐                    │
│                     │ - social │     │               │                    │
│                     │   _acct  │  있음 ✓          없음 ✗                  │
│                     │   생성   │     │               │                    │
│                     │ - 온보딩 │     ▼               ▼                    │
│                     │   유도   │ ┌──────────┐  ┌──────────┐               │
│                     └──────────┘ │ 계정 통합 │  │ 신규 가입 │               │
│                                  │ (Account  │  │ 처리     │               │
│                                  │  Linking)  │  └──────────┘               │
│                                  │           │                            │
│                                  │ email_    │                            │
│                                  │ verified  │                            │
│                                  │ 확인 필요!│                            │
│                                  └──────────┘                              │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

6.3 이메일 기반 계정 통합 (Account Linking)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Account Linking 전략과 보안 고려사항                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  시나리오: 사용자가 Google로 먼저 가입 후, Kakao로도 로그인 시도            │
│  두 계정의 이메일이 동일: user@gmail.com                                   │
│                                                                             │
│  전략 1: 자동 통합 (Auto-Linking) - 편리하지만 위험                        │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  조건: Provider에서 받은 이메일이 이미 등록된 이메일과 일치  │           │
│  │  동작: 자동으로 같은 users 레코드에 social_accounts 추가    │           │
│  │                                                             │           │
│  │  위험: 이메일 검증 없이 통합하면 계정 탈취 가능!             │           │
│  │  ├── 공격자가 피해자 이메일로 가짜 소셜 계정 생성           │           │
│  │  ├── 해당 소셜 계정으로 로그인 → 자동 통합 → 계정 탈취     │           │
│  │  └── 반드시 Provider의 email_verified=true 확인 필요        │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  전략 2: 수동 통합 (Manual Linking) - 안전하지만 번거로움                  │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  1. 새 Provider 로그인 시 같은 이메일 계정 발견              │           │
│  │  2. 사용자에게 안내: "이미 Google로 가입된 이메일입니다"     │           │
│  │  3. 기존 계정으로 로그인하도록 유도                          │           │
│  │  4. 기존 계정 로그인 후 "소셜 계정 연결" 설정에서 추가 연동 │           │
│  │  5. 두 Provider 모두 같은 계정에 연결됨                     │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  전략 3: 조건부 자동 통합 (권장)                                           │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  email_verified = true  → 자동 통합 허용                    │           │
│  │  email_verified = false → 수동 통합 강제                    │           │
│  │  email = null           → 무조건 새 계정 생성               │           │
│  │                                                             │           │
│  │  추가 안전장치:                                             │           │
│  │  ├── Provider가 email_verified 정보를 제공하는지 확인       │           │
│  │  │   ├── Google: 제공 (거의 항상 true)                      │           │
│  │  │   ├── Kakao: email_verified 필드 있음                    │           │
│  │  │   ├── Naver: 미제공 (기본적으로 verified 간주 가능)      │           │
│  │  │   └── Apple: 제공 (email_verified 항상 true)             │           │
│  │  └── 의심스러운 경우 추가 인증 요구 (이메일 인증 코드 등)   │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  구현 시 주의사항:                                                         │
│  ├── Apple Private Email Relay 이메일은 통합 대상에서 제외                 │
│  ├── 하나의 이메일에 같은 Provider 계정은 1개만 허용                       │
│  ├── 계정 통합 이벤트는 반드시 로그 기록 (보안 감사)                       │
│  └── 통합 해제(Unlink) 기능도 제공 필요                                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

6.4 탈퇴 및 데이터 삭제

┌─────────────────────────────────────────────────────────────────────────────┐
│              회원 탈퇴 처리 (GDPR/PIPA 준수)                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  탈퇴 처리 순서:                                                           │
│                                                                             │
│  1. Provider 연동 해제 (Unlink API 호출)                                   │
│     ├── Kakao:  POST kapi.kakao.com/v1/user/unlink                         │
│     ├── Google: POST oauth2.googleapis.com/revoke?token={AT}               │
│     ├── Naver:  POST nid.naver.com/oauth2.0/token                         │
│     │           (grant_type=delete, service_provider=...)                  │
│     └── Apple:  POST appleid.apple.com/auth/revoke                        │
│                 (client_secret JWT 필요, App Store 심사 필수 사항!)        │
│                                                                             │
│  2. 서비스 데이터 처리                                                     │
│     ├── 즉시 삭제: social_accounts, provider_tokens,                       │
│     │              service_refresh_tokens                                  │
│     ├── 소프트 삭제: users 테이블 (deleted_at 설정)                        │
│     │   └── 복구 요청 기간 (7~30일) 후 하드 삭제                           │
│     ├── 익명화: 법적 보관 필요 데이터 (결제 기록 등)                       │
│     │   └── 이메일, 이름 → 해시 또는 "탈퇴회원" 처리                       │
│     └── 완전 삭제: 보관 기한 경과 후                                       │
│                                                                             │
│  3. 법적 요구사항                                                          │
│     ├── 개인정보보호법(PIPA): 목적 달성 시 지체 없이 파기                  │
│     ├── GDPR (EU 대상): Right to Erasure (잊힐 권리)                       │
│     ├── Apple: 탈퇴 시 Apple revoke API 미호출 → 심사 거절                │
│     └── 통신비밀보호법: 로그인 기록 3개월 보관 의무 (한국)                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

7. 시스템 구축에 필요한 요소

7.1 인프라 구성

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 인프라 아키텍처                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  Client (Browser / Mobile App)                                      │   │
│  │  ├── React/Next.js / Flutter / Swift                                │   │
│  │  └── "카카오 로그인" 버튼 클릭 → Redirect 시작                     │   │
│  └────────────────────────────┬────────────────────────────────────────┘   │
│                               │                                            │
│                               ▼                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  API Gateway / Reverse Proxy                                        │   │
│  │  ├── Kong / Nginx / AWS API Gateway / Traefik                       │   │
│  │  ├── Rate Limiting: IP당 로그인 시도 제한 (분당 10회)               │   │
│  │  ├── CORS: 허용 도메인 화이트리스트                                 │   │
│  │  ├── TLS Termination: HTTPS 강제                                    │   │
│  │  └── Request Logging: 모든 인증 요청 로그                           │   │
│  └────────────────────────────┬────────────────────────────────────────┘   │
│                               │                                            │
│                               ▼                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  Auth Service (인증 전담 마이크로서비스)                              │   │
│  │  ├── /auth/{provider}/login    → Authorization URL 생성 + Redirect  │   │
│  │  ├── /auth/{provider}/callback → Code 수신 + Token 교환             │   │
│  │  ├── /auth/token/refresh       → 서비스 토큰 갱신                   │   │
│  │  ├── /auth/logout              → 세션 무효화                        │   │
│  │  └── /auth/me                  → 현재 사용자 정보                   │   │
│  └──────┬──────────────┬──────────────┬────────────────────────────────┘   │
│         │              │              │                                     │
│         ▼              ▼              ▼                                     │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐                             │
│  │   Redis    │ │    RDB     │ │   Kafka    │                             │
│  │            │ │            │ │ (Optional) │                             │
│  │ - state    │ │ - users    │ │            │                             │
│  │   임시 저장│ │ - social_  │ │ - 가입     │                             │
│  │ - 세션 캐시│ │   accounts │ │   이벤트   │                             │
│  │ - Rate     │ │ - tokens   │ │ - 로그인   │                             │
│  │   Limit    │ │ - login_   │ │   이벤트   │                             │
│  │   카운터   │ │   history  │ │ - 탈퇴     │                             │
│  │ - Token    │ │            │ │   이벤트   │                             │
│  │   Blacklist│ │ PostgreSQL │ │            │                             │
│  └────────────┘ │ / MySQL    │ └────────────┘                             │
│                 └────────────┘                                             │
│                                                                             │
│  외부 연동:                                                                │
│  ├── kauth.kakao.com / kapi.kakao.com                                     │
│  ├── accounts.google.com / oauth2.googleapis.com                           │
│  ├── nid.naver.com / openapi.naver.com                                    │
│  └── appleid.apple.com                                                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

7.2 보안 체크리스트

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 보안 필수 체크리스트                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  전송 보안:                                                                │
│  [x] HTTPS 필수 (HTTP 요청 시 자동 Redirect)                              │
│  [x] HSTS 헤더 설정 (Strict-Transport-Security)                           │
│  [x] Redirect URI는 HTTPS만 허용 (localhost 제외)                         │
│                                                                             │
│  CORS 설정:                                                                │
│  [x] Access-Control-Allow-Origin: 정확한 도메인만 (와일드카드 금지)       │
│  [x] Access-Control-Allow-Credentials: true (쿠키 전송 시)                │
│  [x] Preflight 캐시: Access-Control-Max-Age 설정                          │
│                                                                             │
│  OAuth 보안:                                                               │
│  [x] state 파라미터 필수 (CSRF 방지, 세션에 저장 후 검증)                  │
│  [x] nonce 파라미터 (OIDC 사용 시, 리플레이 방지)                         │
│  [x] Redirect URI 정확히 일치 검증 (화이트리스트)                          │
│  [x] Authorization Code 일회용 보장 (사용 후 즉시 무효화)                 │
│  [x] client_secret 환경 변수로 관리 (코드/Git에 포함 금지)                │
│  [x] PKCE 사용 (지원하는 Provider의 경우)                                 │
│                                                                             │
│  토큰 보안:                                                                │
│  [x] Access Token: httpOnly + Secure + SameSite=Lax 쿠키                  │
│  [x] Refresh Token: 서버 DB 저장 (해시값만), 클라이언트 노출 최소화       │
│  [x] Provider Token: AES-256 암호화 후 DB 저장                            │
│  [x] Token Rotation: Refresh Token 사용 시 새 토큰 발급 + 이전 무효화     │
│  [x] JWT 서명 키 정기 교체 (Key Rotation)                                 │
│                                                                             │
│  Rate Limiting:                                                            │
│  [x] 로그인 시도: IP당 분당 10회                                          │
│  [x] Token 갱신: 사용자당 분당 5회                                        │
│  [x] 회원가입: IP당 시간당 3회                                            │
│  [x] 전역: 초당 1000 요청 (서비스 규모에 따라 조정)                       │
│                                                                             │
│  입력 검증:                                                                │
│  [x] code 파라미터 형식 검증 (영숫자 + 특수문자 제한)                     │
│  [x] state 파라미터 길이 및 형식 검증                                     │
│  [x] Provider 응답 데이터 sanitization                                    │
│  [x] SQL Injection 방지 (Parameterized Query)                             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

7.3 라이브러리/프레임워크 비교

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 구현 라이브러리 비교                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────┬──────────────┬───────────────┬──────────────────┐    │
│  │ 라이브러리       │ 언어/프레임워크│ 난이도        │ 적합한 경우      │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Spring Security  │ Java/Kotlin  │ 중~상         │ 엔터프라이즈,     │    │
│  │ OAuth2 Client    │ Spring Boot  │               │ 대규모 서비스    │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ NextAuth.js      │ JavaScript   │ 하            │ Next.js 프로젝트 │    │
│  │ (Auth.js v5)     │ Next.js      │               │ 빠른 구현       │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Passport.js      │ JavaScript   │ 중            │ Express/Node.js  │    │
│  │                  │ Node.js      │               │ 유연한 전략     │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Keycloak         │ Java (서버)  │ 중~상         │ 자체 IdP 필요,   │    │
│  │                  │ 독립 서비스  │               │ 기업 SSO 통합   │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Auth0            │ SaaS         │ 하            │ 빠른 출시,       │    │
│  │                  │ (관리형)     │               │ 운영 부담 최소화 │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Firebase Auth    │ SaaS         │ 하            │ 모바일 앱,       │    │
│  │                  │ (Google)     │               │ 프로토타입      │    │
│  ├──────────────────┼──────────────┼───────────────┼──────────────────┤    │
│  │ Authlib          │ Python       │ 중            │ FastAPI/Flask    │    │
│  │                  │              │               │ Python 백엔드   │    │
│  └──────────────────┴──────────────┴───────────────┴──────────────────┘    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Spring Security OAuth2 Client (간단 예시)

// application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          kakao:
            client-id: ${KAKAO_CLIENT_ID}
            client-secret: ${KAKAO_CLIENT_SECRET}
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
            scope: profile_nickname, account_email
            client-name: Kakao
            client-authentication-method: client_secret_post
          google:
            client-id: ${GOOGLE_CLIENT_ID}
            client-secret: ${GOOGLE_CLIENT_SECRET}
            scope: openid, profile, email
          naver:
            client-id: ${NAVER_CLIENT_ID}
            client-secret: ${NAVER_CLIENT_SECRET}
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
            scope: name, email, profile_image
        provider:
          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user-name-attribute: id
          naver:
            authorization-uri: https://nid.naver.com/oauth2.0/authorize
            token-uri: https://nid.naver.com/oauth2.0/token
            user-info-uri: https://openapi.naver.com/v1/nid/me
            user-name-attribute: response
// OAuth2 로그인 성공 핸들러
@Component
public class OAuth2LoginSuccessHandler
        extends SimpleUrlAuthenticationSuccessHandler {

    @Autowired private UserService userService;
    @Autowired private JwtTokenProvider jwtProvider;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) throws IOException {

        OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
        String registrationId = ((OAuth2AuthenticationToken) authentication)
                .getAuthorizedClientRegistrationId();  // "kakao", "google" 등

        // Provider별 사용자 정보 추출
        SocialUserInfo userInfo = extractUserInfo(registrationId, oAuth2User);

        // 신규/기존 회원 판별 + JIT Provisioning
        User user = userService.findOrCreateUser(userInfo);

        // 서비스 자체 JWT 발급
        String accessToken = jwtProvider.createAccessToken(user.getId());
        String refreshToken = jwtProvider.createRefreshToken(user.getId());

        // Refresh Token DB 저장
        userService.saveRefreshToken(user.getId(), refreshToken);

        // 쿠키 또는 Redirect URL에 토큰 포함
        addTokenCookie(response, accessToken, refreshToken);
        getRedirectStrategy().sendRedirect(request, response, "/");
    }
}

NextAuth.js (Auth.js v5) 예시

// auth.ts (Next.js App Router)
import NextAuth from "next-auth"
import KakaoProvider from "next-auth/providers/kakao"
import GoogleProvider from "next-auth/providers/google"
import NaverProvider from "next-auth/providers/naver"
import AppleProvider from "next-auth/providers/apple"

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    KakaoProvider({
      clientId: process.env.KAKAO_CLIENT_ID!,
      clientSecret: process.env.KAKAO_CLIENT_SECRET!,
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    NaverProvider({
      clientId: process.env.NAVER_CLIENT_ID!,
      clientSecret: process.env.NAVER_CLIENT_SECRET!,
    }),
    AppleProvider({
      clientId: process.env.APPLE_CLIENT_ID!,
      clientSecret: process.env.APPLE_CLIENT_SECRET!,
    }),
  ],
  callbacks: {
    async signIn({ user, account, profile }) {
      // 신규/기존 회원 판별 + 계정 연동 로직
      const existingUser = await findUserBySocialAccount(
        account.provider,
        account.providerAccountId
      );
      if (!existingUser) {
        await createUserWithSocialAccount(user, account);
      }
      return true;
    },
    async jwt({ token, account }) {
      if (account) {
        token.accessToken = account.access_token;
        token.provider = account.provider;
      }
      return token;
    },
    async session({ session, token }) {
      session.accessToken = token.accessToken;
      return session;
    },
  },
})

8. 보안 심화

8.1 Token 탈취 대응

┌─────────────────────────────────────────────────────────────────────────────┐
│              Token 탈취 방지 및 대응 전략                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1. Refresh Token Rotation (필수)                                          │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │                                                             │           │
│  │  일반적 방식 (위험):                                        │           │
│  │    RT-1 → 사용 → 새 AT 발급 (RT-1 그대로 유지)             │           │
│  │    RT-1 → 사용 → 새 AT 발급 (RT-1 계속 사용 가능)          │           │
│  │    → RT-1 탈취 시 만료까지 악용 가능!                       │           │
│  │                                                             │           │
│  │  Rotation 방식 (안전):                                      │           │
│  │    RT-1 → 사용 → 새 AT + 새 RT-2 발급 (RT-1 즉시 무효화)   │           │
│  │    RT-2 → 사용 → 새 AT + 새 RT-3 발급 (RT-2 즉시 무효화)   │           │
│  │    → 탈취된 RT 사용 시 즉시 탐지 (이미 무효화됨)            │           │
│  │                                                             │           │
│  │  Rotation 탐지 로직:                                        │           │
│  │    이미 사용된(무효화된) RT로 요청 → 탈취 의심              │           │
│  │    → 해당 사용자의 모든 RT 즉시 무효화 (전체 로그아웃)      │           │
│  │    → 사용자에게 보안 알림 발송                               │           │
│  │                                                             │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  2. DPoP (Demonstration of Proof-of-Possession, RFC 9449)                  │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │                                                             │           │
│  │  기존 Bearer Token의 한계:                                   │           │
│  │  - Token을 가진 누구나 사용 가능 (소유 증명 없음)           │           │
│  │  - 탈취 시 바로 악용 가능                                   │           │
│  │                                                             │           │
│  │  DPoP 방식:                                                 │           │
│  │  1. 클라이언트가 키쌍 생성 (공개키 + 비밀키)                │           │
│  │  2. Token 요청 시 DPoP Proof JWT 첨부 (비밀키로 서명)       │           │
│  │  3. 서버가 Token을 클라이언트 공개키에 바인딩               │           │
│  │  4. API 호출 시 매번 DPoP Proof 첨부 필요                   │           │
│  │  5. Token + 비밀키 둘 다 없으면 사용 불가                   │           │
│  │                                                             │           │
│  │  상태: RFC 9449로 표준화 (2023), OAuth 2.1에서 권장          │           │
│  │  지원: 아직 소셜 Provider 지원은 제한적                     │           │
│  │        (자체 Auth Server에서 구현 가능)                      │           │
│  │                                                             │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

8.2 Bot 대량 가입 방지

┌─────────────────────────────────────────────────────────────────────────────┐
│              봇 가입 방지 다층 방어 전략                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Layer 1: Rate Limiting                                                    │
│  ├── IP 기반: 동일 IP에서 시간당 가입 3회 제한                             │
│  ├── 전역: 분당 전체 가입 수 상한 설정                                     │
│  ├── Sliding Window 방식 (Redis ZSET 활용)                                 │
│  └── 프록시/VPN 감지: X-Forwarded-For 체인 분석                            │
│                                                                             │
│  Layer 2: CAPTCHA                                                          │
│  ├── reCAPTCHA v3 (점수 기반, 사용자 마찰 없음)                            │
│  │   ├── score >= 0.7: 정상 사용자 → 통과                                 │
│  │   ├── score 0.3~0.7: 의심 → 추가 인증 요구                             │
│  │   └── score < 0.3: 봇 의심 → 차단                                      │
│  ├── hCaptcha (GDPR 친화적 대안)                                           │
│  └── Turnstile (Cloudflare, 사용자 경험 최적화)                            │
│                                                                             │
│  Layer 3: Device Fingerprinting                                            │
│  ├── 브라우저 지문: Canvas, WebGL, 폰트 목록, 화면 해상도 등              │
│  ├── 동일 Fingerprint에서 다수 계정 생성 시 차단                           │
│  └── FingerprintJS, ThreatMetrix 등 활용                                   │
│                                                                             │
│  Layer 4: 행동 분석                                                        │
│  ├── 로그인 버튼까지의 시간 (봇은 즉시 클릭)                              │
│  ├── 마우스/터치 패턴 분석                                                 │
│  ├── 페이지 스크롤 여부                                                    │
│  └── JavaScript 실행 환경 검증 (Headless Chrome 감지)                      │
│                                                                             │
│  Layer 5: CI/DI 본인인증 (한국 서비스)                                     │
│  ├── PASS 인증 (통신사 본인확인)                                           │
│  ├── 카카오톡 본인인증                                                     │
│  ├── 공동인증서 (구 공인인증서)                                            │
│  ├── CI 값으로 중복 가입 차단 (동일 CI = 동일인)                           │
│  └── 비즈앱에서 카카오 CI 활용 가능                                        │
│                                                                             │
│  Layer 6: 전화번호 인증 (자체 구현)                                        │
│  ├── SMS 인증 코드 발송 (6자리, 3분 유효)                                  │
│  ├── 동일 전화번호 중복 가입 제한                                          │
│  └── SMS API: NHN Cloud, AWS SNS, Twilio 등                               │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

8.3 세션 관리 및 다중 디바이스

┌─────────────────────────────────────────────────────────────────────────────┐
│              다중 디바이스 세션 관리 전략                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  세션 정책 옵션:                                                           │
│                                                                             │
│  1. 무제한 세션 (Netflix 스타일)                                           │
│     ├── 모든 디바이스에서 동시 로그인 허용                                 │
│     └── 세션 목록 조회 + 개별/전체 로그아웃 제공                           │
│                                                                             │
│  2. 최대 N개 세션 (Google 스타일)                                          │
│     ├── 세션 수 초과 시 가장 오래된 세션 자동 만료                         │
│     ├── Redis ZSET으로 세션 관리 (score = 마지막 활동 시간)                │
│     └── 새 로그인 시 ZSET 크기 확인 → 초과 시 oldest 제거                 │
│                                                                             │
│  3. 단일 세션 (은행 앱 스타일)                                             │
│     ├── 새 로그인 시 기존 모든 세션 강제 만료                              │
│     ├── "다른 기기에서 로그인되어 현재 세션이 종료됩니다" 알림             │
│     └── 보안 최우선 서비스에 적합                                          │
│                                                                             │
│  Session Fixation 방지:                                                    │
│  ├── 로그인 성공 시 반드시 세션 ID 재발급                                  │
│  ├── 이전 세션 ID 즉시 무효화                                              │
│  └── Spring Security: sessionFixation().newSession()                       │
│                                                                             │
│  Provider 장애 시 Fallback:                                                │
│  ├── 이미 로그인된 사용자: 서비스 자체 JWT로 정상 동작                     │
│  ├── 신규 로그인: 해당 Provider 버튼 비활성화 + 안내 메시지               │
│  ├── Circuit Breaker 패턴: Provider API 장애 감지 → 자동 차단             │
│  │   ├── Resilience4j (Java), opossum (Node.js)                            │
│  │   ├── 실패율 50% 이상 → Circuit Open → 60초 후 Half-Open               │
│  │   └── Open 상태에서 즉시 에러 반환 (Provider 호출 안 함)               │
│  └── 다중 Provider 지원의 중요성 (하나 장애 시 대체 수단 존재)            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

9. 2025-2026 최신 동향

9.1 Passkeys (WebAuthn / FIDO2)

┌─────────────────────────────────────────────────────────────────────────────┐
│              Passkeys - 비밀번호 없는 인증의 미래                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Passkeys란:                                                               │
│  ├── FIDO2 / WebAuthn 기반의 비밀번호 없는 인증                            │
│  ├── 공개키 암호화 사용 (비밀키는 디바이스에만 저장)                       │
│  ├── 생체인식(지문, 얼굴), PIN, 패턴으로 인증                              │
│  └── Apple, Google, Microsoft 모두 지원 (2022~)                            │
│                                                                             │
│  동작 방식:                                                                │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  등록 (Registration):                                       │           │
│  │  1. 서버 → Challenge 생성 → 클라이언트 전송                 │           │
│  │  2. 클라이언트 → 생체인증 → 키쌍 생성                      │           │
│  │  3. 공개키 → 서버 저장                                      │           │
│  │  4. 비밀키 → 디바이스 Secure Enclave (절대 외부 전송 안 됨) │           │
│  │                                                             │           │
│  │  인증 (Authentication):                                     │           │
│  │  1. 서버 → Challenge 생성 → 클라이언트 전송                 │           │
│  │  2. 클라이언트 → 생체인증 → 비밀키로 Challenge 서명         │           │
│  │  3. 서명 → 서버 전송 → 공개키로 검증                        │           │
│  │  4. 검증 성공 → 로그인 완료                                 │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  소셜 로그인과의 관계:                                                     │
│  ├── 대체가 아닌 보완 관계                                                 │
│  ├── 소셜 로그인: "어떤 계정으로 로그인할지" (Identity)                    │
│  ├── Passkeys: "어떻게 인증할지" (Authentication Method)                   │
│  ├── 조합 가능: Passkey로 Google 계정 인증 → 소셜 로그인                   │
│  └── 신규 서비스: Passkeys 우선 제공 + 소셜 로그인 보조 권장               │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

9.2 FedCM (Federated Credential Management) API

┌─────────────────────────────────────────────────────────────────────────────┐
│              FedCM - 브라우저 네이티브 소셜 로그인                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  배경: 3rd-party 쿠키 차단 시대                                            │
│  ├── Chrome Privacy Sandbox: 3rd-party 쿠키 단계적 차단                    │
│  ├── Safari/Firefox: 이미 3rd-party 쿠키 차단                              │
│  ├── 문제: 기존 소셜 로그인은 iframe + 3rd-party 쿠키에 의존               │
│  └── 해결: FedCM API로 브라우저가 직접 중재                                │
│                                                                             │
│  FedCM 동작 방식:                                                          │
│  ┌─────────────────────────────────────────────────────────────┐           │
│  │  기존 방식:                                                  │           │
│  │  웹사이트 → iframe으로 Google 페이지 로드                    │           │
│  │         → 3rd-party 쿠키로 Google 로그인 상태 확인           │           │
│  │         → 토큰 반환                                          │           │
│  │                                                             │           │
│  │  FedCM 방식:                                                 │           │
│  │  웹사이트 → navigator.credentials.get() API 호출             │           │
│  │         → 브라우저가 네이티브 UI로 계정 선택 팝업 표시       │           │
│  │         → 브라우저가 직접 IdP에 요청 (3rd-party 쿠키 불필요) │           │
│  │         → 토큰 반환                                          │           │
│  └─────────────────────────────────────────────────────────────┘           │
│                                                                             │
│  // FedCM API 사용 예시 (JavaScript)                                       │
│  const credential = await navigator.credentials.get({                      │
│    identity: {                                                             │
│      providers: [{                                                         │
│        configURL: "https://accounts.google.com/gsi/fedcm.json",            │
│        clientId: "your-client-id",                                         │
│      }]                                                                    │
│    }                                                                       │
│  });                                                                       │
│  // credential.token에 ID Token 포함                                       │
│                                                                             │
│  현재 상태 (2025~2026):                                                    │
│  ├── Chrome: 지원 (Chrome 108+, One Tap이 FedCM 기반으로 전환 중)         │
│  ├── Firefox: 개발 중                                                      │
│  ├── Safari: 미지원 (Apple은 자체 방식 선호)                               │
│  ├── Google: One Tap → FedCM 전환 진행 중                                  │
│  └── 카카오/네이버: 아직 FedCM 미지원 (향후 지원 가능성)                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

9.3 OAuth 2.1 + DPoP + Zero Trust

┌─────────────────────────────────────────────────────────────────────────────┐
│              2025-2026 인증 트렌드 종합                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  OAuth 2.1 표준화 진행:                                                    │
│  ├── 상태: IETF Draft (draft-ietf-oauth-v2-1-11, 2024년 말 기준)          │
│  ├── 변경사항 요약: PKCE 필수, Implicit/Password 제거, RT Rotation        │
│  ├── 실무 영향: 대부분의 Provider가 이미 2.1 수준 구현 완료               │
│  └── 권장: 신규 구현 시 OAuth 2.1 기준 적용                               │
│                                                                             │
│  DPoP (Demonstration of Proof-of-Possession):                              │
│  ├── RFC 9449 (2023 표준화)                                                │
│  ├── Bearer Token의 근본적 한계 극복 (소유 증명 추가)                      │
│  ├── 금융/의료 등 고보안 서비스에서 도입 시작                              │
│  └── 자체 Auth Server 구축 시 적극 고려                                    │
│                                                                             │
│  Zero Trust 인증:                                                          │
│  ├── 원칙: "절대 신뢰하지 않고, 항상 검증"                                │
│  ├── 지속적 검증: 매 요청마다 인증/인가 확인                               │
│  ├── 최소 권한: 필요한 최소한의 접근 권한만 부여                           │
│  ├── 네트워크 경계 무신뢰: VPN 안이라고 안전하지 않음                      │
│  └── 소셜 로그인 적용: Token 수명 단축, 지속적 세션 검증                   │
│                                                                             │
│  카카오 2025 정책 변경:                                                    │
│  ├── 동의 항목 정책 강화 (불필요한 정보 수집 제한)                         │
│  ├── 비즈앱 심사 기준 강화                                                 │
│  ├── OIDC 지원 확대 (ID Token 활용 권장)                                   │
│  └── 카카오톡 채널 연동 정책 변경 (채널 추가 동의 UI 변경)                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

10. 종합 요약 및 구현 체크리스트

10.1 구현 순서 로드맵

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 구현 로드맵 (단계별)                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1단계: 단일 Provider 연동 (1~2주)                                         │
│  ├── Kakao Login 연동 (한국 서비스 기준)                                   │
│  ├── DB 스키마 생성 (users, social_accounts, provider_tokens)              │
│  ├── 기본 흐름: 로그인 → Token 교환 → 사용자 정보 조회 → 세션 생성        │
│  ├── 서비스 자체 JWT 발급 로직                                             │
│  └── 로그아웃 처리                                                         │
│                                                                             │
│  2단계: 멀티 Provider 확장 (1~2주)                                         │
│  ├── Google, Naver, Apple 추가                                             │
│  ├── Provider별 사용자 정보 정규화 (통일된 인터페이스)                      │
│  ├── Apple 고유 처리 (JWT secret, Private Email, 첫 로그인 이름)           │
│  └── Provider 선택 UI 구현                                                 │
│                                                                             │
│  3단계: Account Linking (1주)                                              │
│  ├── 이메일 기반 계정 통합 (email_verified 확인)                           │
│  ├── 마이페이지: 소셜 계정 연결/해제 기능                                  │
│  ├── 다중 Provider 연동 상태 표시                                          │
│  └── 통합 해제 시 최소 1개 로그인 수단 유지 검증                           │
│                                                                             │
│  4단계: 보안 강화 (1~2주)                                                  │
│  ├── Rate Limiting (Redis 기반)                                            │
│  ├── CAPTCHA 연동 (reCAPTCHA v3)                                           │
│  ├── Token Rotation 구현                                                   │
│  ├── 다중 디바이스 세션 관리                                               │
│  └── CI/DI 본인인증 연동 (비즈앱, 필요 시)                                 │
│                                                                             │
│  5단계: 모니터링 + 이상 탐지 (1주)                                         │
│  ├── 로그인 성공/실패 메트릭 대시보드                                      │
│  ├── Provider별 응답 시간 모니터링                                         │
│  ├── 이상 패턴 알림 (같은 IP 대량 가입, 비정상 시간대 등)                  │
│  └── Circuit Breaker 설정 (Provider 장애 대응)                             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

10.2 아키텍처 결정 가이드

┌─────────────────────────────────────────────────────────────────────────────┐
│              자체 구축 vs Keycloak vs Auth0 비교                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────┬──────────────────┬──────────────────┬──────────────────┐ │
│  │              │ 자체 구축        │ Keycloak         │ Auth0 (SaaS)     │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 비용         │ 개발 인건비      │ 서버 운영비      │ 월 사용료        │ │
│  │              │ (높음)           │ (중간)           │ (MAU 기반)       │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 초기 구축    │ 2~4주            │ 1~2주            │ 1~3일            │ │
│  │ 시간         │                  │                  │                  │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 커스텀       │ 완전 자유        │ SPI 확장 가능    │ Actions/Rules    │ │
│  │ 유연성       │                  │ (Java 기반)      │ (제한적)         │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 운영 부담    │ 전적으로 자체    │ 서버 관리 필요   │ 거의 없음        │ │
│  │              │ 관리             │ (Docker/K8s)     │ (SaaS)           │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 보안 책임    │ 전적으로 자체    │ 자체 + 커뮤니티  │ Auth0 + 자체     │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 소셜 로그인  │ 직접 구현        │ Identity         │ 60+ Provider     │ │
│  │ Provider     │ (각 Provider별)  │ Brokering        │ 내장             │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 한국         │ 직접 구현        │ 커스텀 Provider  │ 일부 미지원      │ │
│  │ Provider     │ (최적화 가능)    │ 추가 필요        │ (Kakao 등)       │ │
│  ├──────────────┼──────────────────┼──────────────────┼──────────────────┤ │
│  │ 추천 대상    │ 대규모 서비스    │ 중규모 서비스    │ 스타트업         │ │
│  │              │ 특수 요구사항    │ 기업 SSO 필요    │ 빠른 출시 필요   │ │
│  └──────────────┴──────────────────┴──────────────────┴──────────────────┘ │
│                                                                             │
│  한국 서비스 권장:                                                         │
│  ├── 스타트업/MVP: 자체 구축 (Spring Security / NextAuth.js)               │
│  │   └── Auth0/Firebase는 카카오/네이버 지원이 부족할 수 있음              │
│  ├── 중견 서비스: 자체 구축 + Redis + 모니터링                             │
│  └── 대규모 서비스: 자체 Auth 마이크로서비스 또는 Keycloak 커스터마이징    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

10.3 최종 체크리스트

┌─────────────────────────────────────────────────────────────────────────────┐
│              소셜 로그인 시스템 출시 전 체크리스트                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  기본 기능:                                                                │
│  [ ] Kakao / Google / Naver / Apple 로그인 동작 확인                       │
│  [ ] 신규 가입 + 기존 회원 로그인 정상 동작                                │
│  [ ] 서비스 자체 JWT 발급 + 갱신 동작                                      │
│  [ ] 로그아웃 시 세션 무효화                                               │
│  [ ] 회원 탈퇴 시 Provider 연동 해제 + 데이터 삭제                         │
│                                                                             │
│  보안:                                                                     │
│  [ ] HTTPS 강제                                                            │
│  [ ] CORS 정확한 도메인만 허용                                             │
│  [ ] state 파라미터 검증 (CSRF 방지)                                       │
│  [ ] Redirect URI 화이트리스트 (정확한 매칭)                               │
│  [ ] client_secret 환경 변수 관리 (Git 미포함)                             │
│  [ ] Token 암호화 저장 (Provider Token)                                    │
│  [ ] Refresh Token Rotation 구현                                           │
│  [ ] Rate Limiting 설정                                                    │
│  [ ] SQL Injection / XSS 방지                                              │
│                                                                             │
│  에러 처리:                                                                │
│  [ ] Provider 인증 거부 (사용자가 동의 취소)                               │
│  [ ] Provider 서버 장애 (5xx 응답)                                         │
│  [ ] Token 교환 실패 (잘못된 code)                                         │
│  [ ] 이메일 null 처리 (Kakao)                                              │
│  [ ] Apple 이름 미제공 (재로그인 시)                                       │
│  [ ] 네트워크 타임아웃                                                     │
│                                                                             │
│  UX:                                                                       │
│  [ ] 로그인 버튼 Provider 가이드라인 준수                                  │
│  [ ] 로딩 상태 표시 (Provider Redirect 중)                                 │
│  [ ] 에러 메시지 사용자 친화적 표현                                        │
│  [ ] 최초 가입 시 온보딩 플로우 (추가 정보 수집)                           │
│  [ ] 마이페이지 소셜 계정 연결/해제 UI                                     │
│                                                                             │
│  법적/규정:                                                                │
│  [ ] 개인정보 처리방침 업데이트 (소셜 로그인 관련 항목)                    │
│  [ ] 이용약관 소셜 로그인 관련 조항                                        │
│  [ ] Apple Sign In 제공 (iOS 앱에서 소셜 로그인 시 필수)                   │
│  [ ] Apple Token Revocation (탈퇴 시 필수)                                 │
│  [ ] 로그인 기록 보관 (통신비밀보호법, 3개월)                              │
│                                                                             │
│  모니터링:                                                                 │
│  [ ] 로그인 성공/실패율 대시보드                                           │
│  [ ] Provider별 응답 시간 모니터링                                         │
│  [ ] 비정상 패턴 알림 설정                                                 │
│  [ ] Circuit Breaker 설정                                                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

11. 참고 자료

11.1 공식 문서

┌─────────────────────────────────────────────────────────────────────────────┐
│              참고 자료 및 공식 문서                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  표준/RFC:                                                                 │
│  ├── RFC 6749 - OAuth 2.0 Authorization Framework                          │
│  │   https://datatracker.ietf.org/doc/html/rfc6749                         │
│  ├── RFC 7636 - PKCE (Proof Key for Code Exchange)                         │
│  │   https://datatracker.ietf.org/doc/html/rfc7636                         │
│  ├── RFC 9449 - DPoP (Demonstration of Proof-of-Possession)               │
│  │   https://datatracker.ietf.org/doc/html/rfc9449                         │
│  ├── OAuth 2.1 Draft                                                       │
│  │   https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/              │
│  ├── OpenID Connect Core 1.0                                               │
│  │   https://openid.net/specs/openid-connect-core-1_0.html                │
│  └── WebAuthn (W3C)                                                        │
│      https://www.w3.org/TR/webauthn-2/                                     │
│                                                                             │
│  Provider 개발자 문서:                                                     │
│  ├── Kakao Developers                                                      │
│  │   https://developers.kakao.com/docs/latest/ko/kakaologin/common        │
│  ├── Google Identity Services                                              │
│  │   https://developers.google.com/identity                                │
│  ├── Naver Login                                                           │
│  │   https://developers.naver.com/docs/login/overview/overview.md         │
│  └── Apple Sign In                                                         │
│      https://developer.apple.com/sign-in-with-apple/                       │
│                                                                             │
│  라이브러리/프레임워크:                                                    │
│  ├── Spring Security OAuth2 Client                                         │
│  │   https://docs.spring.io/spring-security/reference/servlet/oauth2/      │
│  ├── NextAuth.js (Auth.js)                                                 │
│  │   https://authjs.dev/                                                   │
│  ├── Passport.js                                                           │
│  │   https://www.passportjs.org/                                           │
│  ├── Keycloak                                                              │
│  │   https://www.keycloak.org/documentation                                │
│  └── FedCM API (Chrome)                                                    │
│      https://developers.google.com/privacy-sandbox/cookies/fedcm           │
│                                                                             │
│  관련 문서 (이 저장소):                                                    │
│  ├── sso-연동.md - SSO 개념, OIDC 흐름, JIT Provisioning                  │
│  ├── oauth2-keycloak.md - OAuth 2.0 상세, Keycloak 구축                   │
│  └── jwt-인증메커니즘.md - JWT 구조, 검증, 보안                            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘