티스토리 뷰

grant_type

  • OAuth 2.0 프레임워크의 핵심은 다양한 클라이언트 환경에 적합한 인증 및 권한의 위임 방법(grant_type)을 제공하고 그 결과로 클라이언트에게 access_token을 발급하는 것이다.

  • 한 번 획득된 access_token은 만료 시점까지 모든 리소스 서버의 엔드포인트 요청 헤더에 Authorization: Bearer {ACCESS_TOKEN}로 첨부된다.

  • 사용자의 인증 과정에 개입하는 2가지 방식(authorization_code, implicit)과 사용자가 인증 과정에 개입하지 않는 2가지 방식(password, client_credentials)이 있다. 마지막으로 만료된 access_token을 재발급 받기 위한 refresh_token이 있다.

authorization_code

  • 클라이언트가 백엔드를 제공하는 웹 애플리케이션이면 authorization_code 인증을 사용한다. [관련 링크]
GET https://{oauth2_server}/oauth/authorize
?response_type=code
&client_id={client_id}
&redirect_uri={redirect_uri}
&scope={scope}
  • 사용자가 클라이언트가 요청한 scope에 대한 권한 위임에 동의하면 아래와 같이 응답한다.
HTTP/1.1 302 Found
Location: {redirect_uri}?code={code}
  • 사용자 브라우저에서는 redirect_uri가 가리키는 클라이언트의 백엔드 웹 서버로 아래와 같이 GET 요청을 수행한다. 클라이언트는 이 시점에 사용자가 권한 위임에 동의한 code를 획득할 수 있지만 아직 access_token은 모르는 상태이다.
GET {redirect_uri}?code={code} HTTP/1.1
Host: {redirect_host}
  • 클라이언트의 백엔드는 아래와 같이 획득한 code를 인증 서버에 요청하여 access_token을 발급 받는다. 이 과정에서 access_token은 클라이언트 외부로 유출되지 않는다. 클라이언트의 백엔드가 존재할 경우 가장 안전한 인증 방식이라고 불리는 이유이다.
curl -X POST 'https://{oauth2_server}/oauth/token'
-H 'Authorization: Basic {base64 of client_id:client_sercret}'
-d 'grant_type=authorization_code'
-d 'code={code}'
-d 'redirect_uri={redirect_uri}'

HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": {access_token},
    ...
}

implicit

  • implicitauthorization_code과 같이 인증 과정에서 사용자의 로그인 및 권한 동의를 요구하는 타입이다.

  • implicit은 웹 서버가 아닌 모바일 네이티브 앱 및 브라우저 기반의 JS 애플리케이션(SPA)에 가장 적합하도록 설계된 grant_type타입이다.

  • authorization_code와의 차이점이라면 response_type으로 code가 아닌 token을 요청하고 반환한다는 것이다. 사용자가 로그인 및 권한 위임에 동의하면 redirect_uritoken 파라메터를 통해 access_token을 바로 내려준다.

  • 이 방식은 access_token이 그대로 사용자(또는 외부)에게 노출된다. 유효한 클라이언트인지 확인할 방법은 redirect_uri 뿐이다. (절대 사용자(외부)에 노출되지 않아야 할 client_secret은 전혀 사용되지 않는다.)

  • refresh_token 또한 노출되지 않아야 하기 때문에 발급되지 않는다. 따라서 access_token이 만료되면 같은 인증 과정을 반복해야 한다. (Azure AD같은 서비스는 iframe에 세션 쿠키를 유지하는 방법으로 이러한 인증 과정을 생략하기도 한다.)

  • [1단계] 클라이언트가 인증 서버에게 사용자 로그인 및 권한 동의 웹 페이지를 요청한다. GET /oauth/authorize?response_type=token&client_id={CLINET_ID}&redirect_uri={CALLBACK_URL}&scope={SCOPE} Yahoo와 같이 다국어 지원 API들은 language 파라메터를 옵션으로 요청 받기도 한다.

  • [2단계] 1단계 성공시 POST {CALLBACK_URL}#token={ACCESS_TOKEN}으로 리다이렉트한다. 이 시점에 클라이언트는 access_token을 획득하게 된다.

  • [3단계] 획득한 access_token으로 리소스 서버의 엔드포인트로 API를 요청한다.

SPA에서의 implicit 인증 흐름

  • SPA는 백엔드가 존재하지 않는 클라이언트로 implicit 인증에 적합하다. 따라서 사용자 브라우저에서 바로 access_token을 획득해야 한다. 아래와 같이 인증 서버에 권한 위임 동의 페이지를 요청한다. 백엔드 외에 노출되지 말아야 할 client_secret은 전달되지 않는다. 인증 서버는 client_idredirect_uri가 기존에 등록된 것과 일치하는지 확인한다.
GET https://{oauth2_server}/oauth/authorize
?response_type=token
&client_id={client_id}
&redirect_uri={redirect_uri}
&scope={scope}
  • 사용자가 클라이언트가 요청한 scope에 대한 권한 위임에 동의하면 아래와 같이 응답한다.
HTTP/1.1 302 Found
Location: {redirect_uri}#access_token={access_token}
  • 사용자 브라우저에서는 아래와 같이 GET 요청을 수행한다. 이 과정에서 access_token은 네트워크에 노출되지 않는다. 사용자 브라우저에서만 access_token을 획득한다. [관련 링크]
GET {redirect_uri} HTTP/1.1
Host: {redirect_host}
  • GET 요청이 완료되면 SPAJavaScriptaccess_token을 확인할 수 있다. refresh_token이 제공되지 않으므로 보통 access_token의 유효기간으로 2주가 제공된다. 2주가 지나면 다시 같은 절차를 반복해야 한다.
window.location.hash; // #access_token={access_token}

password

  • password는 사용자의 인증 정보를 클라이언트로부터 보호하는 authorization_code, implicit과 다르게 클라이언트가 이미 사용자의 인증 정보를 알고 있을 경우 사용할 수 있는 타입이다. 클라이언트가 매우 신뢰할 수 있는 경우에 사용한다. [관련 링크]


  • POST /oauth/token 요청으로 바로 access_token을 획득한다. 필수로 요구되는 파라메터는 client_id, client_secret, grant_type = password, username, password이다.

refresh_token

refresh_tokenaccess_token을 재발급하기 위한 인증 방식이다. 아래와 같이 인증 서버에 access_token의 재발급을 요청한다.

curl -X POST 'https://{oauth2_server}/oauth/token'
-H 'Authorization: Basic {base64 of client_id:client_secret}'
-d 'grant_type=refresh_token'
-d 'refresh_token={refresh_token}'

HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": {access_token},
    ...
}

보호된 자원 요청

  • 앞서 다양한 인증 방식에 의해 사용자의 권한 위임 정보를 담은 access_token을 획득한 클라이언트는 이제 리소스 서버의 보호된 자원에 접근할 수 있다.
curl -X GET 'https://{protected_resource_server}/resources/1'
-H 'Authorization: Bearer {access_token}'

참고 글

댓글
댓글쓰기 폼