- Published on
Keycloak vs Authentik vs Zitadel vs Ory Hydra vs Auth0 vs WorkOS vs Okta — 2026 SSO / OIDC / SAML / OAuth 2.1 / FAPI 2.0 / FedCM 심층 비교
- Authors

- Name
- Youngju Kim
- @fjvbn20031
콜드 오픈 — 2026년 5월, SSO가 다시 첨예해진 이유
2026년 1분기, IETF가 OAuth 2.1을 공식 RFC로 등록했다. 같은 분기에 OpenID Foundation은 FAPI 2.0 Security Profile을 Final로 확정했다. 5월 Google Chrome 안정 채널은 FedCM(Federated Credential Management) API를 데스크톱·모바일 전체에서 기본 활성화했다. Microsoft Edge는 한 달 뒤 동일한 인터페이스를 따라간다. 같은 시기, NIST는 SP 800-63-4를 발효시키고 패스키(passkey)와 동기화 가능한 인증자(syncable authenticator)를 AAL2의 기본 권고로 명시했다.
이 모든 것이 한 분기에 동시에 일어났다. 그래서 2026년의 SSO는 "Okta 살까, 직접 띄울까"라는 5년 전 질문과 완전히 다르다. 지금은 (1) 어떤 프로토콜 스택을 채택할지, (2) 브라우저가 중개하는 페더레이션을 받아들일지, (3) 패스키 전용 사용자와 SAML만 받는 엔터프라이즈 고객을 동시에 어떻게 처리할지가 핵심이다.
등장 인물 정리 — 누가 어떤 자리에 있는가
이 글에서 비교하는 일곱 가지 IDP는 동일한 시장에서 싸우지 않는다. 비슷한 단어를 쓰지만 실제 포지션은 다르다.
| 제품 | 라이선스 | 호스팅 | 강점 | 약점 |
|---|---|---|---|---|
| Keycloak | Apache 2.0 | 자가호스팅 | Quarkus 기반 빠른 시작, 풍부한 어댑터 | 멀티테넌시 빈약, UI 한계 |
| Authentik | MIT | 자가호스팅 | Outpost 아키텍처, 모던 UI | 작은 커뮤니티 |
| Zitadel | Apache 2.0 | 자가호스팅 / SaaS | 멀티테넌시, 이벤트 소싱 | 운영 진입장벽 |
| Ory Hydra | Apache 2.0 | 헤드리스 | OAuth 2.1 적합성, 가볍다 | UI 없음, 직접 구현 |
| Auth0 | 상용 | SaaS | DX, Rules/Actions | Okta 인수 후 가격 인상 |
| WorkOS | 상용 | SaaS | B2B SSO/SCIM 전용 | 소비자 사용 사례 약함 |
| Okta | 상용 | SaaS | 엔터프라이즈 표준 | 가격, 인시던트 이력 |
이 표는 출발점일 뿐이다. 실제 결정은 사용자 수, 멀티테넌시 필요 여부, 규제 영역, 그리고 가장 중요하게는 운영팀의 역량에 달려 있다.
OAuth 2.1과 OAuth 2.0의 차이를 다시 짚기
OAuth 2.1은 2026년 1월 RFC 9700번대로 굳어졌다. 핵심 변경 사항은 새로운 발명이 아니라, 지난 10년의 베스트 프랙티스를 강제로 끌어 올린 것이다.
- Implicit grant는 폐기되었다. 응답 모드
token을 더 이상 지원하지 않는 IDP가 늘고 있다. - Resource Owner Password Credentials grant도 폐기. Keycloak 25는 기본 비활성화이며, 활성화하려면 명시적 플래그가 필요하다.
- PKCE가 모든 confidential client에서도 필수가 되었다. 더 이상 "public client에서만"이라는 예외가 없다.
- Refresh token rotation이 권고에서 사실상의 표준으로 격상되었다.
- Redirect URI 매칭은 exact match만 허용된다. wildcard prefix는 금지.
OAuth 2.1을 실제 시스템에 도입할 때 가장 큰 갈등은 모바일 앱과 SPA에서 발생한다. Implicit가 사라졌으니 Authorization Code + PKCE를 무조건 써야 하는데, 모바일 앱은 backend-for-frontend(BFF) 패턴이나 native secure storage(iOS Keychain, Android Keystore)를 통한 refresh token 보관 전략을 함께 결정해야 한다.
DPoP와 sender-constrained 토큰 — 토큰 도난이 더 이상 치명적이지 않은 이유
DPoP(Demonstration of Proof-of-Possession, RFC 9449)는 OAuth bearer token의 가장 큰 약점인 "도난당하면 끝"을 해결한다. 토큰을 클라이언트의 개인키로 서명한 JWT(DPoP proof)와 함께 제시해야 한다. Resource server는 토큰의 cnf.jkt 클레임과 proof의 공개키를 비교한다.
DPoP가 일반화되기 전, 가장 흔한 공격은 다음과 같았다.
- XSS로 SPA의 access token을 탈취
- 공격자가 직접 API 서버에 그 토큰으로 호출
- 서버는 토큰만 검증, 통과
DPoP는 단계 3을 깨뜨린다. 토큰만으로는 부족하고, 토큰과 일치하는 개인키도 필요하다. WebCrypto의 non-extractable 키와 함께 쓰면 키 자체를 SPA에서 빼내기가 매우 어렵다.
2026년 현재 DPoP를 기본 지원하는 IDP는 Keycloak 25, Zitadel, Ory Hydra이다. Auth0는 enterprise 플랜에서 베타, Okta는 일부 워크플로우에서만 지원한다. Authentik은 2025년 12월 릴리스에서 안정화되었다.
FAPI 2.0 — 금융 API의 새로운 바닥
FAPI(Financial-grade API) 1.0 Advanced는 2018년부터 영국 Open Banking에서 사용되었다. FAPI 2.0은 그 경험을 정리해서 단순화했다.
핵심 차이점은 다음과 같다.
- FAPI 1.0의 응답 서명 요구사항(JARM 등)이 단순화되었다.
- mTLS와 DPoP 중 어느 쪽이든 sender-constrained 토큰만 인정한다.
- PAR(Pushed Authorization Request, RFC 9126)이 필수다. 인가 요청을 백채널로 먼저 푸시한 뒤 짧은
request_uri만 프론트엔드에 전달한다. - RAR(Rich Authorization Requests, RFC 9396)이 표준화되어 "이체 1000만원 승인" 같은 트랜잭션 단위 권한을 표현할 수 있다.
한국 마이데이터, 일본 전자정부, EU PSD3 모두 FAPI 2.0을 사실상 의무화하는 방향으로 움직였다. Keycloak은 FAPI 2.0 적합성 테스트를 2025년 통과했고, Authelia는 미준수, Auth0는 별도 추가 모듈로 지원한다.
Keycloak 25 — Quarkus 전환 이후의 풍경
Keycloak은 18 버전부터 WildFly에서 Quarkus로 전환했고, 25에 와서 그 결정의 효과가 안정화되었다. 콜드 스타트는 1초대로 떨어졌고, 메모리 풋프린트는 절반 수준이다. 컨테이너 이미지가 가벼워서 Kubernetes 환경에서 HPA로 쉽게 확장된다.
25의 주요 변화는 다음과 같다.
- Account Console v2가 React 기반으로 재작성되어 패스키 등록 UX가 개선되었다.
- Admin UI도 마찬가지로 React로 재작성, REST API는 안정.
- Organizations 기능이 GA로 승격. 진정한 멀티테넌시는 아니지만, 단일 realm 안에서 조직 단위로 사용자를 묶을 수 있다.
- WebAuthn passwordless 등록이 기본 인증 흐름에 통합되었다.
# Keycloak 25 deployment in Kubernetes (Helm values 발췌)
keycloak:
image:
repository: quay.io/keycloak/keycloak
tag: "25.0.6"
args:
- "start"
- "--optimized"
- "--db=postgres"
- "--hostname=auth.example.com"
- "--proxy-headers=xforwarded"
- "--health-enabled=true"
- "--metrics-enabled=true"
env:
- name: KC_FEATURES
value: "fapi,dpop,par,organization,passkeys"
- name: KC_LOG_LEVEL
value: "INFO"
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
memory: 2Gi
Keycloak이 잘 못하는 일도 명확하다. 진정한 multi-tenant SaaS를 만들 때, 각 realm을 분리해서 운영하면 인스턴스가 폭발한다. 한 인스턴스에서 수백 realm을 운영하면 cold start가 다시 느려진다. 이 지점에서 Zitadel을 검토하게 된다.
Authentik — Outpost가 만드는 다른 방식의 IDP
Authentik은 "프록시 인증" 사용 사례에서 출발해 풀 IDP로 진화한 프로젝트다. Outpost라는 개념이 핵심이다. Outpost는 별도의 작은 프로세스로, IDP 코어와는 분리된다. 각 Outpost는 특정 프로토콜(LDAP, RADIUS, Proxy)을 담당한다.
Outpost 모델의 장점은 다음과 같다.
- LDAP 서버가 다운돼도 OIDC 흐름은 영향을 받지 않는다.
- Outpost는 Kubernetes operator로 자동 배포된다.
- 보안 경계가 명확하다. Outpost는 IDP DB에 직접 접근하지 않고 API만 호출한다.
Authentik의 Flow 개념도 흥미롭다. 인증/등록/패스워드 리셋을 모두 동일한 "Flow" 추상화로 표현한다. Stage(MFA, password, prompt, captcha 등)를 조합해서 임의의 인증 절차를 만든다.
# authentik Flow 예시: passkey 우선, 폴백 TOTP
metadata:
name: default-authentication-flow
spec:
designation: authentication
stages:
- name: identification
type: identification
user_fields: [email, username]
- name: webauthn-passkey
type: authenticator_validate
device_classes: [webauthn]
not_configured_action: skip
- name: password-fallback
type: password
backends: [authentik_core.auth.InbuiltBackend]
- name: totp-mfa
type: authenticator_validate
device_classes: [totp]
not_configured_action: configure
Authentik의 약점은 커뮤니티 규모와 엔터프라이즈 지원 옵션이다. 회사 BeryJu가 상용 라이선스를 판매하지만, Okta 수준의 SLA를 기대하기는 어렵다.
Zitadel — 멀티테넌시를 정면돌파한 설계
Zitadel은 스위스 회사가 만든 IDP로, 처음부터 멀티테넌트 SaaS를 위해 설계되었다. 다른 IDP와 가장 다른 점은 이벤트 소싱(Event Sourcing) + CQRS를 코어 아키텍처로 채택했다는 사실이다.
모든 상태 변경은 이벤트로 저장된다. 사용자 생성, 패스워드 변경, 권한 부여, 토큰 발급 — 전부 append-only event log에 기록된다. 현재 상태는 projection(materialized view)으로 만든다. 이 설계의 결과:
- 모든 변경 이력이 영구 보존된다. 감사(audit) 요건을 충족하기 쉽다.
- Read 모델을 다양하게 만들 수 있다. PostgreSQL projection을 ClickHouse로 옮기는 등.
- 사용자를 "되돌리기"가 가능하다. 잘못된 권한 변경을 이벤트 단위로 추적해서 보정한다.
Zitadel의 멀티테넌시 모델은 Organization 단위다. 한 인스턴스에 수천 Organization을 운영할 수 있고, 각 Organization은 자체 IdP 설정, 자체 도메인, 자체 브랜딩을 가진다. Keycloak realm을 1000개 운영하는 것과 Zitadel Organization 1000개를 운영하는 것은 운영 비용이 한 자릿수 차이가 난다.
단점은 운영 진입장벽이다. Cockroach DB 호환 PostgreSQL이 필요하고, 이벤트 로그가 빠르게 커지므로 보관 정책을 명확히 해야 한다.
Ory Hydra — 헤드리스 OAuth 2.1 서버
Ory Hydra는 OIDC/OAuth 2.1 사양 적합성만을 목표로 한다. UI가 없다. 사용자 DB가 없다. 로그인 페이지가 없다. 그 모든 것은 "consent app"이라는 별도 애플리케이션이 책임진다.
Hydra의 인증 흐름:
- 클라이언트가
/oauth2/auth로 사용자를 보낸다. - Hydra는 사용자를 자기 자신이 아니라, 별도 호스팅된 login app으로 리다이렉트한다.
- Login app은 사용자 인증을 수행하고 Hydra에 "이 사용자를 받아라"라고 통보한다.
- Hydra가 consent 단계로 리다이렉트한다.
- 같은 패턴 반복 후, Hydra가 토큰을 발급한다.
// Ory Hydra login app 예시 (Express)
import express from 'express'
import { Configuration, OAuth2Api } from '@ory/client'
const hydraAdmin = new OAuth2Api(
new Configuration({ basePath: process.env.HYDRA_ADMIN_URL })
)
const app = express()
app.get('/login', async (req, res) => {
const challenge = req.query.login_challenge as string
const { data: loginRequest } = await hydraAdmin.getOAuth2LoginRequest({
loginChallenge: challenge,
})
// 자체 인증 로직(패스키, 패스워드, MFA 등)
// ...
const subject = 'user-uuid-1234'
const { data: accept } = await hydraAdmin.acceptOAuth2LoginRequest({
loginChallenge: challenge,
acceptOAuth2LoginRequest: {
subject,
remember: true,
remember_for: 3600,
},
})
res.redirect(accept.redirect_to)
})
Hydra가 잘 맞는 사례는 회사가 이미 사용자 DB와 로그인 UI를 가지고 있고, OIDC/OAuth만 추가하려는 경우다. Hydra가 잘 안 맞는 경우는 "그냥 IDP가 필요한" 평균적인 사례. 그때는 Keycloak이나 Zitadel이 훨씬 빠르다.
Auth0의 위치 — Okta 인수 이후 4년
Okta가 2021년 Auth0를 인수했다. 4년이 지난 2026년 시점에서 두 제품은 명확히 다른 시장을 노린다.
- Auth0 = 개발자 친화적, B2C, 빠른 통합, Rules → Actions 마이그레이션 완료.
- Okta Workforce = 엔터프라이즈 SSO, Universal Directory, Lifecycle Management.
- Okta Customer Identity Cloud = Auth0의 리브랜딩 + 엔터프라이즈 영업.
Auth0의 가격은 2024-2025년 사이 큰 폭으로 올랐다. 무료 티어가 축소되고, MAU 기반 가격이 가팔라졌다. 100만 MAU 기준 월 비용이 2021년 대비 약 2.5배 인상되었다는 공개된 사례가 여러 건 있다. 이것이 자가호스팅 IDP로의 마이그레이션이 다시 활발해진 이유다.
Auth0의 강점은 여전히 DX다. SDK 품질, 문서, 지원 — 이 부분은 자가호스팅 옵션이 따라잡지 못한다. 빠른 PoC와 초기 단계 스타트업에는 여전히 합리적이다.
WorkOS — B2B만 정면으로 노린 제품
WorkOS는 "엔터프라이즈 고객이 SSO를 요구할 때, 빠르게 대응할 수 있게" 만들어진 SaaS다. 핵심 가치는 다음과 같다.
- SAML, OIDC, SCIM을 통일된 API로 제공.
- "Directory Sync" — Okta, Azure AD, Google Workspace, BambooHR 등 30+ 디렉터리를 동일 모델로 흡수.
- B2C는 안 한다. 소비자 인증, 회원가입, 비밀번호 재설정은 다른 솔루션에 맡긴다.
WorkOS가 잘 맞는 시나리오:
- 우리 제품이 자체 인증을 가지고 있다.
- 이제 엔터프라이즈 고객이 "Okta SSO 필요해요"라고 한다.
- SAML 메타데이터 교환을 IDP마다 다르게 처리하기 싫다.
이 시나리오에서 WorkOS는 한 endpoint로 통합한다. Auth0도 비슷한 기능이 있지만, WorkOS는 이것만 한다는 점에서 가격과 단순성에서 우위를 가진다.
Okta의 현재 — 보안 사고 이후의 신뢰 회복
Okta는 2022년 Lapsus$ 사고, 2023년 HAR 파일 유출 사고를 겪었다. 2026년 현재는 보안 거버넌스를 대대적으로 재정비했고, OIE(Okta Identity Engine)로 전 고객을 이주시켰다. 그럼에도 일부 엔터프라이즈 고객은 "single vendor risk"를 이유로 보조 IDP를 운영한다.
Okta의 강점은 변하지 않았다.
- 7000+ pre-built integration (Okta Integration Network).
- Lifecycle Management — HR 시스템 변경이 곧바로 권한 변경으로 이어진다.
- Adaptive MFA — 디바이스, 위치, 행동 기반 위험 평가.
약점은 가격, lock-in, 그리고 Okta가 다운되면 회사 전체가 다운된다는 의존성이다. 후자에 대한 대비책으로 "Okta 다운 시 우회 로그인 경로"를 런북에 적어 두는 회사가 늘었다.
FedCM — 브라우저가 중개하는 페더레이션
FedCM은 ID 페더레이션을 third-party cookie 없이 가능하게 만드는 브라우저 API다. 기존의 "Google로 로그인" 버튼은 third-party iframe과 redirect를 사용했다. third-party cookie가 사라지는 세상에서 이 흐름은 깨진다.
FedCM의 작동 방식:
- RP(Relying Party)가
navigator.credentials.get({ identity: { providers: [...] } })를 호출한다. - 브라우저가 IdP의
manifest.json을 fetch한다. - 브라우저가 시스템 UI로 "이 사이트가 X.com 계정으로 로그인하길 원합니다" 다이얼로그를 띄운다.
- 사용자 동의 후, 브라우저가 IdP에서 ID token을 받아 RP에 전달한다.
# FedCM IdP manifest 예시
GET /.well-known/web-identity HTTP/1.1
Host: idp.example.com
HTTP/1.1 200 OK
Content-Type: application/json
{
"accounts_endpoint": "/fedcm/accounts",
"client_metadata_endpoint": "/fedcm/client_metadata",
"id_assertion_endpoint": "/fedcm/assertion",
"login_url": "/login",
"branding": {
"background_color": "#0f172a",
"color": "#ffffff",
"icons": [{ "url": "https://idp.example.com/icon.png", "size": 64 }]
}
}
FedCM은 Chrome 132부터 안정. Edge 132에서 동일하게 활성화. Safari는 2026년 5월 현재 "고려 중" 단계. Keycloak 25는 FedCM IdP endpoint를 실험적으로 지원한다. Zitadel은 정식 지원 발표 중. Auth0와 Okta는 RP 측 SDK를 우선 제공한다.
패스키와 WebAuthn — 더 이상 "신기술"이 아니다
2026년 패스키 채택률은 임계점을 넘었다. Microsoft 계정의 약 30%가 패스키를 사용하고, Apple iCloud Keychain은 사실상 모든 iOS 사용자에게 패스키 동기화를 활성화했다. Google 계정도 비슷한 비율이다.
IDP 관점에서 패스키 구현 시 주의점:
- Resident key(discoverable credential)와 non-resident key의 차이를 이해해야 한다. 패스키는 resident key다.
- Cross-device authentication(CDA, hybrid transport)을 지원해야 데스크톱에서 모바일 패스키 사용이 가능하다.
- Attestation 정책을 정해야 한다. 엔터프라이즈는 보통 packed attestation을 요구한다.
- Account recovery 흐름이 패스키 손실 시 빈약하면 사용자가 좌초된다.
Keycloak 25는 패스키 등록을 기본 인증 흐름에 통합. Authentik은 webauthn stage가 안정 GA. Zitadel은 처음부터 WebAuthn first-class. Ory는 Hydra 자체에는 없고 Kratos에서 처리. Auth0는 "Universal Login"에 패스키 옵션 제공.
SCIM과 JIT 프로비저닝
엔터프라이즈 고객은 거의 항상 SCIM(System for Cross-domain Identity Management)을 요구한다. HR 시스템에서 사용자가 추가되면 자동으로 우리 서비스의 사용자가 만들어지고, HR에서 비활성화되면 우리 서비스도 즉시 잠긴다.
SCIM 2.0 표준 endpoint:
/scim/v2/Users— 사용자 CRUD/scim/v2/Groups— 그룹 CRUD/scim/v2/Bulk— 대량 변경/scim/v2/ServiceProviderConfig— 우리 서비스가 지원하는 SCIM 옵션 광고
SCIM의 함정은 표준의 모호함이다. userName과 emails[].value의 매핑, group membership의 동기화 방향(IDP push vs SP pull), soft delete vs hard delete — 이 모든 부분에서 IDP 구현이 다르다. WorkOS는 이 차이를 흡수해서 단일 API로 노출한다. 그게 WorkOS의 가치다.
JIT 프로비저닝은 SCIM의 가벼운 대체재다. 사용자가 처음 로그인할 때, IDP가 보낸 SAML/OIDC assertion의 클레임을 기반으로 사용자 레코드를 생성한다. 빠르지만 즉시 비활성화(deprovisioning)는 불가능하다는 단점이 있다.
Identity broker 패턴 — 한국 PASS와 일본 JPKI 통합
한국 마이데이터, 본인인증 서비스는 PASS, 카카오, 네이버, 토스 같은 본인확인기관(IDP가 아니라 본인확인기관임에 유의)을 통한다. 일본은 マイナンバーカード 기반 JPKI(공적 개인 인증 서비스)로 정부 인증을 제공한다.
자체 서비스가 이런 인증을 직접 통합하면 매번 다른 프로토콜, 다른 응답 형식, 다른 갱신 주기를 처리해야 한다. Identity broker 패턴은 IDP를 중간에 두고, 외부 IDP/본인확인기관 통합을 IDP가 책임지게 한다.
Keycloak의 Identity Provider 기능, Zitadel의 External IdP, Auth0의 Custom Connection이 이 패턴을 지원한다. 한국 환경에서는 다음과 같이 매핑한다.
- PASS API → IDP의 custom OIDC provider로 어댑팅
- 카카오 sync → IDP의 OAuth 2.0 provider로 등록
- 네이버 → IDP의 OAuth 2.0 provider
- 본인확인 (KISA 인증) → IDP의 custom SAML 또는 custom provider
JPKI는 더 복잡하다. PIN 입력, 카드 리더 연동, JPKI client app 호출이 필요하다. IDP는 보통 JPKI client와의 인터페이스만 표준화하고, 실제 카드 통신은 사용자 디바이스에서 일어난다.
B2B vs B2C — 같은 IDP로 둘 다 되나
B2C는 사용자가 자기 이메일로 가입하고, 자기 패스키로 로그인한다. 회사가 관리하지 않는다.
B2B는 사용자가 회사 이메일로 가입한다. 회사가 SSO를 운영하고, 사용자는 회사 IDP로 우리 서비스에 들어온다. 사용자 권한은 회사가 관리한다.
같은 IDP로 둘 다 처리하는 게 가능한가? 가능하지만 권장하지 않는다. 사용자 모델, 인증 흐름, 권한 모델이 너무 다르다. 현실의 패턴은 보통 이렇다.
- B2C는 Auth0/Cognito/자체 구현으로 시작.
- 첫 엔터프라이즈 고객이 SSO 요구. WorkOS를 추가해서 SAML 흡수.
- 사용자가 늘면서 자체 IDP(Keycloak/Zitadel)로 마이그레이션.
- 그 시점에 B2B와 B2C tenant를 분리.
이 진화 경로를 처음부터 예상하고 설계하면 마이그레이션 비용이 작다. 한 가지 IDP에 모든 것을 욱여넣다가 나중에 풀면 비용이 크다.
MFA의 진화 — SMS는 죽었고 패스키가 표준이 되었다
NIST SP 800-63-4가 SMS OTP를 AAL2의 권장 인증자에서 제외했다. SS7 공격, SIM swap 공격으로 SMS는 더 이상 안전하지 않다. 그럼에도 2026년 현재 많은 서비스가 SMS OTP를 쓴다. 이유는 단 하나, "사용자가 추가 앱을 깔기 싫어한다."
대안:
- 패스키 — 가장 안전. 디바이스 손실 시 회복이 문제.
- TOTP (Google Authenticator, Aegis) — 여전히 합리적인 MFA.
- Push notification (Authy, Duo) — phishing-resistant 모드와 함께 쓰면 안전.
- Hardware key (YubiKey) — 엔터프라이즈 표준, 분실 시 백업 키 필요.
IDP에서 MFA를 강제하는 정책은 risk-based이어야 한다. 모든 로그인에 MFA를 강요하면 사용자가 우회 경로(쿠키 영구 저장 등)를 만든다. "새 디바이스에서, 새 IP에서, 민감 작업 직전에" MFA를 요구하는 것이 합리적이다.
세션 관리와 토큰 폐기
OIDC의 어려운 부분 중 하나는 "사용자가 로그아웃했을 때, 모든 RP에서 동시에 로그아웃" — front-channel logout과 back-channel logout 사양이 있지만 구현이 불완전한 IDP가 많다.
토큰 폐기(revocation)는 OAuth 2.1에서 더 중요해졌다. 시나리오:
- 사용자의 휴대폰이 도난당했다.
- 회사 IT가 IDP에서 사용자의 세션을 모두 종료한다.
- 발급된 access token이 만료될 때까지 (보통 5-60분) API 접근이 가능하다.
이 5-60분 갭을 줄이려면:
- Access token 수명을 짧게(5분 이하) 한다. 트래픽 부담이 늘지만 안전하다.
- Token introspection (RFC 7662)을 모든 API 호출에서 한다. 비싸지만 즉각 폐기 가능.
- 또는 Token revocation list를 캐시한다. Sliding cache로 새 폐기 정보를 빠르게 반영.
Keycloak, Zitadel, Auth0 모두 introspection endpoint를 제공한다. Ory Hydra는 더 가볍게 자체 검증과 introspection을 혼합한다.
자가호스팅 IDP의 진짜 비용
"오픈소스 IDP는 공짜"라는 말은 라이선스만 본 것이다. 실제 비용은 다음과 같이 쌓인다.
- HA 운영: PostgreSQL primary/replica, IDP 인스턴스 3개 이상, load balancer, certificate rotation.
- 백업/복구 훈련.
- 보안 패치 추적. CVE 발생 시 24시간 내 패치 적용 책임.
- 24/7 on-call. Okta가 다운된 것과 우리 IDP가 다운된 것의 사용자 영향은 같다.
- 컴플라이언스 감사. SOC 2 type II를 받는 회사는 IDP도 감사 대상이다.
100만 MAU 기준 대략 추산:
- Auth0/Okta CIC: 월 $20,000-30,000.
- 자가호스팅 Keycloak 또는 Zitadel: 인프라 월 $1,000-3,000 + 풀타임 엔지니어 0.5-1명.
회사 규모와 자체 운영 역량에 따라 손익분기점이 다르다. 사용자 30만 미만이면 SaaS가 거의 항상 싸다. 200만 이상이면 자가호스팅이 거의 항상 싸다.
공격면 — 토큰 도난, refresh rotation, OAuth phishing
2025-2026년에 보고된 OAuth 관련 공격 트렌드:
- OAuth phishing — 가짜 클라이언트 ID로 진짜 IDP의 consent 화면을 거쳐 사용자가 권한을 부여하게 만드는 공격. Google과 Microsoft가 application verification 강화로 대응.
- Refresh token replay — refresh rotation이 없으면 한 번 훔친 refresh token으로 무한 재발급 가능. RFC 6749 4.1.4에 따라 rotation은 SHOULD이지만, 2026년에는 MUST 가까운 위상.
- Token theft via malicious extension — 브라우저 확장이 SPA 메모리에서 토큰을 읽어낸다. DPoP + non-extractable WebCrypto 키로 mitigate.
- Open redirector chain — RP의 허술한 redirect_uri 검증으로 토큰을 외부 도메인에 흘리는 공격. OAuth 2.1의 exact match 요구가 이걸 줄인다.
IDP를 운영한다는 것은 이런 공격을 IDP 레벨에서 차단하고, RP 개발자에게는 안전한 SDK만 노출한다는 의미다.
엔터프라이즈 SSO 조달 현실 — SAML은 죽지 않는다
스타트업 엔지니어는 "왜 아직도 SAML?"이라고 묻는다. 답: 엔터프라이즈가 SAML을 요구하기 때문이다.
엔터프라이즈 IT 부서의 시선에서:
- SAML은 20년의 운영 경험이 있다. 디버깅 도구, 알려진 함정, 표준 메타데이터 교환 절차가 모두 정착되어 있다.
- OIDC는 비교적 신생이고, 매번 IDP마다 다르게 구현한다.
- 보안 검토 위원회는 SAML을 "안전한 기본값"으로 본다.
그래서 우리 서비스가 엔터프라이즈 고객을 받으려면 OIDC와 SAML 둘 다 지원해야 한다. WorkOS, Auth0, Okta CIC, Keycloak, Zitadel 모두 둘 다 지원하지만, 구현 품질과 메타데이터 교환 자동화 정도가 다르다.
조달 프로세스에서 자주 마주치는 요구:
- SAML metadata URL 제공
- AuthnRequest 서명 옵션
- SLO(Single Logout) 지원
- IdP-initiated SSO 지원 (보안 위험이 있지만 엔터프라이즈는 자주 요구)
- 그룹 매핑 (Active Directory group → 서비스 role)
한국 환경 추가 컨텍스트 — PASS, KISA, 본인인증
한국에서 SaaS를 운영할 때 마주치는 인증 요구:
- 본인인증 — 주민등록번호 기반 본인확인. KISA 인증을 받은 본인확인기관(NICE, KCB, SCI)을 통해야 한다.
- PASS — 통신 3사가 운영하는 통합 인증 앱. 본인인증의 주요 채널.
- 마이데이터 — 금융 데이터 이동성. FAPI 1.0 Advanced 기반.
- 전자서명법 개정 (2020) 이후 공인인증서 폐지, 다양한 사설인증 인정.
자체 IDP에 본인인증을 통합할 때 주의:
- 본인확인 결과는 IDP의 사용자 프로필에 저장. 단, 주민등록번호는 hash해서 보관(법적 요구).
- CI(연계정보)와 DI(중복확인정보)의 의미가 다르다. CI는 서비스 간 동일인 식별, DI는 한 서비스 내 중복가입 방지.
- 본인인증 결과의 유효기간(보통 6개월-1년)을 정책으로 관리.
일본 환경 추가 컨텍스트 — JPKI, マイナンバー, OpenID Connect for Identity Assurance
일본은 マイナンバーカード(My Number Card) 기반 JPKI가 정부 인증의 표준이다. JPKI는 카드 안에 두 가지 인증서를 담는다. 서명용 인증서와 이용자증명용 인증서.
서비스 통합 시:
- 「JPKI 利用者証明用電子証明書」으로 OIDC 로그인 가능 (PIN 4자리).
- 「JPKI 署名用電子証明書」은 본격적인 전자서명에 사용 (PIN 6-16자).
- マイナンバー(개인번호) 자체는 절대 IDP에 저장하지 않는다 (마이넘버법 위반).
OpenID Connect for Identity Assurance (OIDC4IDA)는 일본 정부가 표준화에 참여하고 있는 사양으로, IDP가 사용자의 신원 확인 수준(Level of Assurance)을 RP에 전달한다. JPKI 통합 IDP는 OIDC4IDA의 verified_claims를 통해 "이 사용자는 マイナンバーカード로 본인확인을 마쳤다"를 신뢰성 있게 전달한다.
# OIDC4IDA 응답 예시 발췌
{
"sub": "user-uuid-9876",
"verified_claims": {
"verification": {
"trust_framework": "jp_aml",
"assurance_level": "high",
"evidence": [{
"type": "electronic_record",
"check_details": [{
"check_method": "kbv",
"organization": "JPKI",
"txn": "tx-2026-05-001"
}]
}]
},
"claims": {
"given_name": "Taro",
"family_name": "Yamada",
"birthdate": "1985-04-12"
}
}
}
마이그레이션 시나리오 — Auth0에서 Keycloak으로
실제로 자주 보는 시나리오: Auth0에서 시작했는데 가격 인상 후 자가호스팅으로 이동.
마이그레이션 체크리스트:
- 사용자 데이터 export — Auth0 Management API로 사용자 + 메타데이터 export. 패스워드 hash는 bcrypt면 그대로 import 가능, 그렇지 않으면 사용자에게 reset 메일 발송.
- Application/Client 매핑 — Auth0 Application = Keycloak Client. redirect URI, allowed origins, grant types를 1:1로 옮긴다.
- Rules/Actions 마이그레이션 — Auth0의 JavaScript 후크는 Keycloak의 Authenticator SPI 또는 Event Listener SPI로 재구현해야 한다. 자동 마이그레이션 도구는 없다.
- Connection (소셜 IDP) — Google, GitHub, Apple 등의 OAuth client ID/secret를 Keycloak Identity Provider로 재등록.
- 다운타임 없는 cut-over — DNS 변경 전에 양쪽이 동일 사용자 set을 가지도록 동기화. 보통 incremental migration 또는 dual-write 기간을 둔다.
마이그레이션 기간 동안 가장 자주 깨지는 것: 비밀번호 hash 알고리즘 불일치, 그리고 user_id 형식 변경에 따른 외부 시스템 참조 깨짐.
결론 — 2026년의 의사결정 트리
긴 글이지만, 의사결정은 단순화할 수 있다.
- 사용자가 30만 미만이고 운영 인력이 부족하다 → Auth0 또는 Okta CIC.
- B2B만, 엔터프라이즈 SSO/SCIM이 핵심 → WorkOS.
- 자가호스팅 가능, 단일 테넌트로 충분 → Keycloak 25.
- 자가호스팅 필요, 진정한 멀티테넌트 SaaS → Zitadel.
- 자체 사용자 DB가 있고 OIDC만 추가 → Ory Hydra.
- 프록시 인증, 가벼운 사용 사례 → Authentik.
- 거대 엔터프라이즈, 7000개 통합 필요 → Okta Workforce.
선택 후에는 다음을 반드시 검증한다.
- OAuth 2.1 적합성 (PKCE 강제, implicit 거부, refresh rotation).
- DPoP 또는 mTLS 지원.
- FAPI 2.0 필요한 산업이면 적합성 인증서 확인.
- FedCM IdP endpoint 지원 로드맵.
- 패스키 등록/사용/복구 흐름의 완성도.
- SCIM 2.0 양방향 지원.
- 한국/일본 지역 통합(PASS, JPKI) 가능 여부.
2026년의 SSO는 더 이상 "로그인 박스"가 아니다. 사용자 신원의 전체 라이프사이클, 디바이스 바인딩, 규제 적합성, 브라우저 페더레이션을 동시에 다루는 인프라 컴포넌트다. 잘 고른 IDP는 5년을 간다. 잘못 고른 IDP는 마이그레이션으로 1년 분의 엔지니어링을 소모시킨다.
References
- https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/
- https://datatracker.ietf.org/doc/html/rfc9449
- https://datatracker.ietf.org/doc/html/rfc9126
- https://datatracker.ietf.org/doc/html/rfc9396
- https://openid.net/specs/fapi-2_0-security-profile.html
- https://openid.net/specs/openid-connect-4-identity-assurance-1_0.html
- https://www.keycloak.org/
- https://www.keycloak.org/2024/06/keycloak-2500-released
- https://goauthentik.io/
- https://zitadel.com/
- https://www.ory.sh/hydra/
- https://auth0.com/docs
- https://workos.com/docs
- https://help.okta.com/oie/en-us/content/topics/identity-engine/oie-index.htm
- https://developers.google.com/privacy-sandbox/cookies/fedcm
- https://fidoalliance.org/passkeys/
- https://www.w3.org/TR/webauthn-3/
- https://pages.nist.gov/800-63-4/
- https://www.kisa.or.kr/
- https://www.jpki.go.jp/