TL;DR

  • OAuth 2.0과 Keycloak의 핵심 개념과 사용 범위를 한눈에 정리
  • 등장 배경과 필요한 이유를 짚고 실무 적용 포인트를 연결
  • 주요 특징과 체크리스트를 빠르게 확인

1. 개념

이 문서에서는 현대 웹/모바일 애플리케이션의 인증/인가 표준인 OAuth 2.0OpenID Connect(OIDC), 그리고 이를 구현한 오픈소스 IAM 솔루션 Keycloak에 대해 상세히 설명합니다.

2. 배경

OAuth 2.0과 Keycloak이(가) 등장한 배경과 기존 한계를 정리한다.

3. 이유

이 주제를 이해하고 적용해야 하는 이유를 정리한다.

4. 특징

  • 배경: 왜 인증/인가가 복잡해졌나?
  • OAuth 2.0이란?
  • OpenID Connect (OIDC)
  • Keycloak이란?
  • 언제 Keycloak을 도입해야 하나?

5. 상세 내용

작성일: 2026-02-02 키워드: OAuth 2.0, OpenID Connect, OIDC, Keycloak, SSO, JWT, Access Token, Refresh Token, Authorization Server, IAM, 인증, 인가


개요

이 문서에서는 현대 웹/모바일 애플리케이션의 인증/인가 표준인 OAuth 2.0OpenID Connect(OIDC), 그리고 이를 구현한 오픈소스 IAM 솔루션 Keycloak에 대해 상세히 설명합니다.


1. 배경: 왜 인증/인가가 복잡해졌나?

1.1 과거의 단순한 세계

┌─────────────────────────────────────────────────────────────────────────────┐
│                    2000년대 초반: 단순한 인증                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  사용자                    서버                     데이터베이스             │
│    │                        │                           │                  │
│    │  1. ID/PW 입력         │                           │                  │
│    │ ─────────────────────→ │                           │                  │
│    │                        │  2. DB에서 비밀번호 확인   │                  │
│    │                        │ ─────────────────────────→ │                  │
│    │                        │ ←───────────────────────── │                  │
│    │  3. 세션 쿠키 발급     │                           │                  │
│    │ ←───────────────────── │                           │                  │
│    │                        │                           │                  │
│    │  4. 이후 요청마다      │                           │                  │
│    │     세션 쿠키 전송     │                           │                  │
│    │ ─────────────────────→ │                           │                  │
│                                                                             │
│  특징:                                                                      │
│  - 하나의 서버, 하나의 서비스                                               │
│  - 세션은 서버 메모리에 저장                                                │
│  - 단순하고 이해하기 쉬움                                                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 현대의 복잡한 요구사항

┌─────────────────────────────────────────────────────────────────────────────┐
│                    현재: 복잡한 인증 요구사항                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│                           ┌─────────────────┐                               │
│                           │   사용자 Kim    │                               │
│                           └────────┬────────┘                               │
│                                    │                                        │
│          ┌─────────────────────────┼─────────────────────────┐              │
│          │                         │                         │              │
│          ▼                         ▼                         ▼              │
│  ┌───────────────┐       ┌───────────────┐       ┌───────────────┐          │
│  │   웹 앱       │       │  모바일 앱    │       │  데스크톱 앱  │          │
│  │ (React/Vue)   │       │ (iOS/Android) │       │  (Electron)   │          │
│  └───────┬───────┘       └───────┬───────┘       └───────┬───────┘          │
│          │                       │                       │                  │
│          └───────────────────────┼───────────────────────┘                  │
│                                  │                                          │
│                                  ▼                                          │
│  ┌──────────────────────────────────────────────────────────────────┐       │
│  │                        API Gateway                               │       │
│  └──────────────────────────────┬───────────────────────────────────┘       │
│                                 │                                           │
│     ┌───────────────────────────┼───────────────────────────┐               │
│     │                           │                           │               │
│     ▼                           ▼                           ▼               │
│  ┌──────────┐            ┌──────────┐            ┌──────────┐               │
│  │ 사용자   │            │ 주문     │            │ 결제     │               │
│  │ 서비스   │            │ 서비스   │            │ 서비스   │               │
│  └──────────┘            └──────────┘            └──────────┘               │
│                                                                             │
│  🔴 발생하는 문제들:                                                        │
│  - 각 서비스마다 인증 로직 구현? (중복 코드 + 보안 위험)                    │
│  - 세션을 어디에 저장? (서비스가 여러 개인데 세션 공유?)                    │
│  - 모바일 앱은 쿠키를 어떻게 처리?                                          │
│  - 외부 서비스(Google, Kakao 로그인)와 연동은?                              │
│  - SSO(한 번 로그인으로 모든 서비스 접근)는?                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2. OAuth 2.0이란?

2.1 OAuth의 탄생 배경

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 탄생 스토리 (2006-2007)                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  🔴 당시 문제 상황:                                                         │
│                                                                             │
│  "내가 만든 앱에서 사용자의 Twitter 친구 목록을 가져오고 싶어요"            │
│                                                                             │
│  기존 방법 (매우 위험):                                                     │
│  ┌─────────────────────────────────────────────────────────────────┐       │
│  │  앱: "Twitter 아이디와 비밀번호를 알려주세요"                    │       │
│  │  사용자: "뭐? 내 비밀번호를 다른 앱에?"                          │       │
│  │                                                                 │       │
│  │  문제점:                                                        │       │
│  │  → 사용자 비밀번호를 제3자 앱에 직접 제공해야 함                 │       │
│  │  → 보안 위험: 앱이 비밀번호 저장/악용 가능                       │       │
│  │  → 권한 제한 불가: 앱이 사용자처럼 모든 것을 할 수 있음          │       │
│  │  → 비밀번호 변경 시 모든 앱 재설정 필요                          │       │
│  │  → 특정 앱만 권한 해제 불가                                     │       │
│  └─────────────────────────────────────────────────────────────────┘       │
│                                                                             │
│  💡 해결 아이디어:                                                          │
│  "비밀번호 대신 '제한된 권한을 가진 토큰'을 발급하면 어떨까?"              │
│                                                                             │
│  📅 타임라인:                                                               │
│  - 2006년: Twitter의 Blaine Cook과 Google 개발자들이 논의 시작             │
│  - 2007년: OAuth 1.0 초안 발표                                             │
│  - 2010년: OAuth 1.0a (보안 취약점 수정)                                   │
│  - 2012년: OAuth 2.0 RFC 6749 표준화 (완전히 새로운 설계)                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 OAuth 2.0 핵심 개념: 4가지 역할

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 2.0의 4가지 역할 (Roles)                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1️⃣ Resource Owner (자원 소유자)                                           │
│  ─────────────────────────────────                                          │
│     - 보호된 리소스(데이터)에 대한 접근 권한을 가진 사람                    │
│     - 보통 "최종 사용자(End User)"                                          │
│     - 예: Twitter 계정을 가진 Kim                                          │
│                                                                             │
│  2️⃣ Resource Server (자원 서버)                                            │
│  ───────────────────────────────                                            │
│     - 보호된 리소스를 호스팅하는 서버                                       │
│     - Access Token을 검증하고 요청에 응답                                   │
│     - 예: Twitter API 서버, Google Drive API                               │
│                                                                             │
│  3️⃣ Client (클라이언트)                                                    │
│  ────────────────────────                                                   │
│     - Resource Owner를 대신하여 보호된 리소스에 접근하려는 애플리케이션     │
│     - 예: "트위터 분석 앱", "Google Drive 동기화 앱"                        │
│                                                                             │
│  4️⃣ Authorization Server (인가 서버)                                       │
│  ──────────────────────────────────────                                     │
│     - Resource Owner를 인증하고 권한을 확인한 후 Access Token 발급         │
│     - 예: Twitter 로그인 서버, Google OAuth 서버                            │
│     - ⭐ Keycloak이 이 역할을 수행!                                         │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  실제 예시로 이해하기:                                                      │
│                                                                             │
│  "내 트위터 분석 앱이 사용자의 트윗을 분석하고 싶다"                         │
│                                                                             │
│  ┌────────────────────────────────────────────────────────────────┐        │
│  │ Resource Owner    : 트위터 사용자 Kim                          │        │
│  │ Client            : 트위터 분석 앱                             │        │
│  │ Authorization Server : Twitter OAuth 서버                      │        │
│  │ Resource Server   : Twitter API (트윗 데이터 제공)             │        │
│  └────────────────────────────────────────────────────────────────┘        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.3 OAuth 2.0 Authorization Code Flow

가장 일반적이고 안전한 흐름입니다.

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Authorization Code Flow (상세)                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  사용자(Kim)        클라이언트(앱)      Authorization      Resource         │
│     │                    │              Server             Server           │
│     │                    │                  │                  │            │
│     │ 1. "로그인" 클릭   │                  │                  │            │
│     │ ─────────────────→ │                  │                  │            │
│     │                    │                  │                  │            │
│     │                    │ 2. 인가 요청 URL 생성               │            │
│     │                    │    - client_id                     │            │
│     │                    │    - redirect_uri                  │            │
│     │                    │    - response_type=code            │            │
│     │                    │    - scope=read write              │            │
│     │                    │    - state=랜덤값                  │            │
│     │ ←─────────────── 리다이렉트 ─────────│                  │            │
│     │                    │                  │                  │            │
│     │ 3. 로그인 페이지 표시                 │                  │            │
│     │ ─────────────────────────────────────→│                  │            │
│     │                                       │                  │            │
│     │ 4. ID/PW 입력 + 권한 동의 ("이 앱이   │                  │            │
│     │    내 프로필을 읽어도 될까요?" 확인)  │                  │            │
│     │ ─────────────────────────────────────→│                  │            │
│     │                                       │                  │            │
│     │ 5. Authorization Code 발급            │                  │            │
│     │ ←── 리다이렉트: redirect_uri?code=abc123&state=랜덤값 ──│            │
│     │ ─────────────────→ │                  │                  │            │
│     │                    │                  │                  │            │
│     │                    │ 6. Code → Token 교환               │            │
│     │                    │    POST /token                     │            │
│     │                    │    - grant_type=authorization_code │            │
│     │                    │    - code=abc123                   │            │
│     │                    │    - client_id + client_secret     │            │
│     │                    │ ────────────────→│                  │            │
│     │                    │                  │                  │            │
│     │                    │ 7. 토큰 발급     │                  │            │
│     │                    │    - access_token                  │            │
│     │                    │    - refresh_token                 │            │
│     │                    │    - expires_in                    │            │
│     │                    │ ←────────────────│                  │            │
│     │                    │                  │                  │            │
│     │                    │ 8. API 호출                        │            │
│     │                    │    Authorization: Bearer {token}   │            │
│     │                    │ ─────────────────────────────────→ │            │
│     │                    │                  │                  │            │
│     │                    │ 9. 데이터 응답   │                  │            │
│     │                    │ ←───────────────────────────────── │            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.4 OAuth 2.0의 토큰들

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 2.0 토큰 종류                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1️⃣ Authorization Code (인가 코드)                                         │
│  ─────────────────────────────────                                          │
│     수명: 매우 짧음 (보통 1-10분)                                           │
│     용도: Access Token과 교환하기 위한 일회용 코드                          │
│     전달: URL 파라미터 (노출 위험 → 짧은 수명으로 보완)                     │
│                                                                             │
│  2️⃣ Access Token (접근 토큰) ⭐                                            │
│  ───────────────────────────────                                            │
│     수명: 짧음 (보통 5분 ~ 1시간)                                           │
│     용도: API 호출 시 인증 수단                                             │
│     형식: JWT (JSON Web Token) 또는 Opaque Token                           │
│     사용: Authorization 헤더에 포함                                         │
│                                                                             │
│     ┌────────────────────────────────────────────────────────────┐         │
│     │ Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...     │         │
│     └────────────────────────────────────────────────────────────┘         │
│                                                                             │
│  3️⃣ Refresh Token (갱신 토큰)                                              │
│  ──────────────────────────────                                             │
│     수명: 김 (보통 7일 ~ 30일, 또는 더 길게)                                │
│     용도: Access Token 만료 시 재발급                                       │
│     저장: 안전하게 저장 필요 (HttpOnly Cookie, Secure Storage)             │
│                                                                             │
│  4️⃣ ID Token (OIDC에서 추가)                                               │
│  ─────────────────────────────                                              │
│     용도: 사용자 정보 (이름, 이메일 등) 포함                                │
│     형식: JWT (서명 포함)                                                   │
│     검증: 클라이언트에서 서명 검증으로 위변조 확인                          │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  💡 왜 Access Token은 수명이 짧을까?                                        │
│                                                                             │
│  Access Token:                                                              │
│  - 매 API 요청마다 네트워크로 전송됨                                        │
│  - 노출 위험 높음                                                           │
│  - 짧은 수명 → 탈취되어도 피해 최소화                                       │
│                                                                             │
│  Refresh Token:                                                             │
│  - 토큰 갱신 시에만 사용                                                    │
│  - 서버에만 전달 (더 안전)                                                  │
│  - 긴 수명 → 사용자가 자주 로그인 안 해도 됨                               │
│                                                                             │
│  Access Token 만료 시 흐름:                                                 │
│  ┌────────────────────────────────────────────────────────────────┐        │
│  │ Client: "Access Token 만료됐네, Refresh Token으로 갱신하자"   │        │
│  │ Client → Auth Server: POST /token (refresh_token=xxx)         │        │
│  │ Auth Server → Client: 새 access_token + (새 refresh_token)    │        │
│  │ → 사용자는 다시 로그인할 필요 없음!                            │        │
│  └────────────────────────────────────────────────────────────────┘        │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.5 OAuth 2.0 Grant Types

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 2.0 Grant Types (인가 방식)                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1️⃣ Authorization Code (권장 ⭐)                                           │
│  ─────────────────────────────────                                          │
│     사용처: 서버 사이드 웹 앱                                               │
│     특징: 가장 안전, client_secret을 서버에서 안전하게 보관                │
│     흐름: 앞서 설명한 전체 흐름                                             │
│                                                                             │
│  2️⃣ Authorization Code + PKCE (모바일/SPA 권장 ⭐)                         │
│  ───────────────────────────────────────────────────                        │
│     사용처: SPA, 모바일 앱 (client_secret 저장 불가한 환경)                 │
│     특징: code_verifier/code_challenge로 Authorization Code 탈취 방지      │
│     PKCE: Proof Key for Code Exchange                                       │
│                                                                             │
│     흐름:                                                                   │
│     1. Client가 code_verifier(랜덤 문자열) 생성                            │
│     2. code_challenge = SHA256(code_verifier) 계산                         │
│     3. 인가 요청 시 code_challenge 전송                                    │
│     4. 토큰 교환 시 code_verifier 전송                                     │
│     5. Auth Server가 검증: SHA256(code_verifier) == code_challenge?        │
│                                                                             │
│  3️⃣ Client Credentials                                                     │
│  ─────────────────────────                                                  │
│     사용처: 서버 간 통신 (사용자 개입 없이)                                 │
│     예시: 백엔드 Service A → 백엔드 Service B                               │
│                                                                             │
│     흐름:                                                                   │
│     ┌─────────────────────────────────────────────────────────────┐        │
│     │ POST /token                                                 │        │
│     │   grant_type=client_credentials                             │        │
│     │   client_id=service-a                                       │        │
│     │   client_secret=xxx                                         │        │
│     │                                                             │        │
│     │ → Access Token 발급 (사용자 정보 없음)                      │        │
│     └─────────────────────────────────────────────────────────────┘        │
│                                                                             │
│  4️⃣ Resource Owner Password (비권장 ⚠️)                                    │
│  ─────────────────────────────────────────                                  │
│     사용처: 레거시 시스템, 매우 신뢰할 수 있는 자사 앱                      │
│     위험: 클라이언트가 사용자 비밀번호를 직접 받음                          │
│     현재: OAuth 2.1에서 제거 예정                                          │
│                                                                             │
│  5️⃣ Implicit (폐기됨 ❌)                                                   │
│  ─────────────────────────                                                  │
│     과거: SPA용으로 사용됨 (Access Token이 URL fragment로 직접 전달)       │
│     문제: Access Token이 URL에 노출, 보안 취약                             │
│     현재: PKCE로 완전히 대체됨, OAuth 2.1에서 제거                          │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3. OpenID Connect (OIDC)

3.1 OAuth 2.0의 한계

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 2.0만으로는 부족한 점                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  🔴 OAuth 2.0의 원래 목적:                                                  │
│     "인가(Authorization)" = 무엇을 할 수 있는가?                            │
│     "사용자가 이 앱에 자신의 데이터 접근을 허용한다"                         │
│                                                                             │
│  🔴 OAuth 2.0이 정의하지 않은 것:                                           │
│     "인증(Authentication)" = 누구인가?                                      │
│     - 사용자가 누구인지 확인하는 표준 방법 없음                             │
│     - Access Token은 "누구"에 대한 정보를 포함하지 않을 수 있음             │
│     - 각 서비스마다 다른 방식으로 사용자 정보 제공                          │
│                                                                             │
│  각 서비스의 사용자 정보 API (다 다름):                                     │
│  ┌─────────────────────────────────────────────────────────────────┐       │
│  │ Google:   GET /userinfo     → {"email": "...", "name": "..."}  │       │
│  │ Facebook: GET /me           → {"id": "...", "first_name": ...} │       │
│  │ Twitter:  GET /account/verify_credentials → {"screen_name":...}│       │
│  │ GitHub:   GET /user         → {"login": "...", "email": ...}   │       │
│  │                                                                 │       │
│  │ → API 경로도 다르고, 응답 형식도 다름                           │       │
│  │ → 여러 소셜 로그인 통합하려면 각각 다르게 처리해야 함           │       │
│  └─────────────────────────────────────────────────────────────────┘       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.2 OIDC = OAuth 2.0 + 인증 레이어

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OpenID Connect (OIDC)                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  📅 탄생: 2014년                                                            │
│  📚 정의: OAuth 2.0 위에 구축된 인증(Authentication) 레이어                 │
│                                                                             │
│  구조:                                                                      │
│  ┌─────────────────────────────────────────────────────────────────┐       │
│  │                                                                 │       │
│  │              ┌───────────────────────────────┐                  │       │
│  │              │    OpenID Connect (OIDC)      │   ← 인증 레이어  │       │
│  │              │   - ID Token                  │                  │       │
│  │              │   - UserInfo Endpoint         │                  │       │
│  │              │   - 표준 Claims               │                  │       │
│  │              │   - Discovery                 │                  │       │
│  │              └───────────────────────────────┘                  │       │
│  │                           │                                     │       │
│  │              ┌────────────┴────────────┐                        │       │
│  │              │      OAuth 2.0          │      ← 인가 프레임워크 │       │
│  │              │   - Access Token        │                        │       │
│  │              │   - Refresh Token       │                        │       │
│  │              │   - Grant Types         │                        │       │
│  │              └─────────────────────────┘                        │       │
│  │                                                                 │       │
│  └─────────────────────────────────────────────────────────────────┘       │
│                                                                             │
│  OIDC가 추가한 것:                                                          │
│                                                                             │
│  1️⃣ ID Token (JWT)                                                         │
│     - 사용자 정보를 담은 서명된 토큰                                        │
│     - 클라이언트에서 서명 검증으로 위변조 확인                              │
│     - 표준 Claims: sub, name, email, picture, iat, exp 등                  │
│                                                                             │
│  2️⃣ UserInfo Endpoint (표준화)                                             │
│     - GET /userinfo → 모든 OIDC 제공자가 동일한 경로와 형식                 │
│     - 통합이 쉬워짐                                                        │
│                                                                             │
│  3️⃣ Discovery (자동 설정 조회)                                             │
│     - GET /.well-known/openid-configuration                                │
│     - 인가 서버의 모든 설정 정보 자동 조회                                  │
│     - 토큰 엔드포인트, 지원 스코프, 키 정보 등                             │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.3 ID Token 상세

┌─────────────────────────────────────────────────────────────────────────────┐
│                    ID Token (JWT) 구조                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ID Token = Header.Payload.Signature (Base64로 인코딩)                      │
│                                                                             │
│  예시:                                                                      │
│  eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.                                     │
│  eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IktpbSIsImVtYWlsIjoiLi4uIn0.          │
│  SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c                               │
│                                                                             │
│  디코딩 결과:                                                               │
│                                                                             │
│  Header:                                                                   │
│  {                                                                         │
│    "alg": "RS256",     // 서명 알고리즘                                    │
│    "typ": "JWT",                                                           │
│    "kid": "key-id-123" // 서명 검증에 사용할 키 ID                         │
│  }                                                                         │
│                                                                             │
│  Payload (Claims):                                                         │
│  {                                                                         │
│    // 필수 Claims                                                          │
│    "iss": "https://keycloak.example.com/realms/cck",  // 발급자            │
│    "sub": "user-uuid-12345",                          // 사용자 식별자     │
│    "aud": "accio-frontend",                           // 대상 클라이언트   │
│    "exp": 1706860800,                                 // 만료 시간         │
│    "iat": 1706857200,                                 // 발급 시간         │
│                                                                             │
│    // 선택 Claims (OIDC 표준)                                              │
│    "name": "Kim",                                                          │
│    "email": "kim@example.com",                                             │
│    "email_verified": true,                                                 │
│    "picture": "https://...",                                               │
│                                                                             │
│    // Keycloak 커스텀 Claims                                               │
│    "realm_access": {                                                       │
│      "roles": ["admin", "user"]                                            │
│    }                                                                       │
│  }                                                                         │
│                                                                             │
│  Signature:                                                                │
│  → 위 내용이 변조되지 않았음을 증명                                         │
│  → 공개키로 검증 가능                                                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4. Keycloak이란?

4.1 Keycloak 개요

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak 소개                                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  📚 정의:                                                                   │
│     오픈소스 IAM(Identity and Access Management) 솔루션                     │
│     = OAuth 2.0 + OIDC + SAML + 사용자 관리 + SSO를 모두 제공              │
│                                                                             │
│  📅 역사:                                                                   │
│     - 2014년: Red Hat (JBoss) 팀에서 개발 시작                             │
│     - 현재: CNCF(Cloud Native Computing Foundation) 인큐베이팅 프로젝트    │
│     - 기반: Java (WildFly → Quarkus로 전환 중)                             │
│                                                                             │
│  🎯 핵심 기능:                                                              │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────┐       │
│  │                                                                 │       │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │       │
│  │  │ 사용자 관리  │  │    SSO       │  │  Social     │          │       │
│  │  │ - 가입/로그인│  │ - 한 번     │  │  Login      │          │       │
│  │  │ - 비밀번호   │  │   로그인으로│  │ - Google    │          │       │
│  │  │   정책      │  │   모든 앱   │  │ - Facebook  │          │       │
│  │  │ - 프로필    │  │   접근      │  │ - Kakao     │          │       │
│  │  └──────────────┘  └──────────────┘  │ - GitHub    │          │       │
│  │                                      └──────────────┘          │       │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │       │
│  │  │ OAuth 2.0/  │  │  역할 기반   │  │ LDAP/AD     │          │       │
│  │  │ OIDC 서버   │  │  접근 제어   │  │ 연동        │          │       │
│  │  │ - 토큰 발급 │  │ - Role      │  │ - 기업 계정 │          │       │
│  │  │ - 토큰 검증 │  │ - Permission│  │   통합      │          │       │
│  │  └──────────────┘  └──────────────┘  └──────────────┘          │       │
│  │                                                                 │       │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │       │
│  │  │ 2FA/MFA     │  │  세션 관리   │  │  이벤트     │          │       │
│  │  │ - OTP       │  │ - 세션 목록 │  │  로깅       │          │       │
│  │  │ - WebAuthn  │  │ - 강제 로그 │  │ - 감사 추적 │          │       │
│  │  │             │  │   아웃      │  │             │          │       │
│  │  └──────────────┘  └──────────────┘  └──────────────┘          │       │
│  │                                                                 │       │
│  └─────────────────────────────────────────────────────────────────┘       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.2 Keycloak 핵심 개념

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak 핵심 용어                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1️⃣ Realm (영역)                                                           │
│  ─────────────────                                                          │
│     - 독립된 인증 공간 (테넌트 개념)                                        │
│     - 각 Realm은 별도의 사용자, 클라이언트, 역할, 설정 보유                 │
│     - 멀티테넌트 구현에 활용                                                │
│     - 기본 Realm: "master" (관리용)                                        │
│                                                                             │
│     ┌─────────────────────────────────────────────────────────────┐        │
│     │ Keycloak Server                                             │        │
│     │                                                             │        │
│     │  ┌───────────────┐  ┌───────────────┐  ┌───────────────┐    │        │
│     │  │ Realm: master │  │ Realm: cck    │  │ Realm: demo   │    │        │
│     │  │ (관리자용)    │  │ - Users: 100  │  │ - Users: 10   │    │        │
│     │  │               │  │ - Clients: 5  │  │ - Clients: 2  │    │        │
│     │  └───────────────┘  └───────────────┘  └───────────────┘    │        │
│     │                                                             │        │
│     └─────────────────────────────────────────────────────────────┘        │
│                                                                             │
│  2️⃣ Client (클라이언트)                                                    │
│  ────────────────────────                                                   │
│     - Keycloak에 등록된 애플리케이션                                        │
│     - 각 앱(웹, 모바일, 백엔드)마다 별도 Client 등록                        │
│     - 설정: Client ID, Client Secret, Redirect URIs, 허용 Grant Type       │
│                                                                             │
│     Client Types:                                                          │
│     ┌─────────────────────────────────────────────────────────────┐        │
│     │ Confidential │ client_secret 안전하게 보관 가능 (백엔드)   │        │
│     │ Public       │ client_secret 노출됨 (SPA, 모바일)          │        │
│     │ Bearer-only  │ 토큰 검증만 함 (API 서버)                   │        │
│     └─────────────────────────────────────────────────────────────┘        │
│                                                                             │
│  3️⃣ User (사용자)                                                          │
│  ──────────────────                                                         │
│     - 로그인 가능한 사용자 계정                                             │
│     - 속성: username, email, firstName, lastName, attributes              │
│     - Federation: LDAP/Active Directory와 연동 가능                        │
│     - Identity Provider: 외부 IdP로 로그인 (Google, Kakao 등)              │
│                                                                             │
│  4️⃣ Role (역할)                                                            │
│  ────────────────                                                           │
│     Realm Role:                                                            │
│     - 전체 영역에서 유효                                                   │
│     - 예: admin, manager, user                                             │
│                                                                             │
│     Client Role:                                                           │
│     - 특정 클라이언트에서만 유효                                           │
│     - 예: accio-admin, accio-viewer                                        │
│                                                                             │
│  5️⃣ Group (그룹)                                                           │
│  ─────────────────                                                          │
│     - 사용자를 묶어서 역할을 일괄 부여                                      │
│     - 계층 구조 가능                                                        │
│     - 예: /company/engineering/backend → backend 팀원에게 특정 역할 부여   │
│                                                                             │
│  6️⃣ Identity Provider (외부 IdP)                                           │
│  ────────────────────────────────                                           │
│     - 외부 인증 제공자와 연동                                               │
│     - Social: Google, Facebook, Kakao, Naver, GitHub                       │
│     - Enterprise: SAML, OIDC 기반 기업 IdP                                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.3 Keycloak 아키텍처

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak을 포함한 시스템 아키텍처                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│                            ┌─────────────────┐                              │
│                            │    사용자       │                              │
│                            └────────┬────────┘                              │
│                                     │                                       │
│          ┌──────────────────────────┼──────────────────────────┐            │
│          │                          │                          │            │
│          ▼                          ▼                          ▼            │
│  ┌───────────────┐       ┌───────────────┐       ┌───────────────┐         │
│  │   Accio Web   │       │   Jump App    │       │   Admin       │         │
│  │   (React)     │       │   (Mobile)    │       │   (Angular)   │         │
│  └───────┬───────┘       └───────┬───────┘       └───────┬───────┘         │
│          │                       │                       │                  │
│          │         1. 로그인 필요 시 리다이렉트          │                  │
│          │                       │                       │                  │
│          └───────────────────────┼───────────────────────┘                  │
│                                  │                                          │
│                                  ▼                                          │
│                    ┌─────────────────────────────┐                          │
│                    │        Keycloak             │                          │
│                    │   (Authorization Server)   │                          │
│                    │                             │                          │
│                    │  - 로그인 UI 제공          │                          │
│                    │  - 사용자 인증              │                          │
│                    │  - Token 발급              │                          │
│                    │  - SSO 세션 관리           │                          │
│                    │  - Social Login 처리       │                          │
│                    │                             │                          │
│                    └──────────────┬──────────────┘                          │
│                                   │                                         │
│                      2. Token 발급 후 앱으로 리다이렉트                     │
│                                   │                                         │
│          ┌────────────────────────┼────────────────────────┐                │
│          │                        │                        │                │
│          ▼                        ▼                        ▼                │
│  ┌───────────────┐       ┌───────────────┐       ┌───────────────┐         │
│  │   Accio Web   │       │   Jump App    │       │   Admin       │         │
│  │  (Token 저장) │       │  (Token 저장) │       │  (Token 저장) │         │
│  └───────┬───────┘       └───────┬───────┘       └───────┬───────┘         │
│          │                       │                       │                  │
│          │         3. API 호출 시 Authorization 헤더에 Token 포함          │
│          │                       │                       │                  │
│          └───────────────────────┼───────────────────────┘                  │
│                                  │                                          │
│                                  ▼                                          │
│                    ┌─────────────────────────────┐                          │
│                    │       API Gateway           │                          │
│                    │   (또는 각 서비스에서)      │                          │
│                    │   - Token 검증             │                          │
│                    │   - Role/Permission 확인   │                          │
│                    └──────────────┬──────────────┘                          │
│                                   │                                         │
│          ┌────────────────────────┼────────────────────────┐                │
│          │                        │                        │                │
│          ▼                        ▼                        ▼                │
│  ┌───────────────┐       ┌───────────────┐       ┌───────────────┐         │
│  │ Accio Backend │       │ Jump Backend  │       │ Mothership    │         │
│  │   Service     │       │   Service     │       │   Service     │         │
│  └───────────────┘       └───────────────┘       └───────────────┘         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.4 Keycloak의 장점

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak 사용의 7가지 장점                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  1️⃣ 인증 로직 중앙화                                                       │
│  ─────────────────────                                                      │
│     Without Keycloak:                                                      │
│     - 각 서비스마다 로그인 로직 구현 (중복 코드)                            │
│     - 비밀번호 정책, 암호화 각각 관리 (불일치 위험)                         │
│     - 보안 취약점 발생 가능성 증가                                          │
│                                                                             │
│     With Keycloak:                                                         │
│     - 인증은 Keycloak만 담당 (단일 책임)                                   │
│     - 서비스는 토큰 검증만 하면 됨                                         │
│     - 보안 업데이트 한 곳에서 관리                                         │
│                                                                             │
│  2️⃣ SSO (Single Sign-On)                                                   │
│  ────────────────────────                                                   │
│     - 한 번 로그인으로 모든 연결된 앱 접근                                  │
│     - Keycloak 세션이 유효한 동안 자동 로그인                               │
│     - 사용자 경험 대폭 향상                                                 │
│     - Single Logout도 지원 (모든 앱에서 로그아웃)                          │
│                                                                             │
│  3️⃣ Social Login 쉬운 연동                                                 │
│  ────────────────────────────                                               │
│     - Google, Facebook, Kakao 등 클릭 몇 번으로 설정                        │
│     - 직접 OAuth 연동 코드 작성 불필요                                      │
│     - Identity Brokering: 외부 IdP를 내부 사용자로 매핑                    │
│                                                                             │
│  4️⃣ 기업 디렉토리 연동                                                     │
│  ─────────────────────────                                                  │
│     - LDAP, Active Directory 연동                                          │
│     - 기존 사내 계정 그대로 사용                                            │
│     - User Federation: 외부 저장소의 사용자 동기화                         │
│                                                                             │
│  5️⃣ 세밀한 권한 관리                                                       │
│  ─────────────────────                                                      │
│     - Role-Based Access Control (RBAC)                                     │
│     - Fine-grained Authorization: 리소스/스코프 단위 권한                   │
│     - Policy 기반 접근 제어                                                │
│                                                                             │
│  6️⃣ 관리자 콘솔 제공                                                       │
│  ─────────────────────                                                      │
│     - 웹 UI로 사용자/클라이언트/역할 관리                                   │
│     - 직접 관리 기능 구현 불필요                                            │
│     - 이벤트 로그 조회, 세션 관리, 통계 대시보드                            │
│                                                                             │
│  7️⃣ 오픈소스 & 무료                                                        │
│  ─────────────────────                                                      │
│     - Apache 2.0 라이선스                                                  │
│     - 상용 지원 필요 시: Red Hat SSO                                       │
│     - 활발한 커뮤니티, 풍부한 문서                                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5. 언제 Keycloak을 도입해야 하나?

5.1 도입이 적합한 상황

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak 도입 권장 상황                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ✅ 다음 상황에서 Keycloak 도입 권장:                                       │
│                                                                             │
│  1. 마이크로서비스 아키텍처                                                 │
│     └── 여러 서비스가 공통 인증 필요                                        │
│     └── API Gateway + Keycloak 조합                                        │
│     └── 서비스 간 토큰 기반 인증                                           │
│                                                                             │
│  2. 여러 애플리케이션 운영                                                  │
│     └── 웹, 모바일, 데스크톱 앱 동시 운영                                   │
│     └── SSO로 사용자 경험 통일                                             │
│     └── 일관된 인증 정책 적용                                              │
│                                                                             │
│  3. B2B 플랫폼 / 멀티테넌트                                                │
│     └── 고객사별 다른 인증 정책 필요                                        │
│     └── Realm으로 테넌트 분리                                              │
│     └── 각 고객사의 IdP 연동                                               │
│                                                                             │
│  4. Social Login 필요                                                      │
│     └── Google, Kakao, Naver 로그인                                        │
│     └── 직접 구현 대비 80% 시간 절약                                       │
│                                                                             │
│  5. 기업 시스템 연동                                                        │
│     └── LDAP/Active Directory 사용 중                                      │
│     └── SAML 기반 기존 SSO와 연동                                          │
│                                                                             │
│  6. 보안 요구사항 높음                                                      │
│     └── 2FA/MFA 필요                                                       │
│     └── 비밀번호 정책 강제                                                  │
│     └── 세션 관리, 감사 로그 필수                                          │
│                                                                             │
│  7. 직접 운영 능력/의지 있음                                                │
│     └── DevOps 팀 있음                                                     │
│     └── 인프라 직접 관리 가능                                              │
│     └── 커스터마이징 필요                                                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5.2 도입이 과할 수 있는 상황

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Keycloak이 과할 수 있는 상황                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ⚠️ 다음 상황에서는 다른 옵션 고려:                                        │
│                                                                             │
│  1. 단일 모놀리식 앱                                                        │
│     └── 서비스가 하나뿐이면 세션 기반 인증으로 충분                         │
│     └── Spring Security + Session만으로 해결 가능                          │
│                                                                             │
│  2. 소규모 팀 / 초기 스타트업                                               │
│     └── Keycloak 운영 오버헤드가 큼                                        │
│     └── 관리형 서비스가 더 효율적일 수 있음                                │
│                                                                             │
│  3. 직접 운영 원하지 않음                                                   │
│     └── Auth0, Firebase Auth 등 SaaS 고려                                  │
│     └── 운영 부담 없음                                                     │
│                                                                             │
│  4. 빠른 MVP 개발이 우선                                                    │
│     └── 나중에 필요할 때 도입                                              │
│     └── 처음부터 완벽한 인증 불필요                                        │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  💡 대안 비교:                                                              │
│                                                                             │
│  ┌───────────────────────────────────────────────────────────────────┐     │
│  │ 솔루션       │ 특징                                │ 비용          │     │
│  ├───────────────────────────────────────────────────────────────────┤     │
│  │ Keycloak    │ 셀프호스팅, 완전한 커스터마이징     │ 무료 (운영비) │     │
│  │ Auth0       │ SaaS, 빠른 도입, 관리 불필요       │ 유료          │     │
│  │ Firebase    │ Google 생태계, 간편함              │ 프리티어 있음 │     │
│  │ AWS Cognito │ AWS 통합, 서버리스                 │ 사용량 기반   │     │
│  │ Okta        │ 엔터프라이즈급, 풍부한 기능        │ 고가          │     │
│  │ Supabase    │ Firebase 대안, PostgreSQL 기반     │ 프리티어 있음 │     │
│  └───────────────────────────────────────────────────────────────────┘     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

6. 실제 구현 예시

6.1 Spring Boot + Keycloak (Resource Server)

// build.gradle.kts
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
    implementation("org.springframework.boot:spring-boot-starter-security")
}

// application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://keycloak.example.com/realms/cck
          # 또는 직접 JWK Set URI 지정
          # jwk-set-uri: https://keycloak.example.com/realms/cck/protocol/openid-connect/certs

// SecurityConfig.kt
@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http
            .authorizeHttpRequests { auth ->
                auth
                    .requestMatchers("/public/**").permitAll()
                    .requestMatchers("/admin/**").hasRole("ADMIN")
                    .requestMatchers("/api/**").authenticated()
                    .anyRequest().authenticated()
            }
            .oauth2ResourceServer { oauth2 ->
                oauth2.jwt { jwt ->
                    jwt.jwtAuthenticationConverter(keycloakJwtConverter())
                }
            }
        return http.build()
    }

    @Bean
    fun keycloakJwtConverter(): Converter<Jwt, AbstractAuthenticationToken> {
        return KeycloakJwtAuthenticationConverter()
    }
}

// KeycloakJwtAuthenticationConverter.kt
// Keycloak의 realm_access.roles를 Spring Security 권한으로 변환
class KeycloakJwtAuthenticationConverter : Converter<Jwt, AbstractAuthenticationToken> {

    override fun convert(jwt: Jwt): AbstractAuthenticationToken {
        val authorities = extractRoles(jwt)
        return JwtAuthenticationToken(jwt, authorities, jwt.getClaimAsString("preferred_username"))
    }

    private fun extractRoles(jwt: Jwt): Collection<GrantedAuthority> {
        val realmAccess = jwt.getClaimAsMap("realm_access") ?: return emptyList()
        val roles = realmAccess["roles"] as? List<*> ?: return emptyList()

        return roles
            .filterIsInstance<String>()
            .map { SimpleGrantedAuthority("ROLE_${it.uppercase()}") }
    }
}

// Controller에서 사용
@RestController
@RequestMapping("/api/user")
class UserController {

    @GetMapping("/me")
    fun getCurrentUser(authentication: JwtAuthenticationToken): UserInfo {
        val jwt = authentication.token
        return UserInfo(
            id = jwt.getClaimAsString("sub"),
            username = jwt.getClaimAsString("preferred_username"),
            email = jwt.getClaimAsString("email"),
            roles = authentication.authorities.map { it.authority }
        )
    }
}

6.2 React + Keycloak 연동

// keycloak.ts
import Keycloak from 'keycloak-js';

const keycloak = new Keycloak({
    url: 'https://keycloak.example.com',
    realm: 'cck',
    clientId: 'accio-frontend'
});

export default keycloak;

// App.tsx
import { ReactKeycloakProvider } from '@react-keycloak/web';
import keycloak from './keycloak';

function App() {
    return (
        <ReactKeycloakProvider
            authClient={keycloak}
            initOptions=
            onEvent={(event, error) => {
                console.log('Keycloak event:', event, error);
            }}
        >
            <RouterProvider router={router} />
        </ReactKeycloakProvider>
    );
}

// useAuth.ts - 커스텀 훅
import { useKeycloak } from '@react-keycloak/web';

export function useAuth() {
    const { keycloak, initialized } = useKeycloak();

    return {
        isAuthenticated: keycloak.authenticated,
        user: keycloak.tokenParsed,
        token: keycloak.token,
        login: () => keycloak.login(),
        logout: () => keycloak.logout({ redirectUri: window.location.origin }),
        hasRole: (role: string) => keycloak.hasRealmRole(role),
        initialized
    };
}

// api.ts - API 호출 시 토큰 포함
import keycloak from './keycloak';

const api = {
    async fetch(url: string, options: RequestInit = {}) {
        // 토큰 만료 임박 시 자동 갱신
        if (keycloak.isTokenExpired(30)) {
            await keycloak.updateToken(30);
        }

        return fetch(url, {
            ...options,
            headers: {
                ...options.headers,
                'Authorization': `Bearer ${keycloak.token}`,
                'Content-Type': 'application/json'
            }
        });
    }
};

export default api;

// ProtectedRoute.tsx
import { useAuth } from './useAuth';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children, requiredRole }: Props) {
    const { isAuthenticated, hasRole, initialized } = useAuth();

    if (!initialized) {
        return <div>Loading...</div>;
    }

    if (!isAuthenticated) {
        return <Navigate to="/login" />;
    }

    if (requiredRole && !hasRole(requiredRole)) {
        return <Navigate to="/unauthorized" />;
    }

    return children;
}

7. 요약

┌─────────────────────────────────────────────────────────────────────────────┐
│                    OAuth 2.0 & Keycloak 핵심 요약                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  📚 OAuth 2.0                                                               │
│  ─────────────                                                              │
│     - 2012년 표준화된 인가(Authorization) 프레임워크                        │
│     - "비밀번호 공유 없이 제3자 앱에 제한된 권한 부여"                      │
│     - 4가지 역할: Resource Owner, Client, Auth Server, Resource Server    │
│     - 토큰: Authorization Code, Access Token, Refresh Token               │
│     - 권장 Grant Type: Authorization Code + PKCE                           │
│                                                                             │
│  📚 OpenID Connect (OIDC)                                                   │
│  ─────────────────────────                                                  │
│     - OAuth 2.0 위의 인증(Authentication) 레이어                           │
│     - ID Token (JWT)으로 "사용자가 누구인지" 확인                          │
│     - 표준화된 UserInfo Endpoint                                           │
│     - Discovery로 자동 설정 조회                                           │
│                                                                             │
│  📚 Keycloak                                                                │
│  ─────────────                                                              │
│     - Red Hat의 오픈소스 IAM 솔루션                                        │
│     - OAuth 2.0 + OIDC + SAML + SSO + 사용자 관리 통합                     │
│     - 핵심 개념: Realm, Client, User, Role, Group                          │
│                                                                             │
│     장점:                                                                   │
│     ✓ 인증 로직 중앙화                                                     │
│     ✓ SSO (Single Sign-On)                                                 │
│     ✓ Social Login 쉬운 연동                                               │
│     ✓ LDAP/AD 연동                                                         │
│     ✓ 세밀한 권한 관리 (RBAC)                                              │
│     ✓ 관리자 콘솔 제공                                                     │
│     ✓ 무료 & 오픈소스                                                      │
│                                                                             │
│  🎯 도입 시점                                                               │
│  ──────────────                                                             │
│     ✅ 마이크로서비스 아키텍처                                              │
│     ✅ 여러 앱에서 공통 인증/SSO 필요                                       │
│     ✅ Social Login / 기업 디렉토리 연동                                    │
│     ✅ 직접 운영 능력 및 의지 있음                                          │
│                                                                             │
│     ⚠️ 단일 앱, 소규모 팀 → 세션 기반 또는 SaaS 고려                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

참고 자료

  • OAuth 2.0 RFC 6749: https://datatracker.ietf.org/doc/html/rfc6749
  • OpenID Connect 명세: https://openid.net/specs/openid-connect-core-1_0.html
  • Keycloak 공식 문서: https://www.keycloak.org/documentation
  • Spring Security OAuth2: https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html

관련 키워드

OAuth 2.0, OpenID Connect, OIDC, Keycloak, SSO, Single Sign-On, JWT, Access Token, Refresh Token, ID Token, Authorization Code, PKCE, Grant Type, Realm, Client, IAM, 인증, 인가, Identity Provider, RBAC