OAuth 2.0·OIDC·SAML 차이: 인가·로그인·SSO를 구분하기
1장 개념과 보호 목표#
OAuth 2.0은 다른 애플리케이션에 제한된 접근 권한을 위임하는 인가 프레임워크입니다. OIDC는 OAuth 위에 신원 확인을 위한 규칙을 추가하고, SAML은 서명된 assertion을 주고받는 연합 인증 방식으로 기업 SSO 등에 활용됩니다.
2장 원리와 구분#
Access Token은 자원 접근에, ID Token은 클라이언트의 인증 결과 확인에 사용합니다. JWT는 토큰 형식 중 하나이며 OAuth 토큰이 모두 JWT인 것은 아닙니다. 인가 코드 흐름에서는 PKCE와 정확한 redirect URI 검증을 적용하고, state 및 OIDC nonce를 용도에 맞게 검증합니다. 공개 클라이언트에 client secret을 넣는 것으로 비밀을 안전하게 보관할 수는 없습니다.
3장 비교와 판단 기준#
| 구분 | 목적 | 주요 검증 |
|---|---|---|
| OAuth 2.0 | 접근 권한 위임 | 코드·PKCE·redirect URI·scope |
| OIDC | 인증 결과 전달 | ID Token 서명·issuer·audience·nonce |
| SAML | 신원·속성 전달 | assertion 서명·수신자·시간·재사용 |
| JWT | 서명 등을 담는 토큰 형식 | 허용 알고리즘·키·클레임 |
4장 OAuth의 네 참여자를 그려 본다#
사용자는 자원에 대한 권한을 갖고 클라이언트는 제한된 권한을 요청합니다. 인가 서버는 인증·동의·정책에 따라 토큰을 발급하고 자원 서버는 접근 토큰을 확인해 API를 제공합니다. 로그인과 데이터 접근이 서로 다른 참여자와 검증을 거칠 수 있습니다.
flowchart LR
U["사용자"] --> C["클라이언트"]
C --> A["인가 서버"]
A --> T["접근 토큰"]
T --> C
C --> R["자원 서버의 토큰·업무 권한 검증"]5장 권한 위임과 로그인 결과를 구분한다#
OAuth는 권한 위임의 프레임워크입니다. 인증 서버가 로그인 화면을 제공할 수 있어도 OAuth만으로 클라이언트의 신원 확인 규약이 모두 정해지는 것은 아닙니다. OIDC는 ID Token과 관련 규약으로 인증 결과를 전달합니다. 사용자의 프로필과 API 권한도 같은 정보가 아닙니다.
토큰의 목적을 API 계약에 명시해야 합니다. ID Token을 자원 서버에 보내 모든 API를 허용하거나 다른 서비스용 접근 토큰을 받는 오류를 피합니다.
6장 인가 코드는 토큰 그 자체가 아니다#
코드는 정해진 교환 절차를 거쳐 토큰을 얻는 값입니다. 유효기간·일회성·클라이언트·리다이렉트·PKCE 등의 조건으로 연결해야 합니다. 돌아온 코드가 있다는 사실만으로 사용자를 로그인시키면 요청 혼동과 가로채기 문제가 생길 수 있습니다.
인가 요청 시작과 요청 상태 저장
인증·인가 후 코드 수신
정해진 서버와 PKCE 조건으로 교환
ID Token 또는 접근 토큰을 목적에 맞게 검증
애플리케이션 세션과 업무 권한 연결7장 PKCE의 challenge와 verifier#
클라이언트는 요청의 verifier와 연결된 challenge를 인가 요청에 사용하고 교환 단계에서 verifier를 제시합니다. 코드를 얻은 다른 주체가 같은 조건으로 교환하기 어렵도록 연결하는 보호입니다. 지원하는 안전한 방식과 규약을 사용하고 verifier를 로그에 남기지 않습니다.
PKCE는 모든 토큰 노출·인가 오류를 해결하는 기능이 아닙니다. redirect URI의 정확한 검증, 요청·응답의 연결과 토큰 검증을 함께 적용합니다.
8장 state와 OIDC nonce의 다른 목적#
state는 시작한 요청과 돌아온 응답을 연결하고 CSRF 방어에 활용합니다. OIDC nonce는 인증 요청과 ID Token의 연결에 사용합니다. 서로 같은 옵션이라고 묶거나 하나를 넣었으니 나머지 검증이 필요 없다고 생각하지 않습니다. 구체적인 흐름과 라이브러리의 요구를 확인합니다.
발급·저장·만료·단일 사용과 실패 처리를 서버 정책에 맞춥니다. 여러 탭과 동시에 시작한 로그인도 서로의 요청 상태가 섞이지 않는지 시험합니다.
9장 redirect URI 검증#
인가 결과가 돌아갈 주소는 등록된 허용 조건을 정확하게 검증해야 합니다. 넓은 접두어·임의 서브도메인·중간 리다이렉트가 예상하지 않은 곳으로 코드를 보내는지 확인합니다. 운영과 개발 주소를 무제한 섞지 않습니다.
URL에 전달된 민감한 값은 로그·분석·리퍼러로 새어 나갈 수 있습니다. 교환을 마친 뒤의 화면 이동과 로깅 정책도 함께 확인해야 합니다.
10장 JWT 디코딩은 서명 검증이 아니다#
JWT의 내용을 읽을 수 있다는 사실은 신뢰할 클레임이라는 뜻이 아닙니다. 허용 알고리즘·키·서명·issuer·audience·만료 등을 검증한 뒤 목적에 맞게 사용합니다. 토큰이 제시한 임의의 키 위치나 알고리즘을 무조건 채택해서는 안 됩니다.
flowchart TB
T["받은 토큰"] --> F["형식과 허용 알고리즘"]
F --> S["신뢰한 키와 서명 검증"]
S --> C["발급자·대상·시간·필수 클레임"]
C --> P["API scope와 실제 자원 권한"]
P --> A["허용된 요청 실행"]11장 scope와 객체 권한의 관계#
orders.read 같은 scope가 있어도 모든 고객의 주문을 읽게 해서는 안 됩니다. 토큰의 허용 기능과 실제 자원의 조직·소유권을 결합해야 합니다. scope·역할·대상 API·현재 계정 상태를 어떤 위치에서 확인하는지 정합니다.
짧은 토큰 수명과 회수 요구도 연결합니다. 사용자 권한이 바뀌었는데 기존 토큰의 역할이 계속 유효한 상황을 시험해야 합니다.
12장 SAML assertion의 검증 경계#
SAML은 서명된 assertion으로 신원·속성을 전달하는 연합 인증 방식입니다. 서명한 요소와 실제 신원 판단에 사용한 요소가 같은지 확인해야 하며 서명 검증 성공만으로 전체 XML의 모든 내용을 신뢰하지 않습니다. 수신자·audience·시간·요청 연결과 재사용을 검증합니다.
| 확인 항목 | 중요한 질문 |
|---|---|
| 서명 | 신뢰한 발급자와 정확한 서명 대상인가? |
| 수신자·대상 | 이 서비스에 전달된 결과인가? |
| 요청 연결 | 내가 시작한 요청의 응답인가? |
| 시간·재사용 | 지금 유효하며 한 번만 처리되는가? |
13장 키 교체와 토큰 보관#
인증 서버의 키가 바뀔 때 검증 서비스의 캐시와 갱신이 제대로 동작하는지 시험합니다. 미지원 키를 만났을 때 무검증으로 받아들이지 않습니다. Access Token·ID Token·Refresh Token은 각각 필요한 보관과 수명을 정합니다.
브라우저·모바일·서버의 비밀 보관 능력이 다릅니다. 공개 클라이언트에 시크릿을 넣어 영원히 숨길 수 있다는 가정을 피하고 해당 클라이언트 종류에 맞는 흐름을 사용합니다.
14장 적용 사례와 운영 방법#
로그인 연동에서는 ID Token의 서명·issuer·audience·만료를 검증합니다. API 서버는 자신을 위한 접근 토큰과 scope·자원 권한을 확인합니다. SAML은 assertion의 서명, 수신자, audience와 유효시간을 확인하고 재사용과 잘못된 XML 서명 처리에 대비합니다.
15장 인가 코드와 OIDC 개요#
sequenceDiagram
participant U as 사용자
participant C as 클라이언트
participant A as 인증·인가 서버
participant R as API 서버
U->>C: 로그인 시작
C->>A: 인가 요청과 PKCE challenge
A->>U: 인증·동의
A-->>C: 인가 코드
C->>A: 코드·PKCE verifier 교환
A-->>C: Access Token과 ID Token
C->>C: ID Token 검증
C->>R: Access Token으로 요청
R->>R: 토큰·자원 권한 검증16장 토큰의 발급 대상과 사용 대상을 확인한다#
OAuth 흐름에는 권한을 가진 사용자, 클라이언트, 인가 서버, 자원 서버가 참여합니다. 클라이언트가 인가 코드를 토큰으로 교환하고 자원 서버가 접근 토큰을 검증합니다. ID Token은 로그인 결과를 클라이언트에 전달하는 OIDC의 토큰이므로 API 접근용 토큰과 발급 대상·검증 목적이 다릅니다.
서명이 맞는 JWT라도 issuer·audience·만료와 허용 알고리즘이 다르면 받아들이면 안 됩니다. 디코딩은 검증이 아닙니다. 토큰에 들어 있는 역할이 현재 업무 권한을 항상 반영하는지도 확인해야 합니다. 권한 회수와 토큰의 남은 수명을 연결하는 정책이 필요합니다.
17장 PKCE·state·nonce를 서로 대신하지 않기#
PKCE는 인가 코드 교환을 해당 요청의 verifier와 연결합니다. state는 요청과 돌아온 응답의 연결 및 CSRF 방어에 사용하며, OIDC nonce는 인증 요청과 ID Token을 연결하는 값입니다. 구체적인 흐름에서 각 값의 생성·저장·검증과 일회성을 구현해야 하며 같은 의미의 옵션으로 취급하지 않습니다.
SSO 장애를 줄이려면 인증 서버의 키 교체와 캐시 갱신도 시험합니다. SAML에서는 assertion의 서명 대상과 실제 사용한 XML 요소가 같은지, 수신자·시간·요청 연결·재사용 검증이 이뤄지는지 확인합니다. 새로 설계하는 OAuth 흐름은 RFC 9700의 보안 권고를 기준으로 검토합니다.
18장 적용 전 확인할 사항#
- 로그인 결과와 API 접근 토큰을 구분한다
- issuer·audience·만료와 키 교체를 검증한다
- 토큰을 로그·URL·브라우저 저장소에 노출하는 경로를 점검한다
19장 자주 묻는 질문#
ID Token으로 모든 API를 호출해도 되나요?#
ID Token은 클라이언트가 인증 결과를 확인하기 위한 토큰입니다. API는 자신을 대상으로 발급된 접근 토큰과 필요한 권한을 검증하도록 설계해야 합니다.
Access Token이 JWT가 아니면 검증할 수 없나요?#
불투명한 토큰도 사용할 수 있습니다. 자원 서버가 정해진 조회나 검증 절차로 유효성과 권한을 확인하면 되며 JWT 형식이 필수는 아닙니다.
클라이언트 시크릿을 모바일 앱에 넣으면 안전한가요?#
배포된 앱에서 비밀을 계속 숨긴다고 가정하기 어렵습니다. 공개 클라이언트에 맞는 흐름과 PKCE 등 해당 프로토콜의 보호 수단을 적용해야 합니다.