노블의 개발이야기

OAuth 본문

기타

OAuth

더플러스 2015. 8. 4. 11:28

1. 액세스 토큰

OAuth 2.0을 반영한 대부분의 API는 허가된 요청을 만드는데 전달 토큰만 있으면 된다. 전달 토큰은 간단한 토큰 값으로 보호되는 자원에 접근할 수 있게 해주는 액세스 토큰의 한 종류다. API 호출을 만드는 데 필요한 암호 키 같은 추가 정보는 없다.


액세스 토큰을 얻은 후, 그것을 요청에 실어 보낼 수 있다. 액세스 토큰을 요청에 실어 보내는 다양한 방법 중 HTTP 권한 헤더에 액세스 토큰을 포함하는 방법을 선호한다.


GET /tasks/v1/lists/@default/tasks HTTP/1.1

Host: www.googleapis.com

Authorization: Bearer ya29.AHES6ZSzX


개발자들은 아래와 같은 이유로 HTTP 권한 헤더에 액세스 토큰을 포함하는 방법을 선호한다.


  • 헤더는 프록시 서버나 웹 서버 접근 로그에 거의 로그를 남기지 않는다.
  • 헤더는 거의 캐시되지 않는다.
  • 헤더는 클라이언트에서 요청이 만들어질 때 브라우저 캐시에 저장되지 않는다.

질의 파라미터에 액세스 토큰을 포함하는 방법
URL 질의 파라미터에 액세스 토큰을 포함하는 방법은 디버깅이나 라이브러리가 권한 헤더를 수정하기 어려울 때 유용하다. 이 메커니즘은 클라이언트사이드 플로우를 사용할 때와 JSONP 요청 안에 액세스 토큰을 포함할 때 유용하다. 

https://www.googleapis.com/tasks/v1/lists/@default/tasks?callback=ouputTasks&access_token=ya29.AHES6ZTh00gsAn4

인코딩된 Form body 파라미터에 액세스 토큰을 포함하는 방법
이는 애플리케이션이 요청의 권한 헤더를 수정할 수 없을 때 사용하는 대체 메커니즘이다. HTTP body가 정상적으로 보내질 때만 사용되며, "application/x-www.form-urlencoded"의 바디에 form 파라미터로 추가될 수 있다.
단, Google Tasks API는 이 메커니즘을 지원하지 않는다.

2. 권한 플로우
각 클라이언트 프로파일에는 자원 소유자의 데이터에 접근할 수 있는 권한 획득을 위해 적절한 프로토콜 플로우를 적용해야한다. OAuth 2.0 프로토콜에는 권한 획득을 위한 네 개의 주요 '허가 유형'과 확장 메커니즘이 정의되어 있다.

권한 코드
이 허가 유형은 서버사이드 웹 애플리케이션에 가장 적절하다. 자원 소유자가 데이터에 접근을 허가하면, URL의 질의 파라미터에 의해 권한 코드와 함께 웹애플리케이션으로 리다이렉트된다. 권한 코드는 클라이언트 애플리케이션에 의해 액세스 토큰으로 교환된다. 교환은 서버 간에 이루어지며 자원 소유자라도 액세스 토큰을 얻는 것을 막기 위해 client_id와 client_secret을 요구한다. 그리고 갱신 토크(refresh token)을 이용하여 장기적인 API 접근을 허용한다.

브라우저 기반 클라이언트사이드 애플리케이션의 암묵적 허가
자원 소유자의 비밀번호 기반 허가
클라이언트 인증서

3. 플로우의 단계

1단계: 사용자에게 하는 일과 그 일에 관한 권한을 요청하기

API 제공 업체의 문서에서 OAuth 권한 엔드포인트를 위한 URL을 찾을 수 있다.
Google Tasks (그 외 OAuth 2.0을 사용하는 다른 Google API들)의 권한 엔드포인트는 다음과 같다.
https://accounts.google.com/o/oauth2/auth

client_id
애플리케이션을 등록할 때 제공되는 값이다.

redirect_uri
애플리케이션에 대한 접근을 승인했을 때 사용자가 리턴되어야 하는 위치다. 예를 들면 위 애플리케이션은 'redirect_uri"로 "http://payroll.saasyapp.com/oauth_response.php"을 사용할 것이다. 'redirect_uri'에서 사용되는 값은 API 제공 업체가 미리 등록해야 한다.

scope
애플리케이션이 요청한 데이터의 접근 범위를 가리키며, 공백 문자를 구분자로 사용한다. (페이스북은 콤마(,)를 구분자로 사용한다.) 가능한 범위의 값들은 API 제공자 문서에 포함되어야 한다. Google Tasks의 scope는 "https://www.googleapis.com/auth/tasks"이다. 애플리케이션이 Google Docs에도 접근해야 하면 scope값은 다음과 같이 작성한다.
https://www.googleapis.com/auth/tasks https://docs.google.com/feeds


response_type

서버사이드 웹 애플리케이션 플로우의 코드로, 사용자가 권한 요청을 승인한 후 애플리케이션으로 리턴되는 권한 코드를 나타낸다.


state

구현물에서 사이트 간 요청 위조 CSRF 공격을 막기 위해 애플리케이션에서 사용되는 유일한 값이다. 이 값은 예측이 불가능하고 클라이언트(아마도 서버사이드 세션 안에)에서 기밀이 유지되는 특정 요청에 대한 무작위 상태 값이어야 한다.


표준 OAuth 질의 파라미터 외에 구글 도구에만 해당하는 몇 가지 파라미터가 있다.


approval_prompt

사용자가 애플리케이션에 방문할 때마다 승인을 위해 사용자에게 알리길 원하면, approval_prompt를 'force'로 설정한다. 사용자가 처음 애플리케이션을 방문할 때만 승인 요청을 보게 하려면 'auto'로 설정한다.


access_type

사용자가 컴퓨터를 사용하지 않는 동안 애플리케이션이 사용자 데이터에 접근하길 원하면, access_type를 'offline'으로 설정한다. 그러면 사용자가 명시적으로 애플리케이션에 접근 허가를 승인할 때 발급되는 재발급 토큰을 가져올 수 있다. 만약, 'online'을 사용하면 재발급 토큰은 발급되지 않을 것이다.


# 에러처리

모든 요청 파라미터가 유효하고 사용자가 데이터 접근 요청을 승인하면, 사용자는 다시 redirect_uri에 명세된 URL의 애플리케이션으로 리다이렉트된다. 그러나 요청 파라미터 중 하나라도 유효하지 않으면 에러가 발생할 것이다.


만약 redirect_uri, client_id 또는 다른 요청 정보에 문제가 있으면, 권한 서버는 사용자에게 에러 메시지를 보여주고 사용자를 애플리케이션으로 리다이렉트하지 않는다. 사용자 또는 권한 서버가 접근 요청을 거부하면, 에러 응답을 생성하고 'access_denied" 같은 에러를 발생시킬 질의 파라미터를 포함한 'redirect_uri'로 사용자를 리다이렉트한다. 추가적으로 권한 서버는 error_escription 메시지나 더 많은 에러 정보를 보여주는 웹 페이지 URL인 error_uri를 나타낼 수 있다.


invalid_request

요청에 필수 파라미터가 빠져 있거나 지원하지 않는 파라미터가 들어 있는 등 비정상적인 경우의 에러 타입니다.


unauthorized_client

클라이언트가 권한 코드를 요청하기 위한 권한이 없는 경우 에러 타입니다.


unsupported_response_type

권한 서버가 권한 코드를 얻는 걸 지원하지 않는 경우의 에러 타입이다.


invalid_scope

요청 범위가 유효하지 않거나, 서버가 알 수 없거나, 비정상적인 경우다.


server_error

권한 서버가 요청을 처리할 때 예상치 않은 상태를 만나는 경우의 에러 타입이다.


temporarily_unavailable

권한 서버가 일시적인 과부하나 유지 보수로 인해, 현재 요청을 다룰 수 없는 경우의 에러 타입니다.


2단계: 권한 코드를 액세스 토큰으로 교환하기


승인 과정에서 에러가 발생하지 않는 경우, 권한 서버는 사용자를 'redirect_uri'로 명세된 URL의 애플리케이션으로 리다이렉트할 것이다. 이 예제에서 사용자는 "http://payroll.saasyapp.com/oauth2callback"으로 리다리렉트된다.


사용자가 접근을 허가하면, 다음 두 질의 파라미터는 권한 서버에 의해 웹 애플리케이션으로 리다이렉트된다.


code

사용자가 접근 요청을 승인했을 때를 나타내는 권한 코드다.


state

권한 서버로 초기 요청이 전달될 때 포함되었던 state 파라미터의 값이다.


상태 값은 앞선 1단계에서 생성된 값과 비교된다. 만약 값이 일치하지 않으면 악의적인 사용자가 애플리케이션에 CSRF 공격을 시도한 것일 수도 있다. 따라서 OAuth 플로우를 중단해야 한다. 


http://payroll.saasyapp.com/oauth2callback?code=AB231DEF2134123kj89&state=987d43e51a262f


애플리케이션은 API 요청을 만들기 위해 권한 코드를 OAuth 액세스 토큰으로 교환해야 한다. 만약 OAuth에 대한 클라이언트 라이브러리를 사용한다면, 교환은 일반적으로 라이브러리에 의해 내부적으로 일어난다. 라이브러리를 사용하지 않는다면, 액세스 토큰의 엔드포인트로 HTTP POST 요청을 만들어야 한다. 


code

애플리케이션에 전달되는 권한 코드다.


redirect_uri

권한 엔드포인트에 첫 요청을 보낼 때의 등록된 위치다.


grant_type

권한 코드의 액세스 토큰으로의 교환을 나타내는 값(=authorization_code)이다.


HTTP POST는 애플리케이션 등록으로 얻게되는 'client_id'와 'client_secret'을 사용하여 인증된다. 스펙에는 요청을 인증하는 두 가지 기본 방법이 있다.

HTTP Basic Authorization 헤더(사용자 이름을 client_id로, 비밀번호를 client_secret으로 사용)를 포함하는 방법과 HTTP POST 파라미터로 client_id와 client_secret을 포함하는 방법이다.


일반적인 권한 헤더는 다음과 같다.

Authorization: Basic

MDAwMDAwMDA0NzU1REU0MzpVRWhrTDRzTmVOOFlhbG50UHhnUjhaT WtpVU1nWWlJNg==


HTTP Basic 접근 인증은 OAuth 2.0 스펙에 나중에 추가되었기 때문에, 아직 많은 API 제공 업체가 지원하지는 않는다. 대신 HTTP POST 파라미터 방식이 많이 사용된다.

다음의 추가 POST 파라미터들은 code, state와 함께 사용된다.


client_id

애플리케이션에 등록했을 때 제공되는 값이다.


client_secret 

애플리케이션을 등록했을 때 제공되는 기밀이다.


만약 요청이 인증되고 다른 파라미터가 유효하다면, 권한 서버는 JSON-인코딩 응답에 OAuth 액세스 토큰을 리턴한다.


access_token

API 요청을 허가하는 데 사용되는 토큰이다.


token_type

발급된 액세스 토큰의 타입이다. 종종 'bearer'가 사용되지만 잠재적인 값들로 확장 가능하다.


이 액세스 토큰은 시간 제약이 있을 수 있기 때문에, 다음과 같은 추가 정보가 리턴될 수 있다.


expires_in

액세스 토큰이 만료되기 까지 남은 시간이다. (초 단위)


refresh_token

액세스 토큰이 만료된 후 새로운 액세스 토큰을 얻기 위해 사용되는 토큰디다.


{
"access_token" : "ya29.AHES6ZSzX",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/iQI98wWFfJNFWIzs5EDDrSiYewe3dFqt5vIV-9ibT9k"

}


3단계: API 호출하기

이번 단계는 사용자의 작업을 조회하고 수정한다. OAuth 2.0을 구현하는 API 제공 업체들은 전달 토큰(bearer token)을 사용한다. 이를 통해 애플리케이션이 암호화 서명 없이 요청 내에 OAuth 액세스 토큰을 포함해서 간단하게 API 요청을 허가 받을 수 있다.


## 에러처리

OAuth 2.0 액세스 토큰으로 API 호출을 만들 때, 액세스 토큰이 만료되거나 취소되어서 더 이상 유효하지 않으면 HTTP 4xx 에러가 발생한다. 


HTTP/1.1 401 Unauthorized 

WWW-Authenticate: Bearer realm="example",

                              error="invalid_token", 

                              error_description="The access token expired"


유효한 에러 코드는 invalid_request, invalid_token, insufficient_scope를 포함한다.


{

    "error": {

        "type": "OAuthException",

        "message": "Error validating access token."

    }

}


다음은 새로운 API를 요청했을 때 액세스 토큰이 만료되었다는 응답을 보여주는 구글 에제이다.


{
    "error": {

"errors": [ 

{

"domain": "global",
"reason": "authError",
"message": "Invalid Credentials", 

"locationType": "header", 

"location": "Authorization"

],

"code": 401,

"message": "Invalid Credentials" }


4-1단계: 액세스 토큰 재발급하기

권한 코드가 액세스 토큰으로 교환될 때, API 제공 업체들은 그들의 API에 장기 오프라인 접근 모드를 지원하더라도 단기 액세스 토큰을 발급할 것이다. 비록 단기 액세스 토큰의 수명이 제한되어 있더라도, 두가지 질의 파라미터('expires_in'과 'refresh_token')를 사용하여 장기 접근이 가능하도록 응답에 포함할 수 있다.

expires_in이 응답에 포함되면 access_token의 남은 수명을 초 단위로 나타낸다. 액세스 토큰이 만료되면 refresh_token 파라미터는 새로운 액세스 토큰을 획득하는데 사용할 수 있다.


액세스 토큰 재발급은 토큰의 엔드포인트에 있는 'grant_type'을 'refresh_token'으로 설정하고, refresh_token을 포함하는 HTTP POST를 만들어 보내면 된다.


4-2단계: 새로운 액세스 토큰 획득하기

일부 애플리케이션은 사용자가 "자리에 있을 때"만 사용자의 데이터에 접근되어야 할 수도 있다. 이런 경우, 애플리케이션은 온라인(online) 접근 모드로 요청할 수 있다. 그 결과, 수명이 제한된 액세스 토큰이 발급되고 재발급 토큰은 발급되지 않는다.


  • 구글은 기본 접근 모드가 'online'이며, 권한 코드가 요청되는 시점에 권한 엔드포인트로 'access_type=offline'이 명시적으로 전달되지 않는 한 재발급 토큰은 발급되지 않는다. 이런경우, 사용자가 "내가 애플리케이션을 사용하지 않을 때, 이 연산들을 수행하라"고 애플리케이션에 권한을 부여하면 경고가 발생한다. 온라인 접근 모드만 가진 애플리케이션이 새로운 권한 코드가 필요하다면 사용자에게 묻지 않고 클라이언트에게 자동으로 발급되고, 서버 간 호출을 통해 애플리케이션이 액세스 토큰으로 교환한다. 

  • 페이스북의 기본 접근 모드는 'online'이다. 생명주가기 제한된 액세스 토큰이 발급되고 재발급 토큰은 발급되지 않는다. 만약 애플리케이션이 오프라인 접근이 필요하면, scope 문자열에 권한에 대한 값으로 'offline_access'를 넣어서 요청하면 된다. 그러면 만료 기간이 무제한인 액세스 토큰이 발급된다. 발급된 토큰은 여전히 사용자가 접근을 취소할 수 있다.


2.5 접근을 어떻게 취소할 수 있는가?

페이스북 같은 일부 API 제공 업체들은 사용자가 비밀번호를 바꿀 때 액세스 토큰을 취소한다.


'프로그램으로 취소하기'는 OAuth 2.0 확장 스펙 초안에 정의되어 있고, 세일즈 포스와 구글처럼 대중적인 OAuth 제공 업체가 사용하고 있다. 세일즈포스는 재발급 토큰과 액세스 토큰의 취소를 허용하고, 구글은 오직 재발급 토큰의 취소만 허용하낟.


curl "https://accounts.google.com/o/oauth2/revoke?token=ya29.AHES6ZSzF



[참고 사이트]

OAuth 2.0 공식 홈페이지

OAUTH 2.0 - OPEN API 인증을 위한 만능 도구상자

네이버 개발자 센터


OAuth로 OPEN API 사용하기 1) 개념 설명 및 웹 사용방법

OAuth로 OPEN API 사용하기 (v1.1a) 2) JAVA에서 라이브러리 사용

OAuth로 OPEN API 사용하기 (v2.0) 3) Facebook API 예제


[SNS 서비스 연동하기 시리즈 1) 페이스북

OAuth2 Authentication: Log In With Facebook Account


## Google

Using OAuth 2.0 for Installed Applications

Accessing Google Services Using the OAuth 2.0 Protocol

GTM OAuth 2: Google Toolbox for Mac - OAuth 2 Controllers

Login with Google using OAuth 2.0 for iOS Xcode Objective-C


## YouTube

OAuth 2.0 Flow : Installed apps


## Daum

OAuth 2.0 참조하기


## Line

Integrating Web Login


[참고 문서]

Getting started with OAuth 2.0 - ORELLY

getting_started_with_oauth_2.0.pdf

Getting started with OAuth 2.0 - 번역서

HANB_Getting_Started_with_OAuth2.pdf



'기타' 카테고리의 다른 글

[Gradle] Gradle 기본  (0) 2018.05.06
[Java] Exception이란?  (0) 2017.08.20
[OSX] 시스템파일 및 숨김파일 표시 또는 숨기기  (0) 2015.08.31
Comments