iamminji / TIL

🐬 today i learned
5 stars 0 forks source link

OAuth2.0 에 대해 알아보기 #6

Open iamminji opened 2 years ago

iamminji commented 2 years ago

OAuth2.0

OAuth2.0 이란?

OAuth2.0 을 왜 사용하는지?

신뢰할만한 인증 서버를 사용하여 다양한 플랫폼 (third-party application) 에서 리소스 접근을 보다 쉽게 하기 위해서 등장한 프로토콜이다.

OAuth2.0 Role

OAuth 는 4가지 role 을 가지고 있다.

  1. Resource owner An entity capable of granting access to a protected resource. When a resource owner is a person, it is referred to as an end-user
  2. Resource server The server hosting the protected resources, capable of accepting and responding to protected resource requests using access token.
  3. Client An application maing protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular impelemntation characteristics (ex. wheter the application executes on a server, a desktop, or other devices).
  4. Authorization server The server issuing access tokens to the client after successfully authenticating the resource owner and obtainging authorization.

Resource owner 는 보통 요청자 (사람) 이고 Resource server 는 구글이나 카카오톡과 같이 Resource owner 의 정보가 있는 곳이다. Client 는 (누가 만든) 웹 사이트, 서버이고 Authorization Server 로는 카카오, 네이버 구글, 페이스북, Okta 등이 있다.

사람이 어떤 웹사이트를 이용해서 로그인할 때 Authorization server 를 사용하여 resource에 접근하는 것이다.

OAuth2.0 flow

 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

(A) 클라이언트는 authorization 을 resource owner 에게 요청한다. (B) 클라이언트는 authorization grant(which is a credential representing the resource owner's authorization) type 4가지 중 한가지를 사용합니다. (authorization server 가 어떤 type 을 사용할 것인지에 따라 다르다.) (C) 클라이언트는 access token을 요청한다. (D) authorization server 는 클라이언트가 허가 되었는지, (authorization grant가) 유효한지 확인하고 유효하다면 access token 을 발급한다. (E) 클라이언트는 access token을 사용하여 resource server에게 resource 를 요청한다. (F) resource server 는 access token이 유효한지 확인하고 유효하다면 요청을 받는다.

OAuth2.0 grant type

access token을 얻기 위해 OAuth2.0에는 4가지 grant type이 있다.

Authorization code

일반적으로 많이 사용한다. 백엔드 (API 간 통신) 에서는 이 방식을 쓴다. authorization code 는 Resource owner는 모르고 Authorization server 와 Client 사이의 값이기 때문에 보안적인 측면에서 (밑에 있는) Implicit 보다 낫다. (Client 는 이름이 클라이언트지만 실제로 웹브라우저 같은게 아니라 백엔드, API 이다.)

Implicit

SPA 일 때 보통 사용한다. authorization code 없이 바로 access token을 요청하여 브라우저에서 사용한다.

Resource Owner Password Credentials

Client Credentials

정리

정리하자면 grant type 4가지에서 사용되는 채널은 아래와 같다.

front와 back 을 섞어 쓰는 Authorization code 를 많이들 쓰고 권장한다.

OAuth2.0 Specification

Access Token

Refersh token

Refresh token 은 access token 과 다르게 해당 토큰을 Resource server 에게 보내지 않는다. 오직 Authorization server 를 위해서만 (Access token을 재발급 받기 위해서만) 있다.

TLS Version

최신 버젼을 사용하자

HTTP Redirection

Interoperability

Client 등록

Authorization server에 Client를 등록해야 한다. Client 를 등록할 때 Client 개발자는 아래 내용을 따라야 한다.

Protocol Endpoint

여기서 부터 반드시, ~해야 한다, ~해도 된다 식의 용어를 사용한다. 해당 강제성, 허용은 RFC 문서를 참고하였다. 공통적으로 모든 Endpoint 는 TLS 위에서 동작해야 한다.

권한 허가 (Authorization) 은 2개의 서버 엔드포인트를 사용한다.

클라이언트 엔드 포인트도 있다.

물론 필요에 따라 추가하여 사용할 수 도 있다.

Authorization Endpoint

authorization endpoint 는 resource owner가 authorization grant를 얻을 때 사용한다. endpoint URI 는 application/x-www-form-urlencoded 이고 (강제는 아님 RFC에 MAY 라고 써 있다.) 추가 쿼리 파라미터를 반드시 포함한다. 하지만 URI 맨 끝에 fragment는 절대 포함할 수 없다.

HTTP Mehotd의 경우 반드시 GET 이어야 하고 POST 는 지원해도 된다.

파라미터 없이 요청하면 생략된 것 처럼 행동 해야 하고, Authorization server가 이해하지 못하는 파라미터는 반드시 무시한다.

Request와 Response 에서 동일한 파라미터는 두개 이상 올 수 없다. (반드시 하나만 사용할 것)

Response type

authorization endpoint 는 authorization code grant type 과 implicit gran type 에서 사용된다. authorization server 는 아래의 파라미터를 사용한다.

response_type 파라미터가 없으면 authorization server는 반드시 에러 응답을 주어야 한다.

Redirection Endpoint

redirection endpoint URI 는 반드시 absolute URI 여야 한다. endpoint URI 는 application/x-www-form-urlencoded 이고 (강제는 아님 RFC에 MAY 라고 써 있다.) 추가 쿼리 파라미터를 반드시 포함한다. 하지만 URI 맨 끝에 fragment는 절대 포함할 수 없다. (TODO)

참고

Token endpoint

token endpoint 는 client 가 access token, refresh token 을 얻기 위해 사용된다. endpoint URI 는 application/x-www-form-urlencoded 이고 (강제는 아님 RFC에 MAY 라고 써 있다.) 추가 쿼리 파라미터를 반드시 포함한다. 하지만 URI 맨 끝에 fragment는 절대 포함할 수 없다.

HTTP Method 의 경우 반드시 POST 로 access token 을 요청해야 한ㄷ.

Client Authentication

authorization_code grant_type 요청의 경우 인증 받지 않은 클라이언트는 반드시 client_id 값을 사용해야 하고 인증 받은 클라이언트는 굳이 안 그래도 된다.

참고

Access Token Scope

Obtaining Authorization

Authorization Code Grant

 +----------+
 | Resource |
 |   Owner  |
 |          |
 +----------+
      ^
      |
     (B)
 +----|-----+          Client Identifier      +---------------+
 |         -+----(A)-- & Redirection URI ---->|               |
 |  User-   |                                 | Authorization |
 |  Agent  -+----(B)-- User authenticates --->|     Server    |
 |          |                                 |               |
 |         -+----(C)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
  (A)  (C)                                        |      |
   |    |                                         |      |
   ^    v                                         |      |
 +---------+                                      |      |
 |         |>---(D)-- Authorization Code ---------'      |
 |  Client |          & Redirection URI                  |
 |         |                                             |
 |         |<---(E)----- Access Token -------------------'
 +---------+       (w/ Optional Refresh Token)

Authorization Request

header 는 application/x-www-form-urlencoded 을 사용한다. (authorization endpoint URI)

요청 예시는 다음과 같다. (TLS 위에서 동작한다고 가정)

GET /authorize?
    response_type=code&
    client_id=s6BhdRkqt3&state=xyz&
    redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

Authorization Response

정상 응답일 경우

예시로 authorization server 는 아래와 같은 HTTP 응답을 준다.

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

에러가 나면 아래와 같은 형식

에러날 경우 예시

HTTP/1.1 302 Found
Location: https://client.example.com/cb?error=access_denied&state=xyz

Access Token Request

요청은 다음과 같이 한다.

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

Authorization server 는 반드시 아래와 같이 행동한다.

Access Token Response

요청이 유효하면 access token 을 발급하고 refresh token 은 줘도 되고 안줘도 된다.

요청이 성공하면 아래의 값들을 갖고 있다.

HTTP 응답의 media type은 application/json 이며 http header 에 반드시 Cache-Control: no-store 가 있어야 한다. Pragma 에도 no-cache 를 포함한다. (보안 때문에)

Implicit Grant

TODO...

Resource Owner Password Credentials Grant

TODO...

Client Credentials Grant

TODO...

Issuing an Access Token

Successful Response

성공에 대한 응답 예시는 아래와 같다.

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

토큰을 포함해서 다른 값들은 정의 되지 않았기 때문에 (스펙이 없음) authorization server 가 제대로 가이드 해줘야 한다.

Error Response

에러 응답의 경우엔 HTTP Status Code 400 을 준다. (강제는 아님) 그리고 아래 파라미터들을 포함한다.

에러 응답은 다음 처럼 준다.

     HTTP/1.1 400 Bad Request
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "error":"invalid_request"
     }

Refreshing an Access Token

client 는 token endpoint 로 refresh token 발급을 요청한다.

요청 예시는 다음과 같다.

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

성공/에러 응답은 access token 과 동일하다.

refresh token 요청이 오면 client 는 기존 refresh token 을 파기해야 한다. 그리고 authorization server 는 새로운 refresh token 을 주고 오래된 refresh token 을 revoke 한다. (MAY)

Security Considerations

참고

https://datatracker.ietf.org/doc/html/rfc6749

iamminji commented 2 years ago

Bearer token

OAuth1 에서는 private, public 이라는 명명으로 token을 분리하여 사용했지만 OAUth2.0 부터는 Bearer token 이라는 하나의 값만을 사용한다. 해당 토큰의 목적은 클라이언트가 Authorization 서버에 접근하기 위한 용도일 뿐이다.

Bearer token 은 어떻게 만드는지?

보통 16진수의 랜덤한 문자열을 사용하거나 JWT 를 사용한다.

JWT 토큰을 Bearer token 으로 사용해도 되는건지?

JWT 토큰을 Bearer 토큰으로 사용하는 것은 OAuth2.0 스펙에 위반되는 것은 아니다. Bearer token 의 경우엔 스펙이 없기 때문에 길이 제한 또한 없다.

그런데 JWT 토큰은 넘 길어서 그냥 그렇게 써도 되는건지? 궁금해서 좀 찾아보니까 이런 비슷한 고민의 스택오버플로우 글들도 좀 있더라. 답변이 썩 맘에 드는건 아니였고... 결론만 말하자면 다른 OAuth2 Provider 는 어떤지 조사를 해보니 구글같은 경우는 access token이 2048 byte 였다. 그래서 그냥 JWT 를 사용해도 괜찮을 듯. 어차피 스펙에 사이즈나 길이는 없다.

Bearer token 의 security?

클라이언트가 Auth 서버에게 요청할 때 HTTP header 에 해당 토큰 정보를 담고, HTTPS 로 요청하기 때문에 secure 걱정은 하지 않아도 된다. 그리고 token 자체가 sensitive 한 정보는 아니라고 보고 있다. 하지만 조심은 해야 한다. 그러기 위해선 다음과 같은 권장사항을 따라주자

  1. HTTPS 를 사용한다.
  2. 토큰을 쿠키에 저장하지 않는다.
  3. 토큰의 life time 을 짧게 가져 간다. (access token)
  4. 토큰의 scope 를 정의한다.
  5. URL 에 토큰을 담아 보내지 않는다. (query string 에 포함하지 말자)
iamminji commented 2 years ago

OpenID Connect 란?

Problems with OAuth2.0 for authentication

OpenID Connect is for authentication. OAuth2.0 is for authorization

그래서 요청자의 정보를 사용하기 위해 OpenID Connect라는, OAuth2.0 위에서 동작하는 레이어가 등장하였다.

OpenID Connect는 Authentication을 위한 것으로써, 사용하는 방식은 Authorization server 에서 클라이언트에게 access token 을 줄 때, id token 을 함께 넘겨주는 것이다. (https://oauth.net/id-tokens-vs-access-tokens/)

What OpenID Connect adds

실제 유저 정보를 가지고 있는 것은 id token이 된다.

User Oauth2.0 for

Use OpenID Connect for