이 시리즈의 모든 글 보기 : oauth
용어
OAuth : 별다른 언급이 없으면, OAuth 2.0 을 가리킵니다.
OIDC : OpenId Connect 1.0 Core 최신 판을 의미합니다.
Authorization : "사용자의 허락"을 의미하는 경우 "승인"으로, "자원에 대한 접근 제어 절차"를 의미하는 경우 "인가"로 번역했습니다. 후자가 더 넓은 의미입니다.
OAuth 의 세부 사항에 관해 설명하기에 앞서, 인가/인증이 Http 통신에서 어떻게 처리되는 지에 관한 배경 지식이 약간 필요합니다.
현실의 담배 판매 방식의 비유를 통해 알아 보겠습니다.
인가 (Authorization)
인가는 제한된 자원에 접근할 자격이 있는 지 확인하는 절차로, 인가의 결과는 금지(Forbid)와 자원(Resource) 둘 중에 하나입니다.
담배는 성인에게만 허락된 제품입니다.
누군가 담배를 달라고 하면, "성인"이라는 자격을 증명해야 하는데, 자격을 확인할 수 없는 사람이 대뜸 담배를 달라고 하면, 점원은 아무나 살 수 없다는 답변(Unauthorized 401)과 함께 성인임을 증명할 수 있는 방법을 알려 줍니다.
Http 인증 프레임워크에서는 401 응답 중, WWW-AUTHENTICATION 헤더를 포함한 것을Challenge Response 라고 합니다. 이 헤더에 자격을 증명할 수 있는 방법에 관한 정보가 포함됩니다.
참고로, Asp.Net Core 에서 쿠키 인증을 할 때, Challenge Response 대신에 인증이 가능한 주소로 Redirect(302) 하도록 설정되는데, 이 302도 Challenge 라고 부릅니다. 다만, Http 의 Challenge 응답 규정과 무관한 방식입니다.
엄격한 보안이 요구되는 경우, 증명의 수단을 알려 주는 행위도 보안 위협이 되기 때문에, WWW-AUTHENTICATION 헤더가 없는 401을 응답하거나, Bad Request(400) 답변을 할 수도 있습니다.
현실의 점원은 보통, 성인 증명 방식으로, 신분증을 제시를 요구합니다.
이러한 점원의 요구에도 불구하고, 신분증은 제시하지 않은 채, 계속 담배를 달라고하는 손님은 여전히 "자격을 확인할 수 없는 사람"에 불과해서, 점원도 같은 안내를 반복할 수 밖에 없습니다.
구매자가 안내에 따라 신분증을 제시하면, 점원은 아래의 절차를 수행합니다.
- 신분증이 위조된 것은 아닌 지를 검증하고,
- 신분증의 사진과 제시자의 얼굴을 비교하여 신분증 대상자임을 확인하고
- 신분증의 출생년도를 확인하여 성인 자격인지 확인합니다.
신분증 확인이 끝난, 3 번 단계에서 미성년자로 판명되면, 판매할 수 없다(Forbidden, 403)고 말하거나, 성인인 경우 담배를 제공합니다.(200)
보안 목적 상 Forbidden 대신, Not Found(404) 라고 답할 수 있습니다.
인증 (Authentication)
위 단계에서 신분증 확인(1번 ~ 2번) 과정이 인증에 해당합니다.
인증은 신분 증명이 위조된 것은 아닌 지와 제시자가 정당한 소유자인지 확인하는 절차로,
**인증의 결과는 신분 정보(Identity, User Profile)**입니다.
1 번 단계에서, 제시된 신분증이 위조되었다면, 신분증이 잘 못되었다고 답변을 합니다(Bad Request)
2번 단계에서, 신분증 대상자가 아니라는 판단이 들면, 이 또한 신분증이 잘 못되었다고 말합니다(Bad Request).
위 두 단계 중 하나라도 실패하면, 3번 단계를 진행할 수 없습니다.
이는 인가는 인증을 바탕으로 수행됨을 의미합니다.
이제, OAuth에 관한 내용을 이어나가도록 하겠습니다.
권한 부여(Authorization Grant)
OAuth 의 핵심은 접근이 제한된 데이터에 대한 접근 권한(Authorization)을 제 3 자에게 부여(Grant)하는 절차를 규정하는 것인데, 그 절차는 대체로 아래와 같습니다.
사용자
가클라이언트
에게접근 권한을 부여
클라이언트
는부여 받았다는 증명
을승인 서버(Authorization Server)
에게 제출하고,접근 토큰(Access Token)
과 교환합니다.클라이언트
는 발급 받은접근 토큰
을자원 서버
에 제출하여 자원과 교환합니다.
OAuth 는 이 절차에 대한 구체적인 방법론 네 가지를 제시하고, 여기에 더해 추가로 확장할 수 있는 방법을 제시합니다.
- 승인 코드 부여 (Authorization Code Grant)
- 암묵적 부여 (Implicit Grant)
- 사용자 암호로 부여 (User Credentials Password Credentials Grant)
- 클라이언트 암호로 부여 (Client Credentials Grant)
여기에서, 가장 권고 되는 승인 코드 부여를 위한 흐름을 도식화하면 아래와 같습니다.
클라이언트가 웹 서버인 경우
웹 서버는 비공개 정보를 외부로부터 보호하는데 용이한 앱 형태입니다.
OAuth 에서는 이를 기밀 클라이언트(Confidential Client)라고 부릅니다.
기밀의 주 대상은 클라이언트 인증 정보와 접근 토큰으로, 이들을 자체적으로 저장하고 있어도 외부로 누출될 위험이 현저히 적습니다.
Authz code : Authorization Code(승인 코드)
위 절차는 두 번의 Http 세션(요청~응답)에 걸쳐 진행됩니다.
첫 번째 세션
사용자 : 요청(Http Request) → 클라이언트
승인 요청 단계 (Authorization Request)
클라이언트 : Redirect → 승인 엔드 포인트
승인 엔드 포인트: 응답(Http Response) { 동의 화면 } → 사용자
두 번째 세션
승인 요청 단계 계속
사용자 : 동의(Http Request) → 승인 엔드 포인트
승인 엔드 포인트 : Redirect { 승인 코드 } → 클라이언트
토큰 요청 단계(Token Request)
클라이언트 : Fetch { 승인 코드 } → 토큰 엔드 포인트
토큰 엔드 포인트 : 승인 코드 검증 후 Fetch 응답 { 접근 토큰 } → 클라이언트
자원 요청 단계(Resource Request)
클라이언트 : Fetch { 접근 토큰 } → 자원 서버
자원 서버 : 접근 코드 검증 후 Fetch 응답 { 사용자 데이터 } → 클라이언트
클라이언트 : 응답(Http Response) { 사용자 데이터 } → 사용자
위 과정 중에, 자원 서버는 승인 서버(의 토큰 엔드 포인트)가 발급한 접근 토큰을 검증합니다. 이는 두 서버는 접근 토큰 검증에 필요한 비밀 키를 공유할 수 있을 만큼 깊은 신뢰 관계에 있음을 의미합니다.
현실적으로, 두 서버는 같은 주체(회사)가 제공하는 다른 서비스인 경우가 대부분입니다.
예를 들어, 구글의 자원 서버에서 자원을 얻기 위한 접근 토큰의 경우, 구글의 승인 서버가 발행하는 것이죠.
참고로, 클라이언트가 네이티브 앱인 경우는 같은 절차에, 시스템 브라우저와 OS가 개입됩니다.
클라이언트가 Native 앱 인 경우
Native 앱의 특징은 사용자의 로컬 머신에서 구동된다는 것입니다.
이는 앱의 코드, 앱이 저장한 데이터가 사용자에게 노출될 확률이 매우 높습니다.
OAuth 에서는 이러한 클라이언트를 공개 클라이언트(Public Client) 라고 부릅니다.
공개 클라이언트는 어떤 수단으로도 기밀 정보를 보호할 수 없다는 특징이 있습니다.
네이티브 앱에는 Web View와 같이 브라우저와 유사한 User Agent 컴포넌트를 가진 경우도 포함됩니다. 이는 OAuth의 네이티브 앱 처리와 관련한 권고 규정(RFC 8252)을 따르기 위함입니다.
앞서 살펴 본 웹 서버 클라이언트와의 차이점은, 승인 요청이 (네이티브 앱) 클라이언트가 아닌 시스템의 웹 브라우저를 통해서 간접적으로 이뤄진다는 점과, 사용자 동의로 인해 생성된 승인 코드의 Redirect 응답은 브라우저가 아니라, 운영 체제에 의해, 클라이언트 앱에 전달된다는 점입니다.
시스템 브라우저를 사용하는 이유는, 승인 서버가 사용자 동의를 구할 때, 사용자는 승인서버에 로그인을 하기 때문입니다. 이 로그인 단계를 클라이언트 앱이 수행하면, 사용자 증명(아이디와 비밀번호)이 클라이언트 앱에 그대로 노출되는 위험이 있습니다.
Redirect 응답을 클라이언트 앱에 전달하는 과정은 각 운영체제가 제공하는 "URI를 앱으로 전달하는 기능"에 의존합니다. 이 기능을 사용하기 위해서는, 사전에 Redirect Uri와 클라이언트를 연결하는 설정을 해야 합니다. (이러한 설정은 운영체제 별로 다릅니다)
Redirect Uri와 클라이언트를 연결하는 설정도, 악의적 클라이언트가 Redirect Uri 에 의해 먼저 선택되도록 설정할 수 있는 보안 구멍이 있습니다. 이 글의 범위를 넘어서는 내용이라 다루지 않습니다.
승인 코드 부여 방식은 꽤 복잡하지만, 가장 안전한 방법으로 최우선 적용할 것을 권고하고 있으니, 기본 방식이라고 이해하는 편이 좋습니다.
그러나, 우리가 승인 서버를 구현해야 하는 입장이 아니라면, 그 흐름만 익혀 놓는 정도로 충분하니, 내용에 너무 많이 매몰되지 않아도 됩니다.
OIDC
그런데, 앞서 살펴 본 OAuth 의 절차들은 인증을 위한 것일까요? 인가를 위한 것일까요?
어떤 부여 방식을 따르더라도, 각 방식의 모든 단계가 성공적이면, 클라이언트는 자원 서버로부터
- 자원을 획득하거나
- 거부의 메시지를
받습니다. 이는, OAuth 는 인가 프로토콜이라는 점을 의미합니다.
OAuth 라는 이름도 Open standard for Authorization 의 약자로, "누군가가 어떤 자원에 접근할 권한이 있음을 증명"하는데 필요한 절차(Protocol)를 규격화 한 것입니다.
이러한 특성에도 불구하고, 이 슬로그의 제목은 "OAuth 인증의 이해"입니다.
인가 프로토콜로 인증하는 방식을 이해한다 정도로 해석할 수 있는데, 이것이 가능한 이유는 OIDC(OpenId Connect 1.0 Core)의 존재 때문입니다.
OAuth 확장
앞서 OAuth는 네 가지 기본 권한 부여 절차와 추가로 확장할 수 있는 방법을 규정하고 있다고 언급했습니다.
확장의 구체적인 방법은, 승인 요청 단계
에서 '승인 요청’의 scope
파라미터에 특별한 값을 지정하는 것입니다.
scope={확장 이름}
scope 파라 미터는 원래 OAuth에서 "부여된 권한 범위"를 나타내기 위한 수단입니다.
예를 들어, 아래와 같이 범위를 profile 로 지정하면, 부여된 권한(Authorization Grant)이 사용자의 이름(성, 이름) 데이터라는 의미입니다.
scope=profile
OIDC는 이 파라미터의 값으로 "openid"를 지정했습니다.
OAuth 의 권한 부여 측면에서는, (승인 서버가 사용자에게 부여한) 사용자의 ID (Subject Id, sid, sub)에 접근할 수 있는 권한을 부여함을 가리킵니다.
사용자가 이 권한을 허락하면, 클라이언트는 이 ID 값을 얻을 수 있는데, OIDC에서는 이 값을 공개 ID(Open Id)라고 부릅니다. 이 값은 인증 서버에서는 유일하고, 모든 클라이언트 사이에 동일합니다.
인증 요청 (Authentication Request)
다시 말하면, 클라이언트가 승인 요청을 할 때, scope 파라미터에 “openid” 값을 설정하면, OAuth에서 규정한 인가 절차가 아니라, OIDC에서 규정한 인증 절차가 시작되는 것입니다.
승인 요청 단계 (Authorization Request)
클라이언트 : Redirect to /…?scope=openid → 승인 엔드 포인트 : 동의 화면 응답(Http Response)
OIDC 에서는 이러한 승인 요청을 인증 요청이라고 부릅니다.
인증 요청이 OIDC 인증 절차의 시작점이라고 할 수 있습니다.
위의 내용은 OIDC 1.0 Core 규정을 바탕으로 한 내용입니다.
그런데, 현실의 OIDC 구현은 scope 쿼리 파라미터를 사용하는 방식을 따르지 않을 수도 있습니다. 예를 들면, 아래와 같이 인증 엔드 포인트를 별도로 제공할 수도 있습니다.클라이언트 : Redirect → 인증 엔드 포인트 (/connect/authorize/…)
클라이언트를 구현하는 입장에서는 이 부분에 대해, 각 OIDC 구현 서버의 개별 가이드를 따라야 합니다.
ID Token
OIDC 의 다른 특징 중 하나는 JWT의 사용의 강제입니다.
OAuth의 인가 절차에 나타나는 승인 코드
와 접근 토큰
은 클라이언트가 그 의미를 알 수 없는 암호화된 문자열입니다.
OIDC는 인증 엔드 포인트(인증을 수행하는 승인 엔드 포인트)가 수행한 사용자 인증 결과를 JWT에 담아 응답할 것을 강제합니다. JWT는 페이로드가 오프된 토큰이라, 클라이언트는 인증 결과를 즉시 알 수 있게 된 것입니다.
OIDC에서는 이 JWT를 ID 토큰이라고 명명했는데, ID 토큰에는 인증에 관한 메타 데이터, 인증의 결과, 그리고 기타 클레임이 포함됩니다.
ID 토큰의 페이로드는 보통 아래와 같습니다.
{
"iss": "https://www.an-openid-provider.com",
"sub": "24400320",
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
"exp": 1311281970,
"iat": 1311280970,
"auth_time": 1311280969,
"acr": "urn:mace:incommon:iap:silver"
}
역할 (OIDC Roles)
OIDC는 OAuth 인가 절차에 기반하기에, OAuth 에서 나타나는 플레이어들이 그대로 등장합니다.
다만, 인증 이라는 문맥에 맞게 호칭 또는 역할을 다르게 규정합니다.
OIDC 플레이어들은 아래와 같습니다.
OpenId 제공자 (Provider, OP)
OIDC 를 지원하는 OAuth 승인 서버입니다.
"인증 제공자(Authentication Provider)"라고 부르기도 합니다.
OpenId 인증 의뢰자 (Relying Party, RP)
사용자 인증을 OP에 의존하는 주체(서비스, 서버)를 가리킵니다.
OAuth 의 클라이언트에 해당합니다.
사용자 (End-User)
OP에 계정을 가진 사람을 가리킵니다.
특히, OP의 계정으로 RP의 서비스를 이용, 다시 말하면, OP의 계정으로 RP에 로그인하기를 원합니다.
한 서비스의 계정으로 여러 다른 서비스에 로그인하는 것을 Sigle Sign-On(SSO)이라고 합니다.
OIDC 인증 절차
OIDC에서 규정하는 인증 절차는 대체로 아래와 같습니다.
(RP 가 웹 서버인 경우)
OAuth 그림에서 용어만 바뀐 듯이 보이지만, 핵심은 자원 서버가 사라져 전체적으로 단출해졌습니다. 이 구조에서는 승인 서버가 인증과 관련한 모든 것을 책임지게 됩니다.
OAuth가 4가지 권한 부여 방식(Grant Type)을 제시하였듯, OIDC도 이 절차의 구체적인 방법을 제시합니다.
OIDC 인증 흐름 (Authentication Flows)
OIDC 가 제시하는 인증 절차(Flows)는 아래와 같이 3 가지입니다.
(OAuth 에서 Grant type 선택에 따라 인가 절차가 결정되기 때문에, Flow 라는 단어가 의미적으로 더 자연스러워 보입니다.)
Authorization Code Flow
인증 요청의 결과로 승인 코드
가 발급 됩니다.
이 승인 코드로 ID 토큰을 발급 받을 수 있습니다.
Implicit Flow
인증 요청의 결과로 ID 토큰이 발급 됩니다.
때로는 접근 토큰(과 재발급 토큰)도 함께 발급됩니다.
Hybrid Flow
승인 코드와 ID 토큰(과 접근 토큰)이 모두 발급됩니다.
인증 흐름의 선택
인증 흐름은 RP가 선택할 수 있는데, 구체적인 방법은 인증 요청에 아래 쿼리 파라미터를 넣는 것입니다.
response_type={인증 흐름을 나타내는 값}
이 파라미터에 할당할 수 있는 값은 OIDC에 지정되어 있습니다.
아래 표는 할당할 수 있는 값과 그에 따라 선택되는 인증 흐름을 보여줍니다.
(복수의 값은 공백으로 구분됩니다)
값 | 흐름 |
---|---|
code | Authorization Code Flow |
id_token | Implicit Flow |
id_token token | Implicit Flow |
code id_token | Hybrid Flow |
code token | Hybrid Flow |
code id_token token | Hybrid Flow |
Authorization Code Flow
이 흐름 중 가장 권고 되는 승인 코드 흐름
의 예를 살펴 보겠습니다.
참고로, 이 흐름은 OAuth의 `승인 코드 부여’ 방식의 절차와 거의 동일하기에, 도식 보다는 Http 메시지를 통해 각 단계를 표현하겠습니다.
사용자가 OP를 통해 RP에 로그인 하기를 원합니다.
1. 인증 요청
RP는 사용자를 OP의 승인 엔드 포인트로 Redirect하면서 인증 요청 단계
가 시작됩니다.
이때, repsponse_type 파라미터를 "code"로 지정하여 Authorization Code Flow 를 선택합니다.
(읽기 편의 상, 줄 바꿈과 Url-Encoded 값을 문자로 변경했습니다.)
HTTP/1.1 302 Found
Location: https://www.op.com/{승인 엔드 포인트}?
response_type=code
&scope=openid profile email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https://www.rp.com/on-authz-code-issued
redirect_uri 파라미터 값은 RP가 OP에 클라이언트로 등록할 때, 사전에 지정한 것이어야 합니다.
OP의 승인 엔드 포인트는 이 파라미터 값(https://www.rp.com/on-authz-code-issued)이 사전에 지정된 항목인지 검사합니다. 만약 등록되어 있지 않은 값이면, 에러 메시지를 응답합니다.
이 Redirect를 받은 사용자의 User Agent는 Http 프로토콜에 의해, 아래와 같은 요청을 OP에 보냅니다.
(읽기 편의 상, 줄 바꿈과 Url-Encoded 값을 문자로 변경했습니다.)
GET /{승인 엔드 포인트}?
response_type=code
&scope=openid profile email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&edirect_uri=https://www.rp.com/on-authz-code-issued HTTP/1.1
Host: www.op.com
1.1 인증 요청 검증 / 사용자 동의 / 승인 코드 발급
승인 요청을 수신한 OP는 승인 요청을 자체를 검증하고, 사용자 인증과 동의 과정을 개시합니다.
이에 대한 구체적인 내용은 OIDC 3.1.2.2 ~ 3.1.2.4 까지의 내용을 참조하시기 바랍니다.
이 과정을 마치면, OP는 승인 코드를 발급하여 Redirect 응답합니다.
HTTP/1.1 302 Found
Location: https://www.rp.com/on-authz-code-issued?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
보시다시피 승인 코드는 응답의 바디가 아니라, Redirect Uri(https://www.rp.com/on-authz-code-issued
)에 쿼리 파라미터로 붙인 형태입니다.
만약 이 과정에서 문제가 있다면 Authentication Error Message를 Redirect 합니다.
HTTP/1.1 302 Found
Location: https://www.rp.com/on-authz-code-issued?
error=invalid_request
&error_description=Unsupported response_type value
&state=af0ifjsldkj
보시다시피, RP의 /on-authz-code-issued
핸들러는 승인 코드를 받는 경우와 에러 메시지를 받는 경우를 모두 처리해야 합니다.
참고로, 승인 코드의 발급 단계 이후부터는 OAuth와 동일합니다.
2. 토큰 요청
승인 코드를 수신한 RP의 /on-authz-code-issued
핸들러는 승인 코드를 OP의 토큰 엔드포인트로 보내 ID 토큰(과 때로는 접근 토큰)을 (Fetch)요청합니다.
curl --request POST
–url ‘https://www.op.com/{토큰 엔드 포인트}’
–header ‘content-type: application/x-www-form-urlencoded’
–data grant_type=authorization_code
–data ‘client_id={RP의 클라이언트 ID}’
–data client_secret={RP의 비밀번호}
–data code=SplxlOBeZQQYbYS6WxSbIA
–data ‘redirect_uri=https://www.rp.com/on-authz-code-issued’
보시다 시피 폼 데이터로 토큰 요청에 필요한 정보를 제공합니다.
grant_type=authorization_code
OAuth 의 Authorization Code Grant를 지정하여, 승인 코드를 보내고 있음을 알립니다.
client_id
, client_secret
RP가 OP에 등록할 때 부여 받은 것입니다.
code
승인 엔드포인트로 받은 승인 코드입니다.
redirect_uri=https://www.rp.com/on-authz-code-issued
아래에 다시 설명하겠지만, OP의 토큰 엔드 포인트는 Redirect 가 아닌 OK(200) 을 응답합니다.
따라서, 이 값은 OP의 응답과 직접적인 연관이 없습니다.
그럼에도 불구하고 RP가 이 값을 제공하는 이유는 토큰 요청은 승인 요청과 별개의 Http 세션이기 때문입니다. 토큰 요청 세션에서는 승인 요청 시 제출한 return-uri 값과 토큰 요청에 포함된 값이 일치하는 지 검사하여, 승인 요청과 토큰 요청의 연관성을 확인할 필요가 있기 때문입니다.
토큰 요청의 검증이 완료되면, OP는 토큰을 응답합니다.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
}
Cache-Control: no-store
Http 응답의 Cache-Control 를 통해, 이 응답에 포함된 값이 캐시되지 않도록 합니다.
보시다 시피, 접근 토큰, 재발급 토큰, 그리고 ID 토큰이 발급되었고, ID 토큰은 JWT 형식입니다.
만약, 토큰 요청에 문제가 있다면, 아래와 같이 에러 메시지를 응답합니다.
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
"error": "invalid_request"
}
RP는 ID 토큰에 충분한 ID 정보, 예를 들어, Email 이 있다면 여기서 인증을 끝낼 수 있습니다.
그렇지 않다면, OP의 사용자 정보 엔드 포인트에 접근 토큰을 보내, 사용자 정보를 추가적으로 얻을 수 있습니다.
이 과정은 접근 토큰을 얻는 과정과 동일하니 생략하도록 하겠습니다.
Implicit Flow
이 흐름은 Authorization Code Flow 와 완전히 동일한데, 인증 엔드 포인트가 인증 요청에 대한 응답으로 승인 코드 대신, 모든 토큰을 Redirect 하는 차이만 있습니다.
즉, 승인 요청 => 승인 코드 => 토큰의 과정이, 승인 요청 => 토큰으로 압축된 형태라고 볼 수 있습니다.
1. 승인 요청
RP의 Redirect 응답을 받은 사용자의 브라우저는 아래의 요청을 인증 엔드 포인트로 보냅니다.
GET {승인 엔드 포인트}?
response_type=id_token token
&client_id=s6BhdRkqt3
&redirect_uri=https://www.rp.com/on-idtoken-issued
&scope=openid profile
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: www.op.com
response_type=id_token token
Implicit Flow 를 선택했고, ID 토큰과 접근 토큰을 모두 요청합니다.
client_id
압축된 과정이기에, 토큰 요청 단계에서 제출할 클라이언트 ID를 승인 요청 단계에서 제출해야 합니다. 이때, client-password 는 제출하지 않습니다.
1.1 승인 엔드 포인트의 응답
승인 요청의 검증, 클라리언트 확인, 사용자 인증, 동의 확인을 끝낸 OP는 승인 코드 대신, 아래의 Redirect 응답을 해야 합니다.
(읽기 편의를 위해, Id 토큰 값 줄임)
HTTP/1.1 302 Found
Location: https://www.rp.com/on-idtoken-issued#
access_token=SlAV32hkKG
&token_type=bearer
&id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
&expires_in=3600
&state=af0ifjsldkj
보시다시피, Redirect Uri 에 모든 토큰이 발급되어 있습니다.
Fragment 파라미터 논란
승인 엔트 포인트는 토큰들을 Return Uri에 추가했는데, (?로 시작하는) 쿼리 파라미터가 아닌 (#으로 시작하는) fragment 파라미터가 사용되었습니다. .
그러나, fragment 파라미터를 승인 엔드포인트 URI에 사용하는 것은 OAuth 2.0 3.1 에서 금지하는 방식이라는 의견도 있는데, 이는 문맥 없이 자구만 따지는 협의의 해석 같습니다.
…
The (Authorization) endpoint URI MAY include an “application/x-www-form-urlencoded” formatted (per Appendix B) query component ([RFC3986] Section 3.4), which MUST be retained when adding additional query parameters. The endpoint URI MUST NOT include a fragment component.
…
위 글 마지막 부분에 "The endpoint URI"를 OAuth 에 등장하는 모든 endpoint URI로 해석하면, 어떤 경우라도 fragment 파라미터가 쓰이면 안된다는 의미이지만, 이 내용(3.1)은 승인 엔드 포인트에 관한 것이라서, Authorization endpoint URI만 가르킨다고 볼 수도 있습니다.
이 경우, Return Uri 에는 해당이 없는 것이죠.(써도 된다는 의미)
말로만 설명하는 부분은 이 글이 마지막입니다.
다음 글에서는 구글의 OAuth 인증을 코드로 어떻게 구현하는 지에 대해 알아 보도록 하겠습니다.
(혹시나 틀린 내용이 있다면, 많은 딴지 부탁드립니다)