OAuth 2.0 이해

Security/OAuth 2013.12.29 18:29


The OAuth 2.0 Authorization Framework

http://tools.ietf.org/html/rfc6749

http://oauth.net/2/


OAuth 2.0

OAuth 2.0 logoOAuth 2.0 is the next evolution of the OAuth protocol which was originally created in late 2006. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. This specification is being developed within the IETF OAuth WG and is based on the OAuth WRAP proposal.

Questions, suggestions and protocol changes should be discussed on the mailing list.

Reading the spec

The final version of the spec can be found at http://tools.ietf.org/html/rfc6749.

Implementations

Server Libraries

Client Libraries

Services that support OAuth 2







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

시작하며

모바일의 시대, 플랫폼의 시대가 도래하면서 IT기업에게 open API는 가장 중요한 자산으로 자리잡았다. 어떤 형식으로 API를구성하고 어떤 포맷으로 데이터를 주고받을 것인가에 대한 싸움도 치열했는데, SOAP & XML 과 REST & JSON이 경합을 벌인 끝에 REST & JSON의 승리로 끝났다. 이제 새로 생기는 모든 웹 서비스, 모바일 서비스들은 REST & JSON 기반으로 API를 제공하고 있으며 인증 방식으로는 OAuth 2.0을 택하고 있다.

얼마 전 OAuth 의 메인 에디터인 Eran Hammer 가 자신의 블로그에 자신이 OAuth 2.0 editor를 그만둘 것이며 OAuth 2.0 스펙에서 자신의 이름을 지워 달라는 글을 올렸다. OAuth는 SNS와 모바일 세상에서 가장 중요한 인증 방법으로 자리잡았고 OAuth 2.0은 아직 최종 스펙이 나오지는 않았지만 Facebook, Google 등에서 이미 널리 사용되고 있는 스펙이기에 이 소식은 많은 사람들의 관심을 받았다. 이 글에서는 OAuth에 대한 간단한 소개와 함께 OAuth 2.0에 대한 이야기를 해보려고 한다.

OAuth 1.0a – API 인증을 위한 만능 칼

oauth1
OAuth 를 만들고 활성화 시키는데 기여한 가장 유명한 회사는 트위터다. 트위터를 비롯한 웹 개발자 들이 API의 인증(authentication; 이 사용자가 누구인가)과 권한 부여(authorization; 로그인 한 사용자가 무엇을 할 수 있는가?)를 동시에 제공하는 인증 프로토콜을 찾다가, 결국 적당한 것이 없다고 결론 내리고 새로 만든 것이 OAuth 1.0 이다. OAuth 1.0은 2007년 10월에 확정되었으나 나중에 세션 고정 공격(session fixation attack) 보안 결함이 발견되어 2009년 6월에 이 문제가 개선된 OAuth 1.0a가 발표되었다. OAuth 1.0은 보안 결함이 있는 버전이기 때문에 더 이상 사용해서는 안되는 버전이다. OAuth 1.0a는 2010년 4월에 “The OAuth 1.0 Protocol” 이라는 이름으로 RFC5849 문서 번호를 부여 받으며 IETF 표준이 되었다. RFC 표준이름에는 1.0뒤에 “a”가 붙지 않지만 많은 사람들이 아직도 OAuth 1.0a라고 부른다. 이 글에서도 명확하게 하기 위해 OAuth 1.0a라고 표현하기로 한다.
이 글의 주요 내용은 OAuth 2.0이긴 하지만, 1.0a에 대해서도 간단히 알고 넘어가려고 한다.

OAuth 1.0a의 장점

OAuth 1.0a가 기존의 다른 인증과 구분되는 특징은 크게 두 가지이다. 첫째, API를 인증함에 있어 써드파티 어플리케이션에게 사용자의 비밀번호를 노출하지 않고 인증 할 수 있다는 점. 둘째, 인증(authentication)과 API권한 부여(authorization )를 동시에 할 수 있다는 점이다. OAuth 1.0이 만들어지는 시점에는 써드파티에게 비밀번호를 노출하지 않고 인증하는 방법으로서 이미 Open ID가 있었다. 하지만 Open ID는 API의 권한 부여기능을 가지고 있지 않았고 인증 방법도 OAuth와는 방향이 많이 달랐다.

OAuth 1.0a 동작방식

OAuth 1.0a 가 작동하기 위해서는 기본적으로 유저(user), 컨슈머(consumer), 서비스 프로바이더(service provider)가 있어야 한다. OAuth 1.0a 인증을 3-legged OAuth 라고 부르기도 하는데 OAuth는 둘이서 하는 것이 아니라 셋이서 하는 것이라는 말이다. 간단하게는 각각 유저는 트위터 사용자, 컨슈머는 트위터 단말 어플리케이션, 서비스 프로바이더는 트위터 API 서비스 라고 생각하면 쉽다.

< OAuth 1.0a 트라이앵글>

oauth2_triangle
새로운 트위터 어플리케이션을 앱스토어에서 다운 받았지만, 아직은 어플리케이션을 신뢰할 수 없는 상황이라고 하자. 사용자는 이 어플리케이션에 아이디와 비밀번호를 저장하면 이 어플리케이션이 또 다른 어떤 짓(몰래 아이디/비밀번호를 수집하는 등)을 할 지 모르기 때문에, 어플리케이션에 비밀번호를 저장하고 싶지 않다. OAuth 1.0은 이 경우 트위터 단말 어플리케이션 (consumer)에게 인증토큰(access token)만을 전달하고 단말 어플리케이션이 인증토큰으로 트위터 API(service provider)를 사용할 수 있도록 해준다.

< OAuth 1.0a 인증 프로세스>
oauth2_triangle2

이 과정에서 사용자가 서비스 프로바이더의 API를 사용하겠다고 로그인 할 때, 컨슈머는 서비스 프로바이더의 로그인 화면으로 사용자를 리다이렉트 하게 된다. 이 서비스 프로바이더의 화면은 아래와 같은 정보를 제공한다.
oauth2_screen

사용자가 이 화면에서 로그인을 완료하면 다시 컨슈머로 리다이렉트 되고 동시에 컨슈머는 인증토큰을 사용할 수 있게 된다. 이 인증 토큰은 컨슈머가 사용자의 아이디/패스워드 없이 허가 받은 API에 접근할 수 있게 해준다. 사용자는 컨슈머에 저장되어있는 인증 토큰이 유출 되더라도 서비스 프로바이더의 관리자 화면에서 언제나 그 인증토큰의 권한을 취소(revoke)할 수 있다.
oauth2_screen2

OAuth 1.0a의 인증 과정에서 request token 등 추가적인 개념에 대해서는 이 글에서는 자세히 설명하지 않는다. OAuth 1.0a인증 과정에 대한 자세한 설명은 관련 자료가 많이 있으니 참고하길 바란다.

인증토큰

OAuth 1.0a 인증이 완료가 되면 컨슈머 (예를 들면 트위터 모바일 어플리케이션)은 사용자의 아이디/패스워드를 직접 저장하게 되는 것이 아니라, 인증토큰(access token)을 받게 된다. 이 인증 토큰은 OAuth 2.0에서도 같은 개념으로 사용된다. 인증토큰은 커베로스(Kerberos)의 티켓 개념과 비슷하다라고 할 수 있는데, 아래와 같은 특징을 가진다.

1. 컨슈머가 아이디/패스워드를 가지지 않고 API를 사용할 수 있음
2. 필요한 API에만 제한적으로 접근할 수 있도록 권한 제어 가능
3. 사용자가 서비스 프로바이더의 관리 페이지에서 권한 취소 가능
4. 패스워드 변경 시에도 인증 토큰은 계속 유효함.

자, 그러면 사용자의 스마트폰에 트위터를 인증해 놓은 상태에서, 스마트폰을 분실했을 때, 핸드폰을 습득한 사람이 내 트위터에 접근하지 못하게 하기 위해서 어떻게 해야 할까? 트위터 사이트에서 비밀번호를 바꿔도 트위터 어플리케이션은 계속 사용할 수 있다. 핸드폰을 분실 했다면, 아래와 같이 트위터 관리 페이지에서 어플리케이션 인증을 취소(revoke)하면 된다.
또한, 같은 원리로 트위터 비밀번호를 바꾸어도 내가 트위터 인증을 해놓은 수많은 어플리케이션들과 트위터 내보내기 설정해 놓은 서비스 들에서 다시 인증할 필요 없이 그대로 사용할 수 있다.

OAuth 2.0 – API 인증을 위한 만능 도구상자

oauth2OAuth 2.0은 OAuth 1.0a 와 호환되지 않으며 사용되는 용어부터 시작해서 많은 것들이 다르다. OAuth 1.0a가 만들어지고 어느 정도 지난 후에 IETF 표준이 된 반면에 OAuth 2.0은 거의 초기부터 IETF 표준 프로세스 안에서 만들어지고 있다. OAuth 2.0의 첫 번째 draft가 등록된 것은 2010년 4월 이었고, OAuth 1.0a에서 불편하다고 느꼈던 모바일에서의 사용성 문제나 signature 생성과 같은 개발이 복잡하고 CPU를 많이 소비하는 기능의 단순화, 기능과 규모의 확장성 등을 지원하기 위해 만들어 졌다. 그러기 위해 표준이 매우 커지고 복잡해 졌는데, 이것은 OAuth 1.0a 표준의 정식 명칭이 “OAuth 1.0 프로토콜(The OAuth 1.0 Protocol)“ 인데 반해 OAuth 2.0의 정식 명칙이 “OAuth 인증 프레임웍(The OAuth 2.0 Authorization Framework)” 인 것을 봐도 알 수 있다. 또한 OAuth 1.0은 하나의 RFC문서로 되어있지만, OAuth 2.0은 여러 개의 표준으로 작업이 이루어지고 있으며 그 표준들은 http://tools.ietf.org/wg/oauth/ 에서 확인 할 수 있다. OAuth 1.0a가 인증을 위한 만능 칼 이라면, OAuth 2.0은 인증을 위한 도구상자라고 할 수 있다. 다만 그 안에는 몇몇 위험한 도구들이 섞여있으니 검증된 도구만을 사용해야 하는데 그 안에 무엇이 있는지 알아보자.

OAuth 2.0이 1.0a에서 개선된 부분을 정리해보자

  1. 간단해 졌다.
    OAuth 1.0a에서는 https 가 필수가 아니었기 때문에 API를 호출할 때 signature를 생성해서 호출해야 했다. 때문에 OAuth 1.0a API를 테스트 하려면 curl등을 사용하기 힘들고 별도의 API 콘솔등을 사용해서 테스트 해야 했다. OAuth 2.0의 Bearer 토큰 인증 방식을 쓰면 더 이상 signature 가 필요 없기 때문에 API를 테스트하거나 예제를 만들 때 간단하게 curl등 직관적인 방법을 사용해서 문서화하고 개발 할 수 있게 되었다.
  2. 더 많은 인증 방법을 지원
    OAuth 1.0a는 한가지 인증 방식을 제공한다. HMAC을 이용한 암호화 인증 방식이다. 하지만 OAuth 2.0은 시나리오별로 여러가지 인증 방식을 제공하기 때문에 웹브라우저, 모바일 등의 다양한 시나리오에 대응할 수 있게 해준다.
  3. 대형 서비스로의 확장성 지원
    커다란 서비스를 만들기 위해서는 인증 서버를 분리할 수 있어야 하고 또한 인증 서버를 다중화 할 수 있어야 한다. OAuth 2.0에서는 실제 API 서비스를 하는 서버와 인증 역할을 하는 authorization server의 역할을 명확히 구분함으로서 인증서버의 분리와 다중화 등에 대한 고려가 되어있다.

또한 OAuth 1.0a에서는 사용자(user), 써드파티 어플리케이션(consumer), API 서버(service provider)로 불리우던 것이 OAuth 2.0에서는 용어도 바뀌었다.

  • Resource Owner : 사용자
  • Resource Server : API 서버
  • Authorization Server : 인증서버 (API 서버와 같을 수도 있음)
  • Client : 써드파티 어플리케이션

OAuth 2.0 spec 구성

위 홈페이지에서도 볼 수 있지만, 현재 OAuth 는 oauth-v2 와 oauth-v2-bearer 라는 2개의 표준이 가장 핵심적인 부분이며 현재 RFC에 등록되기 위한 과정을 밟고 있는 중이다. 대부분 “OAuth 2.0 지원”이라고 하는 서비스 들은 이 2가지 spec을 지원한 다는 것을 의미한다. 이 외에도 SAML, JSON 웹 토큰, MAC 토큰 등의 방식이 있지만 아직 활발히 수정 중 이기 때문에 실제 서비스에서 사용되고 있지는 않다.

OAuth 2.0의 버전들

API 서비스를 일찍 시작한 회사들은 기존의 OAuth 1.0a 를 계속 유지하는 경우도 많이 있다. 1.0a와 2.0을 사용하는 유명한 서비스 들은 아래와 같다.
oauth2_provider

OAuth 2.0의 최종 버전이 나오는데 오래 걸리고 있기 때문에 Facebook, Google 등은 OAuth 2.0 spec의 draft 버전이 올라가면서 그 개선사항들을 구현해 오고있다. 현재 최신 draft 는 31버전인데 주요 서비스들이 구현하고 있는 버전들은 아래와 같다.

서비스DRAFT출처
Google22https://developers.google.com/accounts/docs/OAuth2
Facebook12http://developers.facebook.com/docs/authentication/
SalesForce10http://wiki.developerforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com

위 버전들은 서비스가 제공하는 OAuth 인증 페이지에서 수집한 것들이다. 보통 OAuth 2.0 spec의 draft 10 ~ 22 정도를 많이 구현하였는데 중요한 변경사항은 아래와 같은 것이 있다.

  1. HTTP 헤더 앞 부분에 bearer 토큰을 보내기 전에 “OAuth” 에서 “Bearer”로 수정
  2. “oauth_token” 이름이 “access_token” 으로 변경
    위 변경사항 때문에 아직까지는 두 가지를 모두 받아들이는 서비스들이 많다. RFC로 확정이 되면 더 이상은 변경이 불가능 하기 때문에 최종 안으로 정리가 될 것이다.

다양한 인증 방식 (Grant types)

앞에서 OAuth 1.0a가 동작하기 위해서는 사용자, 컨슈머, 서비스 프로바이더가 필요하고 3-legged OAuth 라고 불리우기도 한다고 하였지만, OAuth 2.0은 2-legged 모델 등 다양한 인증 방식을 지원한다. 3-legged 모델의 장점은 최종 사용자 뿐 아니라 개발자가 누구인지도 인증하기 때문에 어떤 어플리케이션이 API를 사용하는지 통계/과금 을 위한 필수적인 정보를 얻을 수 있다는 점이다. user-agent 나 referer 같이 변경될 수 있는 값이 아닌 인증을 통해 확실하게 구분할 수 있기 때문에 개발자가 API를 비정상적으로 호출하고 있다거나 할 때 개발자와 직접 연락하는 등의 조치를 취할 수도 있다. 그럼에도 불구하고 리다이렉트와 같은 OAuth에서 필요로하는 동작이 불가능한 시나리오, 둘이서만 인증하는 시나리오 등을 지원하기 위해 OAuth 2.0은 2-legged 모델도 지원하나, 그래도 OAuth 2.0에서 가장 기본이 되는 것은 3-legged 모델이다.

Client 는 기본적으로 Confidential Client 와 Public Client 로 나뉜다.

  • Confidential 클라이언트는 웹 서버가 API를 호출하는 경우 등과 같이 client 증명서(client_secret)를 안전하게 보관할 수 있는 Client를 의미한다.
  • Public Client는 브라우저기반 어플리케이션이나 모바일 어플리케이션 같이 client 증명서를 안전하게 보관할 수 없는 Client를 의미하는데 이런 경우 redirect_uri 를 통해서 client를 인증한다.

OAuth 2.0이 지원하는 인증방식은 client 종류와 시나리오에 따라 아래 4가지가 있다. 하지만 실제로 Authorization Code Grant와 Implicit Grant를 제외하고는 일반적인 3-legged OAuth 가 아니기 때문에 open API에서는 많이 사용되지 않는다.

  1. Authorization Code Grant
    웹 서버에서 API를 호출하는 등의 시나리오에서 Confidential Client가 사용하는 방식이다. 서버사이드 코드가 필요한 인증 방식이며 인증 과정에서 client_secret 이 필요하다.
    로그인시에 페이지 URL에 response_type=code 라고 넘긴다.
  2. Implicit Grant
    token과 scope에 대한 스펙 등은 다르지만 OAuth 1.0a과 가장 비슷한 인증방식이다. Public Client인 브라우저 기반의 어플리케이션(Javascript application)이나 모바일 어플리케이션에서 이 방식을 사용하면 된다. Client 증명서를 사용할 필요가 없으며 실제로 OAuth 2.0에서 가장 많이 사용되는 방식이다.
    로그인시에 페이지 URL에 response_type=token 라고 넘긴다.
  3. Password Credentials Grant
    이 방식은 2-legged 방식의 인증이다. Client에 아이디/패스워드를 저장해 놓고 아이디/패스워드로 직접 access token을 받아오는 방식이다. Client 를 믿을 수 없을 때에는 사용하기에 위험하기 때문에 API 서비스의 공식 어플리케이션이나 믿을 수 있는 Client에 한해서만 사용하는 것을 추천한다.
    로그인시에 API에 POST로 grant_type=password 라고 넘긴다.
  4. Client Credentials Grant
    어플리케이션 이 Confidential Client일 때 id와 secret을 가지고 인증하는 방식이다.
    로그인시에 API에 POST로 grant_type=client_credentials 라고 넘긴다.
  5. Extension
    OAuth 2.0은 추가적인 인증방식을 적용할 수 있는 길을 열어놓았다. 이런 과도한 확장성을 메인 에디터인 Eran Hammer는 매우 싫어했다고 한다.

Password Credentials Grant와 Client Credentials Grant는 기본적으로 우리가 생각하는 OAuth 의 프로세스를 따르지 않기 때문에 반드시 인증된 client에만 사용되어야 하며 가능하면 사용하지 않는 것이 좋다.

다양한 토큰 지원(Access token)

OAuth 2.0은 기본적으로 Bearer 토큰, 즉 암호화하지 않은 그냥 토큰을 주고받는 것으로 인증을 한다. 기본적으로 HTTPS 를 사용하기 때문에 토큰을 안전하게 주고받는 것은 HTTPS의 암호화에 의존한다. 또한 복잡한 signature 등을 생성할 필요가 없기 때문에 curl이 API를 호출 할 때 간단하게 Header 에 아래와 같이 한 줄을 같이 보내므로서 API를 테스트해볼 수 있다.
Authorization: Bearer

또한 OAuth 2.0은 MAC 토큰과 SAML 형식의 토큰을 지원할 수 있지만 현재 MAC 토큰 스펙은 업데이트 되지 않아 기한 만료된 상태이고 SAML 토큰 형식도 아직은 활발하게 수정중이기 때문에 사용할 수 없는 상태이다. 정리하자면, OAuth 2.0은 다양한 토큰 타입을 지원한지만 실질적으로는 Bearer 토큰 타입만 지원한다.

Refresh token

클라이언트가 같은 access token을 오래 사용하면 결국은 해킹에 노출될 위험이 높아진다. 그래서 OAuth 2.0에서는 refresh token 이라는 개념을 도입했다. 즉, 인증 토큰(access token)의 만료기간을 가능한 짧게 하고 만료가 되면 refresh token으로 access token을 새로 갱신하는 방법이다. 이 방법은 개발자들 사이에서는 논란이 있는데, 토큰의 상태를 관리해야 해서 개발이 복잡해 질 뿐만 아니라 토큰이 만료되면 다시 로그인 하도록 하는 것이 보안 면에서도 안전하다는 의견이 있기 때문이다.

API 권한 제어 (scope)

OAuth 2.0은 써드파티 어플리케이션의 권한을 설정하기 위한 기능이다. scope의 이름이 스펙에 정의되어있지는 않으며 여러 개의 권한을 요청할 때에는 콤마등을 사용해서 로그인 시에 scope를 넘겨주게 된다.

http://example.com/oauth?….&scope=read_article,update_profile

OAuth 2.0은 위험한가?

Eran Hammer가 OAuth 2.0가 형편없다고하며 자신의 블로그에서 제시한 이유는 OAuth 2.0이 너무 복잡하고 안전하지 않다는 점이다. 그는 자신의 블로그에 이렇게 된 이유를 설명하고 있다. OAuth 2.0 스펙에 참가한 사람들은 주로 웹 커뮤니티 멤버들과 대형 기업멤버들로 되어있었다. 웹 관련 멤버들은 OAuth 1.0a와 비슷하되 단점을 개선한 버전을 만들기를 원하는데 반해, 기업 쪽 사람들은 OAuth 2.0을 자신의 솔루션을 위한 인증 framework으로 사용할 수 있도록 유도하며 OAuth 2.0을 너무 복잡하게 만들었고 또 거의 무한한 확장성을 가질 수 있게 하면서 거의 모든 것에 ‘OAuth 2.0 호환’ 딱지를 붙일 수 있게 되었다는 것이다. 그는 OAuth 2.0이 더 간결하고 제한된 스펙이 되기를 원했다. 실제 블로그에서는 “OAuth 1.5 정도의 내용을 가진 새로운 OAuth 2.1이 10page 정도의 짧은 문서로 새로 나왔으면 좋겠다” 라고 했다.

그가 블로그 글에서 지적한 OAuth 2.0의 문제점은 어떤 것들 일까?

  1. OAuth 1.0a에서는 token 과 함께 token 비밀번호를 같이 받는데 2.0에서는 이 토큰 비밀번호가 없어져서 실제로 클라이언트를 구분하기가 힘들어 졌다.
  2. OAuth 1.0a의 signature 기능을 없애서 SSL 기능에 의존함으로서 더 위험해졌다. 또한 이렇게 된 것은 기업 솔루션에 적용 되기위한 것이었다.
  3. OAuth 2.0에서 토큰 유효기간을 설정 할 수 있고 또 만료가 되면 갱신 되어야 한다. 이 변화는 OAuth 1.0 개발자들이 토큰 상태까지 관리해야 한다는 점에서 매우 커다란 변화이다. 이 기능은 자체적으로 인코딩 되어서 저장되는 토큰을 위한 것인데 이런 토큰은 권한을 취소(revoke) 하는데에 문제가 있기 때문에 또 다시 유효기간을 짧게 가져가게 된다.
  4. 권한 부여 방식
    OAuth 2.0에서는 너무 많은 방식을 지원 하고있다. 이는 여러 보안상의 문제점의 가능성을 의미한다.
    또한 OAuth 2.0을 IETF에서 시작한 것을 후회하는 말도 하면서, 그렇다고 딱히 다른 대안이 있는 것도 아니라는 의견도 밝힌다. 현재 워킹 그룹이 합의를 하지 못하고 있는 사항들에 리스트도 적었는데, 그만큼 OAuth 2.0스펙이 너무 포괄적이며 스펙은 더 많은 제한을 가지고 있고 많은 것이 결정되어있어야 한다는 이야기라고 그는 계속 주장 한다

위 글에 대한 반박 글은 참 많지만 그 중에 유명한 것은 아래 2개이다.

위 글에서는 OAuth 2.0의 장점들과 실질적으로는 OAuth 2.0 워킹 그룹이 잘 해나가고 있다는 내용의 글들이다. Eran Hammer는자기 자신의 첫 번째 글이 커다란 반향을 일으키자, 내용을 어느 정도 개선한 두 번째 글을 쓰기도 했다. 이 글에서 몇몇 OAuth 2.0을 잘 받아들인 단체들을 언급하면서, Facebook이나 Google은 OAuth 2.0이 직접 내렸어야 하지만 내리지 못한 결정들을 직접 내리고 OAuth 2.0을 성공적으로 구현했다고 이야기 하고있다. 하지만 그는 자신의 신념에는 변화가 없다는 뜻을 다시 한번 비추었다. 즉 OAuth 2.0이 명확하게 정의하지 않을 부분을 잘 구현한다면 OAuth 2.0은 꽤 쓸만한 표준이나, Eran Hammer는 현재의 OAuth 2.0은 너무 많은 부분들을 허용하고 있고 복잡하기 때문에 안전하지 않다고 주장한 것이다.

정리하자면, 가장 많이 사용되는 Grant type인 Authorization Code 방식이나 Implicit 방식을 사용하고 access token으로서는 Bearer 토큰을 사용하며 HTTPS를 통해서 서비스하고 널리 사용되는 라이브러리들을 사용해서 구현한다면 OAuth 2.0은 안전하다고 할 수 있다. 다만 아직 표준 진행중인 토큰 방식을 사용하거나 자신만의 Extension을 정의해서 사용하는 경우도 OAuth 2.0이라고 부를 수는 있지만 아직은 안전하지 않다고 할 수 있다.

OAuth 2.0에 대한 예상질문

이상 OAuth 2.0에 대해서 알아보았다. 마지막으로 간단한 몇 가지 사항을 짚어보자

1. SSL을 사용하지 않는 bearer 토큰은 안전하지 않나?
안전하지 않다. MAC token을 사용할 수 있지만 OAuth 2.0에서는 실질적으로 관리되고 있지 않은 스펙이다. OAuth 2.0을 이용한 API 호출에는 반드시 HTTPS를 사용해야 한다.

2. API를 서비스하는데 HTTPS를 쓸 수 없는 상황이다. 어떻게 해야 하는가?
그런 경우라면 현 시점에서는 OAuth 1.0a 를 사용하는 것이 최선이다. 아직 OAuth 2.0 스펙은 자체 암호화를 지원하지 않는다.

3. OAuth 2.0의 대안이 있는가?
의미있는 대안은 현재 없다. Facebook, Google 등이 모두 API 인증방식으로OAuth 2.0을 채택했기 때문에 대세는 이미 OAuth 2.0이다.

4. API 사용자를 생성하는 좋은 방법은?
이 이슈는 API의 고전적인 이슈 중 하나이다. API인증을 하기위한 사용자를 생성하는 API는 어떻게 인증해야 하는가에 대한 이야기 이다. API를 사용해서 사용자를 생성한다면, CAPCHA 등의 방법을 사용할 수 없기 때문이다. 보통 다양한 조건체크, email 확인 등의 방법을 사용하기도 하지만, 가능하면 사용자 추가는 그냥 웹 브라우저상에서 직접 하도록 하는 것이 정답이다.

마무리 하며

암호 기술과 함께 인터넷상에서 인증 관련 기술들은 매우 빠르게 발전하고 있다. 최근에는 SHA-3 해쉬 알고리즘이 기나긴 선정과정을 걸쳐 최종 선정되는 커다란 뉴스가 있었고API인증에 있어서도 OAuth 2.0 뿐만 아니라 openid 진영의OpenID Connect 도 활발히 활동하고 있다. 많은 우여곡절 속에서 OAuth 2.0 spec은 최종안을 위해서 달려가고 있는데 예상보다 많은 시간이 걸리고 있고 또 잡음이 있다는 것은 그만큼 많은 사람들과 기업들에게 OAuth 2.0가 중요하고 많은 기대를 하고 있다는 것을 말해준다.

OAuth 2.0의 기본 스펙은 안전하다. 다만 스펙에 참여하고 있는 일부 기업들의 욕심으로 생긴 일부 추가적인 기능들과 방향성에 논란이 있는 상황이다. 이슈가 되는 Refresh 토큰이나 추가기능을 제공하는 extension, 그리고 아직 RFC 단계에 있지 않은 스펙 들 때문에 OAuth 2.0전체가 안전하지 않다고 할 수는 없다. HTTP 1.1스펙의 PATCH 나 HEAD 메소드는 거의 사용되지 않지만 그렇다고 HTTP 1.1 의 GET/POST 메소드 까지 버릴 수는 없지 않을까?

AES나 SHA-3 등과 같은 암호화 알고리즘이 NIST같은 미국 정부기관의 주도로 정해지는 것과 달리 OAuth 는 IETF의 열린 프로세스에 따라서 스펙이 결정되고 메일링 리스트를 통해서 주로 토론이 이루어진다. 이 글을 쓰면서 인터넷 실명제 위헌 판결에 따라서 개인 인증에 대한 중요성이 부각되고 있는 우리나라에서 인터넷에서의 주민번호 대체품으로서 한국 정부가 OAuth 프로바이더를 만드는 것은 어떨까 하는 상상도 해보았다. 더 많은 사람들이 OAuth 2.0등의 열린 인증방법에 관심을 가지고 더 많은 자료들이 API를 통해 공개되고, 또 안전하게 접근할 수 있는 날이 오기를 기대해 본다.

참고자료


출처 - http://earlybird.kr/1584






OAuth 정의
OAuth란 Open API로 개발된 표준 인증 방식으로, 각종 애플리케이션에서 사용자 인증을 할 때 활용될 수 있습니다. OAuth가 사용되기 전에는 인증방식의 표준이 없었기 때문에 기존의 기본인증인 아이디와 비밀번호를 사용하였는데 이 경우는, 아이디와 비밀번호로 인증을 받았기 때문에 정보유출의 위험성을 가지고 있었습니다.

OAuth 인증방식을 사용하면 기존의 아이디/비밀번호를 이용하여 인증을 받는 방식이 아니라 접근 권한을 인증 받는 데 필요한 정보가 담겨있는 '토큰'으로 인증을 받게 되는 방식입니다. 서비스 제공자는 소비자들에게 요청토큰을 발급해 주어야 하고 소비자들은 이 요청토큰을 이용하여 사용자정보에 접근하게 됩니다.



OAuth 용어 정리
  • • 사용자 (User) : 서비스 공급자 (Service Provider) 계정을 가지고 있으면서, 소비자 (Consumer) 를 이용하려는 사용자 (2.0 에서 Resource Owner로 변경)
  • • 소비자 (Consumer) : Open API를 이용하여 개발된 OAuth를 사용하여 서비스 제공자에게 접근하는 웹사이트 (2.0 에서 Client로 변경)
  • • 서비스 공급자 (Service Provider) : OAuth를 통해 접근을 지원하는 웹 (Open API를 제공하는 서비스) 
       (2.0 에서 Resource Server (API 서버) 또는 Authorization Server (인증 서버, API 서버와 같을 수 있음) 로 변경)
  • • 소비자 비밀번호 (Consumer Secret) : 서비스 제공자에서 소비자가 자신임을 인증하기 위한 키
  • • 요청토큰 (Request Token) : 소비자가 사용자에게 접근권한을 인증 받는 데 필요한 정보가 담겨있으며 후에 접근 토큰으로 변환된다
  • • 접근토큰 (Access Token) : 인증 후에 사용자가 서비스 제공자가 아닌 소비자를 통해 보호된 자원에 접근하기 위한 키를 포함한 값


  • OAuth2.0 인증방식
  • 1. Authorization Code Grant
  • • 웹 서버에서 API를 호출하는 등의 시나리오에서 Confidential Client가 사용하는 방식입니다. 서버사이드 코드가 필요한 인증 방식이며, 인증 과정에서 client_secret 이 필요합니다. 로그인 시에 페이지 URL에 response_type=code 라고 넘깁니다.
  • 2. Implicit Grant
  • • token과 scope에 대한 스펙 등은 다르지만 OAuth 1.0a과 가장 비슷한 인증방식입니다. Public Client인 브라우저 기반의 (Javascript application)이나 모바일에서 이 방식을 사용하면 됩니다. Client 증명서를 사용할 필요가 없으며 실제로 OAuth 2.0에서 가장 많이 사용되는 방식입니다. 로그인시에 페이지 URL에 response_type=token이라고 넘깁니다.
  • 3. Password Credentials Grant
  • •  이 방식은 2-legged 방식의 인증입니다. Client에 아이디/패스워드를 저장해 놓고 아이디/패스워드로 직접 access token을 받아오는 방식입니다. Client를 믿을 수 없을 때에는 사용하기에 위험하므로 API 서비스의 공식이나 믿을 수 있는 Client에 한해서만 사용하는 것을 추천합니다. 로그인 시에 API에 POST로 grant_type=password라고 넘깁니다.
  • 4. Client Credentials Grant
  • • 애플리케이션이 Confidential Client일 때 id와 secret을 가지고 인증하는 방식입니다. 로그인시에 API에 POST로 grant_type=client_credentials이라고 넘깁니다.



    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)
    
    (A) 클라이언트는 접근이 승인되면, 클라이언트 식별자, 요청범위, 인증서버가 User-Agent를 이동시킬 Redirection URI 등을 포함하고 있음
    (B) 인증서버는 리소스 소유자 인증 및 클라이언트 권한 요청에 대한 거부 여부를 지정함
    (C) 리소스 소유자에 대한 접근이 허용됐다는 가정에 따라 인증서버는 (요청 또는 클라이언트 등록 시) 제공받은 클라이언트 Redirection URI로 user-agent를 Redirect함.
    => Redirection URI는 인증코드를 포함 
    (D) 클라이언트는 이전 단계에서 받은 인증코드를 포함하여 인증 서버의 토큰 엔드포인트에게 접근 토큰을 요청함
    => 클라이언트는 인증 코드를 얻기 위한 Redirection URI와 인증 코드가 필요
    (E) 인증 서버는 클라이언트를 인증하고 인증코드를 검증하며, 이때 받은 Redirection URI가 (C) 단계에서의 Redirection URI와 일치하는지 확인함
    => 유효한 경우에 한하여 인증서버는 접근 토큰으로 응답, 이때 리프레쉬 토큰도 함께 올 수도 있음



    Client Credentials Grant 인증과정
    +---------+                                  +---------------+
    |         |                                  |               |
    |         |>--(A)- Client Authentication --->| Authorization |
    | Client  |                                  |     Server    |
    |         |<--(B)---- Access Token ---------<|               |
    |         |                                  |               |
    +---------+                                  +---------------+
    
    (A) 클라이언트는 인증서버를 인증하고, 토큰 엔드포인트에게 접근 토큰을 요청
    (B) 인증서버는 클라이언트를 인증하고, 유효한 경우 접근 토큰을 발급



    Password Credentials Grant 인증과정
    +----------+
    | Resource |
    |  Owner   |
    |          |
    +----------+
         v
         |    Resource Owner
        (A) Password Credentials
         |
         v
    +---------+                                  +---------------+
    |         |>--(B)---- Resource Owner ------->|               |
    |         |         Password Credentials     | Authorization |
    | Client  |                                  |     Server    |
    |         |<--(C)---- Access Token ---------<|               |
    |         |    (w/ Optional Refresh Token)   |               |
    +---------+                                  +---------------+
    
    (A) 리소스 소유자가 클라이언트에게 사용자이름과 비밀번호를 제공
    (B) 클라이언트는 리소스 소유자에게서 받은 정보를 이용하여 인증서버의 토큰 엔드포인트에게 접근 토큰을 요청하며, 이 때, 클라이언트가 인증서버를 검증
    (C) 인증서버는 클라이언트를 인증하고, 리소스 소유자의 정보가 유효한지 확인하며, 만약 유효하다면 접근 토큰을 발급



    OAuth1.0의 문제점
  • •  인증과 signature 생성이 너무 복잡하여 구현하기 어려운 부분이 있습니다.
  • •  브라우저나 URL등으로 간단한 도구 테스트를 할 수 없습니다. (대부분 해당 언어의 Library를 찾아야 함)
  • •  인증을 얻기 위한 과정을 변화된 환경 (접속환경) 에 맞게 개선/정리할 필요가 있습니다.


  • OAuth2.0에서 개선된 사항
  • •  브라우저가 아닌 비 브라우저 타입의 클라이언트에서 인증하기 위한 매끄러운 인증과정을 제공합니다.
  • •  클라이언트에서 암호화를 위한 코드 삽입이 불필요합니다.
  • •  signatures 지원을 훨씬 단순화 하였습니다.
  • •  접근토큰을 간단히 리프레쉬할 수 있는 기능을 추가 하였습니다.
  • •  1.0과 호환성을 제공하지 않습니다.
  • •  protected 된 자원에 접근할 때 무조건 https를 사용합니다.

  • 조금 더 간단히 얘기하면, 인증을 통해 접근토큰을 발급받은 이후에는 https와 access_token parameter의 인증만으로 protected 된 자원에 접근할 수 있게 하겠다는 의미입니다. (접근토큰을 얻기까지의 과정은1.0보다 단순하지만 비슷한 형태를 보이고 있음.)



    Gaia OAuth
    Gaia는 Open API를 활용한 개발 도중 부분적으로 필요했던 "인증" 의 불편함을 해결하고자 OAuth 2.0 프레임워크 중 Authorization Code Grant 방식과 Credentials Grant방식을 지원합니다. Gaia는 현재 접근토큰과 리프레쉬 토큰을 이용한 인증이 가능하며, 비밀번호를 이용한 인증을 지원할 예정입니다.
    • Authorization Code Grant : 일반적인 사용자가 접근토큰을 얻기 위한 인증 방식입니다. 3-legged 방식으로 인증코드 발급 단계를 거치며, 인증 완료 시 접근토큰과 리프레쉬 토큰을 발급받습니다.
    • Credentials Grant : 애플리케이션 개발자가 Authorization code 발급 단계를 거치지 않고 바로 접근토큰을 얻기 위한 인증 방식입니다. 2-legged 방식의 인증방식으로 master_secret 값을 이용하며, 인증 완료 시 접근토큰(master_token)과 리프레쉬 토큰을 발급받습니다.
       - 해당 방식으로 부여 받은 토큰은 애플리케이션 개발자임을 나타내며, 애플리케이션 관리자의 roles 권한을 부여 받습니다. 또한, 해당 애플리케이션 노드에 대해 모든 권한을 가집니다.
    • Password Grant : 2-legged 방식의 인증방식으로 애플리케이션에 로그인한 사용자의 아이디/패스워드로 직접 접근 토큰을 받아 오는 방식입니다.
       - 애플리케이션 등록 시 '공개키 생성'을 통해 발급받은 공개키를 이용해 패스워드를 암호화해 전달합니다.
       - 공개키 갱신 시 기존에 사용하던 공개키를 교체해 주어야 합니다.
    » 접근토큰 만료시간 문제 해결을 위해 리프레쉬 토큰을 사용하며, 접근토큰이 중단 될 경우, 리프레쉬 토큰의 수명이 유효한 경우에 한하여 접근토큰을 갱신해줍니다 .
    » 단, 리프레쉬 토큰의 수명은 7일이며, 접근토큰의 수명은 3시간 (10,800초) 입니다. 접근토큰을 일정 시간을 기준으로 갱신하여 토큰을 하이잭킹 당하거나, 분실 시 토큰을 폐기하고 재 발행해 보안을 높일 수 있습니다.
    • Revoke : 발급 받은 토큰을 만료 시킵니다.(사용자를 로그아웃 시킵니다.)



    Gaia OAuth Parameter
    이름필수여부설명
    client_idtrue클라이언트를 식별하기 위한 클라이언트 아이디
    client_secrettrue발급 받은 client_secret 또는 master_secret
    codetrueAuthorization시 발급받은 코드
    grant_typetrue인증 방식을 구분(authorization_code, refresh_token, client_credentials, password)
    redirect_uritrueRedirect URI
    refresh_tokentrueaccess_token과 함께 발급받은 refresh_token, access_token 갱신 시 함께 갱신됨
    response_typetrue값은 오직 "code"만 가능
    token_typefalse값은 오직 "Bearer"만 가능하며, access_token을 문자열로 제공하고 사용
    access token 발급시 확인 가능하며, REST API 사용시 Http header 내에 access_token을 포함하여 전달 하고 싶을 때 필요
    workspace_idtrue클라이언트가 접근하려는 워크스페이스 아이디
    usernametrue사용자 아이디
    passwordtrue암호화된 사용자 비밀번호

    • Authorization Code Grant
    이름설명
    client_id클라이언트를 식별하기 위한 클라이언트 아이디
    workspace_id클라이언트가 접근하려는 워크스페이스 아이디
    redirect_uri- Redirect URI
    - authorization 또는 access_token 발급 시 필요
    response_type- 값은 오직 "code"만 가능
    - authorization 시 필요
    code- Authorization시 발급받은 코드
    - access_token 발급 시 필요
    client_secret- 발급 받은 client_secret
    - access_token 발급 또는 갱신 시 필요
    grant_type- 인증 방식을 구분
    - access_token 발급 또는 갱신 시 필요
    - token 발급 시 grant_type 값 : authorization_code
    - token 갱신 시 grant_type 값 : refresh_token
    refresh_token- access_token과 함께 발급받은 refresh_token 
    - access_token 갱신 시 필요

    • Credentials Grant
    이름설명
    client_id클라이언트를 식별하기 위한 클라이언트 아이디
    workspace_id클라이언트가 접근하려는 워크스페이스 아이디
    client_secret발급 받은 master_secret
    grant_type- 인증 방식을 구분
    - grant_type 값 : client_credentials

    • Password Grant
    이름설명
    client_id클라이언트를 식별하기 위한 클라이언트 아이디
    workspace_id클라이언트가 접근하려는 워크스페이스 아이디
    client_secret발급 받은 client_secret
    grant_type- 인증 방식을 구분
    - grant_type 값 : password
    username사용자 아이디
    password암호화된 사용자 비밀번호

    • Revoke
    이름설명
    client_id클라이언트를 식별하기 위한 클라이언트 아이디
    client_secret발급 받은 client_secret
    workspace_id클라이언트가 접근하려는 워크스페이스 아이디
    access_token발급 받은 access_token



    참고
    Gaia의 인증은 The OAuth 2.0 Authorization Framework draft-ietf-oauth-v2-31 문서를 참고하고 있으며, 자세한 사항은 해당 문서를 통해 확인할 수 있습니다. 


    출처 - http://gaia.i-on.net/start/docs.do?page=document/workspace/oauth






    TISTORY OAuth 인증이란?

    TISTORY는 Open API를 활용한 개발 도중 부분적으로 필요했던 "인증"의 불편함을 해소하고자 OAuth 2.0 프로토콜을 지원합니다.

    1. Server-side flow (JSP, PHP) - Authorization code 방식

    JSP/Servlet, PHP등과 같은 Server-side 프로그래밍으로 인증을 구현할 경우 사용하기 적합한 인증 방식입니다.

    01. 인증에 필요한 티스토리의 인증 요청용 URL 2가지
    • 인증요청 URL : https://www.tistory.com/oauth/authorize
    • access_token 발급 요청 URL : https://www.tistory.com/oauth/access_token
    02. 인증 요청 단계 (client -> Tistory)

    티스토리에게 최초로 클라이언트(=컨슈머)가 인증을 요청합니다.

    • URL : https://www.tistory.com/oauth/authorize
    • Parameter :client_id : 등록시 발급받은 client_id
      redirect_uri : 등록시 등록한 redirect_uri
      response_type : "code" 라고 입력
    • ex)https://www.tistory.com/oauth/authorize?client_id=abcdefghijklmnopqrstuvwxyz&redirect_uri=http://client.redirect.url&response_type=code

    html 예)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <html>
    <head>
        <title>Tistory OAuth 2.0 JSP Sample - Example Authorization Code </TITLE>
    </head>
    <body>
        <form method="GET" action="https://www.tistory.com/oauth/authorize/">
            <input type="hidden" name="client_id" value="{발급 받은 client_id}"/>
            <input type="hidden" name="redirect_uri" value="{등록시 입력한 redirect uri}"/>
            <input type="hidden" name="response_type" value="code"/>
            <button type="submit">Request Athorization Code</button>
        </form>
    </body>
    </html>
                            
    03. 인증 확인 및 Authorization code 발급 (Tistory -> client)
    1. 1)티스토리가 클라이언트로 부터 1번단계인 인증 요청을 받으면, 등록되어 있는 client_id와 redirect_uri의 정보가
      유효한지 확인한후, 유효하다면 즉시 User Login을 유도합니다.
    2. 2)Login 성공과 함께 유저가 연결에 동의를 하면 Authorization code를 발급하고, 다음 단계를 기다립니다.
    3. 3)발급은 클라이언트 등록시 입력한 redirect_uri 로 보냅니다.
    • URL : http://${redirect_uri}/?code=${authorization_code}
    • Parameter :code : 티스토리가 발급하는 Authorization code입니다.
      이 값은 클라이언트가 Access Token을 받을때 까지 잘 유지 해야합니다.
      이 code는 1시간 뒤 expire 되고, 한번 사용한 값은 재사용이 불가능합니다.
    • ex)http://client.redirect.url?code=1234567890
    • 만약 파라미터가 유효하지 않거나 여타 다른 오류가 발생할 경우 에러메세지를 redirect_uri에 실어 보냅니다.
      자세한 명세는 '에러' 부분을 참조해주세요
    04. 인증 허가 및 Access Token 발급 요청 단계 (client -> Tistory)
    1. 1)티스토리는 최초 인증을 요청한 클라이언트가 유효한 클라이언트인지 검증을 합니다.
    2. 2)발급한 code와 등록시 발급된 client_secret 이 유효한지 검증을 합니다.
    3. 3)2번단계에서 받은 code 를 이 요청에 같이 실어 보내야합니다.
    • URL : https://www.tistory.com/oauth/access_token
    • Parameter :client_id : 등록시 발급 받은 client_id
      client_secret : 등록시 발급 받은 client_secret
      rediret_uri : 등록시 등록한 redirect_uri
      code : 2번단계에서 발급받은 Authorization code
      grant_type : authorization_code 라고 입력
    • ex)https://www.tistory.com/oauth/access_token?client_id=abcdefghijklmnopqrstuvwxyz&client_secret=zxcvbnmasdfghjlk&redirect_uri=http://client.redirect.uri&
      code=1234567890&grant_type=authorization_code

    php 예)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
     
        $authorization_code = $_REQUEST['code'];
     
        $client_id = '{발급받은 client_id를 입력}"';
        $client_secret = '{발급받은 client_secret을 입력}';
        $redirect_uri = '{등록시 입력한 redirect uri를 입력}';
        $grant_type = 'authorization_code';
     
        $url = 'https://www.tistory.com/oauth/access_token/?code=' . $authorization_code .
                '&client_id=' . $client_id . '&client_secret=' . $client_secret .
                '&redirect_uri=' . urlencode($redirect_uri) . '&grant_type=' . $grant_type;
     
        $access_token = file_get_contents($url);
        echo $access_token;
     
    ?>
    05. Access Token 발급 (Tistory -> client)
    1. 1)티스토리는 client_secret과 redirect_uri 가 유효한지 검증을 합니다.
    2. 2)또한 code는 재사용되지 않았는지, expire되지 않았는지도 확인을 합니다.
    3. 3)기타 모든 항목값과 일치하게 되면 Access Token이 발급이 완료됩니다.
    • URL : http://${redirect_uri}/?access_token=${access_token}
    • 만약 파라미터가 유효하지 않거나 여타 다른 오류가 발생할 경우 에러메세지를 redirect_uri에 실어 보냅니다.
      자세한 명세는 '에러' 부분을 참조해주세요
    06. Access Token 획득
    1. 1)티스토리로 부터 최종적으로 Access Token 을 발급받습니다.
    2. 2)클라이언트는 반드시 이 토큰을 노출의 위험이 없도록 보안에 주의를 기울여야 합니다.
    07. 에러
    1. 1)만약 어떠한 상황이되었든 유저인증이나 에러가 발생하면 아래와 같이 응답합니다.
    2. 2)에러가 발생하면 등록된 redirect_uri로 에러메세지를 실어서 보냅니다.
    • URL : http://${redirect_uri}/?error=${error}&error_reason=${error_reason}
    • Parameter :error : OAuth 2.0 명세에 정의된 error유형들에 대한 정해진 code값들입니다.
      error_reason : 해당 에러에 대한 원인이나 이유입니다.

    2. Client-side flow (Javascript, Desktop app) - Implicit Grant

    Javascript 등을 이용해 클라이언트 브라우저등에서만 모든 처리가 이루어지는 요청에 활용할수 있습니다.

    01. Authorization 요청 단계 (client -> Tistory)
    1. 1)티스토리에게 최초로 클라이언트(=컨슈머)가 인증을 요청합니다.
    2. 2)server-side flow와 비교하면 response_type 의 값만 다릅니다.
    • 인증요청 URL : https://www.tistory.com/oauth/authorize
    • Parameter :client_id : 등록시 발급받은 client_id
      redirect_uri : 등록시 등록한 redirect_uri
      response_type : "token" 이라고 입력
    • ex)https://www.tistory.com/oauth/authorize?client_id=abcdefghijklmnopqrstuvwxyz&redirect_uri=http://client.redirect.url&response_type=token

    html/javascript 예)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <html>
    <head>
        <title>Tistory OAuth 2.0 Sample - Example Implicit Grant </TITLE>
    </head>
    <body>
        <script>
            if (window.location.hash) {
                alert(window.location.hash.substring(1));
            }
        </script>
        <form method="get" action="https://www.tistory.com/oauth/authorize/">
            <input type="hidden" name="client_id" value="{발급받은 client_id를 입력}"/>
            <input type="hidden" name="redirect_uri" value="{등록시 입력한 redirect uri를 입력}"/>
            <input type="hidden" name="response_type" value="token"/>
            <button type="submit">get access_token!</button>
        <form>
    </body>
    </html>
                            
    02. AccessToken 발급 (Tistory -> client)

    티스토리는 Implicit Grant 인증요청을 받으면 유저를 로그인을 할수있도록 유도 한 후
    로그인에 성공하면, URL에 #access_token= 과 expires_in를 붙혀서 다시 Redirect 시킵니다.
    expires_in 는 access_token의 만료시간을 뜻하며 초단위 입니다.

    • URL : http://${redirect_uri}#access_token={$accss_token}&expires_in=3600
    • ex)http://client.redirect.uri#access_token=1z2x3c4v5b6n7m8z
    03. AccessToken 발급 (Tistory -> client)

    티스토리로 부터 최종적으로 Access Token 을 발급받습니다. 브라우저의 URL로 바로 읽어 들일 수있으며,
    클라이언트는 반드시 이 토큰을 노출의 위험이 없도록 보안에 주의를 기울여야 합니다.



    출처 - http://www.tistory.com/developer/oauth.php






    92 out of 124 rated this helpful Rate this topic

    Live Connect implements the OAuth 2.0 protocol to authenticate users. This topic describes both the authorization flows that Live Connect uses and the supported extension parameters.

    In this topic, we assume that you are familiar with OAuth 2.0 and OAuth terminology. If you're new to OAuth, we recommend that you check out the OAuth 2.0 spec first, or refer to it when you come across a term or idea that's unfamiliar to you.

    Supported OAuth flows

    Live Connect supports the following authorization flows:

    Implicit grant flow

    The implicit grant flow can be used by both web-based and desktop apps. In this flow, the client makes an authorization request to https://login.live.com/oauth20_authorize.srf with request_type=token. This is a standard OAuth 2.0 flow and is defined in detail in the Implicit Grant section of the OAuth 2.0 spec.

    The following diagram illustrates how the implicit grant flow works.

    OAuth 2.0 implicit grant flow diagram.
    1. The client starts the flow by directing the resource owner's user agent to the Live Connect authorization endpoint, by using a URL in the following format.

      https://login.live.com/oauth20_authorize.srf?client_id=CLIENT_ID&scope=SCOPES&response_type=token&redirect_uri=REDIRECT_URI
      

      This URL contains the client ID, requested scopes, and a redirection Uniform Resource Identifier (URI) to which the authorization web service sends the user agent after access is granted or denied.

      Note  Do not include the wl.offline_access scope if you're using the implicit grant flow (response_type=token).

    2. The user is prompted for his or her sign-in credentials, and grants or denies the client's access request.

    3. Assuming that the user has granted access, the Live Connect authorization server redirects the user agent to the client by using the redirection URI that was provided in the initial request. The redirection URI includes an access token in the URI fragment. For example:http://contoso.com/Callback.htm#access_token=ACCESS_TOKEN.

    4. The user agent follows the redirection instructions by making a request to the Contoso web server. The user agent retains the URI fragment locally, but does not include it in the request to the server.

    5. The Contoso server returns a webpage (typically an HTML document that contains an embedded script) that is capable of accessing the full redirection URI, including the fragment that was retained by the user agent. The script can also extract the access token and other parameters that are contained in the fragment.

      The user-agent locally executes the script that was provided by the web server, to extract the access token and pass it to the client.

    Top

    Authorization code grant flow

    In the authorization code grant flow, the client makes authorization requests by using request_type=code. It is a standard OAuth 2.0 flow, and is defined in full detail in the Authorization Code Grant section of the OAuth 2.0 spec. For further details, see Server-side scenarios.

    The following diagram illustrates how the authorization code grant flow works.

    OAuth 2.0 authorization code grant flow diagram.
    1. The client starts the flow by directing the resource owner's user agent to the Live Connect authorization endpoint, by using a URL in the following format.

      https://login.live.com/oauth20_authorize.srf?client_id=CLIENT_ID&scope=SCOPES&response_type=code&redirect_uri=REDIRECT_URI
      

      This URL contains the client ID, requested scopes, and a redirection URI to which the authorization web service sends the user agent after access is granted or denied.

    2. The authorization server authenticates the resource owner via the user agent, and establishes whether the resource owner grants or denies the client's access request.

    3. Assuming that the resource owner has granted access, the Live Connect authorization server redirects the user agent to the client by using the redirection URI that was provided in the initial request.

    4. The user agent calls the client with the redirection URI, which includes an authorization code and any local state that was provided by the client. For example: http://contoso.com/Callback.htm?code=AUTHORIZATION_CODE.

    5. The client requests an access token from the authorization server's token endpoint by using its client credentials for authentication, and includes the authorization code that was received in the previous step. The client includes the redirection URI that was used to obtain the authorization code for verification. The request URL has the following format:

      POST https://login.live.com/oauth20_token.srf
      
      Content-type: application/x-www-form-urlencoded
      
      client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&client_secret=CLIENT_SECRET&code=AUTHORIZATION_CODE&grant_type=authorization_code
      

      The Live Connect authorization server validates the client credentials and the authorization code, and ensures that the redirection URI that was received matches the URI that was used to redirect the client in step 3.

    6. If the credentials are valid, the authorization server responds by returning an access token. If thewl.offline_access scope was requested, then a refresh token is also returned. To refresh the access token, the client must make a request to the following URL.

      POST https://login.live.com/oauth20_token.srf
      
      Content-type: application/x-www-form-urlencoded
      
      client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
      

      To make things easier for developers of desktop and mobile apps, the Live Connect OAuth 2.0 implementation provides the following special redirect URL: https://login.live.com/oauth20_desktop.srf. This enables apps that can host a web browser control (such as a Java app, Cocoa app, or .NET app) to handle redirects after the user has provided consent, by listening for when the user is redirected to https://login.live.com/oauth20_desktop.srf#access_token=ACCESS_TOKEN, and then retrieving the access token from the end of the URL using whatever mechanisms are available in the chosen client platform. Because apps must also refresh access tokens, the Live Connect app management site allows apps to be marked as mobile client apps. When this marker is specified and the special redirect URL (https://login.live.com/oauth20_desktop.srf) is used, the client secret is not required to refresh the access token. In that case, the URL for refreshing the access token looks like this.

      POST https://login.live.com/oauth20_token.srf
      
      Content-type: application/x-www-form-urlencoded
      
      client_id=CLIENT_ID&redirect_uri=https://login.live.com/oauth20_desktop.srf&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
      
      

    Top

    Sign-in control flow

    The sign-in control flow is unique to Live Connect. It uses the Live Connect sign-in control to simplify sign-in and consent for apps. Intended for use by browser-based apps, it does not require the app to use any server-side logic. You start the flow by using the JavaScript API (the WL.login method) or by embedding an HTML control (by calling the WL.ui method), rather than by calling the consent service directly by using an HTTP request. The sign-in control flow is the only web flow that supports seamless, single sign-in across Live Connect and non-Microsoft web apps. Single sign-in is the mechanism by which a user who is already signed in to Live Connect can go to a different website and be automatically signed in to that site, based on the Live Connect account. The user has control over this sign-in behavior on each website, on an opt-in basis.

    The sign-in control flow is a variation of the implicit grant flow. The key difference between the two is that the sign-in control flow is implemented by using an invisible HTML iframe element that is embedded in the client webpage, and the implicit grant flow must be implemented by the client app.

    Important  Because the sign-in control flow requires no server-side processing, apps can access user info only after the page has loaded.

    The sign-in control flow works as follows:

    1. The client starts the flow by directing the resource owner's user agent to the Live Connect authorization endpoint, by using a URL with the following format:https://login.live.com/oauth20_authorize.srf?client_id=CLIENT_ID&
 scope=SCOPES&response_type=code&redirect_uri=REDIRECT_URI.

      This URL contains the client ID, requested scopes, local state, and a redirection URI to which the authorization web service sends the user agent after access is granted or denied.

    2. The user is prompted for his or her credentials, and grants or denies the client's access request.

    Top

    OAuth authorization request parameters

    The following table lists the OAuth authorization request parameters that are used by Live Connect.

    ParameterNotes

    client_id

    The app's client ID.

    display

    The display type to be used for the authorization page. Valid values are "popup", "touch", "page", or "none".

    locale

    Optional. A market string that determines how the consent UI is localized. If the value of this parameter is missing or is not valid, a market value is determined by using an internal algorithm.

    redirect_uri

    Equivalent to the endpoint that is described in the OAuth 2.0 spec.

    response_type

    The type of data to be returned in the response from the authorization server. Valid values are "code" or "token".

    scope

    Equivalent to the scope parameter that is described in the OAuth 2.0 spec.

    state

    Equivalent to the state parameter that is described in the OAuth 2.0 spec.

     

    Top

    OAuth request and response parameters

    The following table lists the OAuth request and response parameters that are used by Live Connect.

    ParameterNotes

    client_id

    The app's client ID.

    client secret

    The app's client secret.

    grant_type

    The authorization type that the server returns. Valid values are "authorization_code" or "refresh_token".

    locale

    Optional. A market string that determines how the consent UI is localized. If the value of this parameter is missing or is not valid, a market value is determined by using an internal algorithm.

    redirect_uri

    Equivalent to the endpoint that is described in the OAuth 2.0 spec.

    response_type

    The type of data to be returned in the response from the authorization server. Valid values are "code" or "token".

    scope

    Equivalent to the scope parameter that is described in the OAuth 2.0 spec.

    state

    Equivalent to the state parameter that is described in the OAuth 2.0 spec.

    display

    The display type to be used for the authorization page. Valid values are "popup", "touch", "page", or "none".

     

    The following table lists the OAuth response parameters that are used by Live Connect.

    ParameterNotes

    access_token

    Equivalent to the access_token parameter that is described in the OAuth 2.0spec.

    authentication_token

    The app's authentication token.

    code

    Equivalent to the code parameter that is described in the OAuth 2.0 spec.

    expires_in

    Equivalent to the expires_in parameter that is described in the OAuth 2.0 spec.

    refresh_token

    Equivalent to the refresh_token parameter that is described in the OAuth 2.0 spec.

    scope

    Equivalent to the scope parameter that is described in the OAuth 2.0 spec.

    state

    Equivalent to the state parameter that is described in the OAuth 2.0 spec.

    token_type

    The type of data to be returned in the response from the authorization server.

     

    Top

    Moving from OAuth WRAP to OAuth 2.0

    Live Connect version 4.1 uses our implementation of OAuth Web Resource Authorization Protocol (WRAP) for user authentication and consent and for managing access tokens and refresh tokens. Live Connect version 5 deprecates OAuth WRAP in favor of our implementation of OAuth 2.0. Also, we plan to turn off access to Live Connect version 4.1 services on 25 June 2012. To move an app from using OAuth WRAP to OAuth 2.0, you'll need to know the following info:

    • If your app has a refresh token that contains one or more scopes that a user has consented to and that are specific to Live Connect version 4.1, your app can use that refresh token with Live Connect version 5 to get an access token that contains equivalent consented scopes in Live Connect version 5. This process allows your app to access a user's info in Live Connect version 5 without unnecessarily interrupting the user to provide consent again to scopes that he or she previously consented to in Live Connect version 4.1. For example, if a user previously consented to theWL_Photos.View scope in Live Connect version 4.1, and your app has a refresh token that contains this consented scope, your app can use that refresh token with Live Connect version 5 to get an access token that contains a scope with functionality equivalent to the WL_Photos.View scope. Your app can then use that access token with Live Connect version 5 to access photo albums and videos that the consenting user has uploaded, along with associated tags and comments. As long as your app has a valid refresh token that is specific to Live Connect version 4.1 and the user has not explicitly revoked consent, you can use that refresh token with Live Connect version 5—even after Live Connect version 4.1 services are turned off.
    • An app can't use Live Connect version 5 to request a user to consent to specific scopes that exist only in Live Connect version 4.1. For example, an app can't use Live Connect version 5 to ask a user to explicitly consent to the WL_Activities.Update scope, which doesn't exist in Live Connect version 5. In this case, we recommend that the app use Live Connect version 5 to ask the user to consent to the wl.share scope, which has equivalent functionality.

    For more info, see Migrating your Live Connect v4.1 app to v5.0.

    Top

    Related topics

    Connect to Outlook.com IMAP using OAuth 2.0

     

     

    Build date: 11/17/2013



    출처 - http://msdn.microsoft.com/en-us/library/live/hh243647.aspx







    OAuth 2.0

    Apps connect to Box using OAuth 2, the standard used by most APIs for authenticating and authorizing users. The following walkthrough will show you how to authenticate a user to use the Box API with OAuth 2. There are also client libraries available in a number of languages that you might find useful. If you just need OAuth tokens for your own account for quick testing, please check out this Heroku app for generating tokens.

    Initial Setup

    Testing: When your app is set to ‘Development’ mode, you can set your redirect_uri to the following local http endpoints: http://127.0.0.1, http://0.0.0.0, and http://localhost.

    Before you can start using OAuth2 with your application, you’ll need to tell Box a bit of information about your application

    1. Register your application here.
    2. Set your redirect url
    3. Select your scope
    4. Make a note of both your client_id and client_secret.
    Redirect URI: The redirect URI is the URL within your application that will receive the OAuth2 credentials.
    Scopes: Select the “Read and write all files and folders” scope if your application needs to perform operations on files and folders, such as creating, downloading, editing, and deleting files and folders. Select the “Manage an enterprise” scope if your application needs to perform enterprise management, such as creating, editing, and deleting users and groups, viewing admin logs, and creating collaborations for groups.

    The First Leg

    First, direct your user to https://www.box.com/api/oauth2/authorize through either a POST or a GET request with the following parameters:

    Parameters: For POST, include the parameters in the POST body. For GET, include them as query parameters. In both cases, URL encode the parameters.
    response_type
    required
    Whether the endpoint returns an authorization code. For web applications, a value of code should be used.
    client_id
    required
    The client_id you obtained in the Initial Setup.
    redirect_uriAn HTTPS URI or custom URL scheme where the response will be redirected. Optional if the redirect URI is registered with Box already.
    stateAn arbitrary string of your choosing that will be included in the response to your application. Box recommends that you use an anti-forgery state token to prevent CSRF attacks to your users

    A sample GET request could therefore look like:

    GET https://www.box.com/api/oauth2/authorize?response_type=code&client_id=MY_CLIENT_ID&state=security_token%3DKnhMJatFipTAnM0nHlZA

    The User Experience

    At this point, you’ve forwarded the user to Box’s authorization page:

    Box login authorization
    Your application doesn’t need to do anything here; Box handles authenticating the user and giving them feedback on any errors:

    Box login error
    After successfully entering their credentials, the user will be taken to a consent page, to authorize your application to access their account.

    Box authorization success

    After clicking either Grant or Deny, you’ll receive a response from Box, as outlined in the next section.

    Handling the Response from Box

    If the user clicked Grant in the previous screen, Box will redirect to the URI you specified earlier with a code parameter and a state parameter, if you included one. For example, if your redirect URI was https://www.sean.com/rose, Box would redirect to:

    https://www.sean.com/rose?code=123456abcdef&state=YOUR_CSRF_PREVENTION_CODE
    Authorization Code: The authorization code is only valid for 30 seconds.

    However, if the user clicked Deny, you will receive a request with an error and error_description parameter, such as:

    GET https://www.sean.com/rose?error=access_denied&error_description=The+user+denied+access+to+your+application

    Assuming you got a Grant response, At this point you should verify that the CSRF security_token you received back is the same one you gave the user back in the First Leg. This will help make sure that it really is your user, and not a malicious script. If the code doesn’t match you should reject with a 401 code.

    The following conditions may also cause an error:

    invalid_requestThe request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.
    unsupported_response_typeThe authorization server does not support obtaining an authorization code using this method.
    Check the value of the code param in your request.
    access_deniedThe resource owner or authorization server denied the request.
    server_errorThe device the user is trying to log in from is not authorized to access the user’s account.
    Error Handling: The error parameter will always be present, while the human readable error_description may not. Your code should rely on error.

    Getting the Access Token

    Once your application has completed the above section and gotten an authorization code, it’ll now need to exchange the authorization code for an access token from Box.

    Access Token: The access token is what’s needed to sign your API requests to Box. You’re almost done!

    To get the access_token, you’ll need to make a POST request to https://www.box.com/api/oauth2/token with the following parameters:

    grant_type
    required
    Must be authorization_code
    code
    required
    The authorization code you retrieved previously
    client_id
    required
    client_id gotten from Box in Initial Setup
    client_secret
    required
    client_secret gotten from Box in Initial Setup
    redirect_uriRequired only if a redirect URI is not configured at box.com/developers/services
    Request: The requests must be over HTTPS and the parameters must be URL encoded.

    An example request in cURL looks like:

    curl https://www.box.com/api/oauth2/token \
    -d 'grant_type=authorization_code&code={your_code}&client_id={your_client_id}&client_secret={your_client_secret}' \
    -X POST

    If everything goes right and the request is successful, you’ll receive a 200 response containing a JSON body like this:

    {
        "access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
        "expires_in": 3600,
        "restricted_to": [],
        "token_type": "bearer",
        "refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
    }

    However, if the response is not successful, you’ll receive an error response, such as this:

    {
        "error": "invalid_grant",
        "error_description": "Invalid user credentials"
    }

    Box supports the full set of error codes in the OAuth 2.0 spec:

    The last four (redirect_uri_mismatch,internal_server_errorinsecure_redirect_uriinvalid_redirect_uri) are not returned to the application. Instead, they are shown to the end user in a Box-generated error page, like this:Using the Access and Refresh TokensThe access_token is the actual string needed to make API requests. Each access_token is valid for 1 hour. In order to get a new, valid token, you can use the accompanying refresh_tokenEach refresh_token is valid for one use in 60 days. Every time you get a new access_token by using a refresh_token, we reset your timer for the 60 day period and hand you a new refresh_token. This means that as long as your users use your application once every 60 days, their login is valid forever. To use the refresh_token to get a new access_token, make a POST request to https://www.box.com/api/oauth2/token with the following, URL encoded parameters:A sample cURL request would look like:

    curl https://www.box.com/api/oauth2/token \ -d 'grant_type=refresh_token&refresh_token={valid refresh token}&client_id={your_client_id}&client_secret={your_client_secret}' \ -X POST

    If the request is successful, you’ll see a response like this:

    { "access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl", "expires_in": 3600, "restricted_to": [], "token_type": "bearer", "refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR" }

    In this response, you’ll receive both a new access_token and refresh_token. The refresh_token you used to make this request is no longer valid. If an error occurs, you’ll receive a 400 Bad Request, along with of the errors listed in the Getting the Access Token section.Using Your Access Token with API V2Once you have a valid access_token, you can use it to make requests to API V2. All you need to do is set it in the Authorization header like this:

    Authorization: Bearer {a valid access token}

    If you were, for example, trying to get a user’s folder in V2, a full cURL request would look like this:

    curl https://www.box.com/api/2.0/folders/0 \ -H "Authorization: Bearer T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl"

    If the protected resource request does not include authentication credentials or does not contain an access token that enabled access to the protected resource, Box sets the WWW-Authenticate response header field. If the protected resource request included an access token and failed authentication, Box sets the “error” attribute to provide the client with the reason why the access request was declined. Box also includes the error-description attribute to provide developers a human-readable explanation that is not meant to be displayed to end users. The following codes can be returned as a value for the WWW-Authenticate header.Destroying TokensIf you would like to get rid of tokens for a user (e.g. if you have a ‘logout of Box’ button in your app), make a POST request to https://www.box.com/api/oauth2/revoke with the following URL encoded parameters:

    • client_id
      required
      The client_id used to create this token
      Type: string
    • client_secret
      required
      The client_secret used to create this token
      Type: string
    • token
      required
      The access_token or refresh_token to be destroyed. Only one is required, though both will be destroyed.
      Type: string

    For example, to destroy access_token 1234 and its associated refresh_token, you would issue this request:

    curl https://www.box.com/api/oauth2/revoke \ -d 'client_id=CLIENT_ID&client_secret=CLIENT_SECRET&token=1234' \ -X POST
    Success: Upon success, both the access_token and refresh_token will be destroyed.

    ErrorError Description(s)What happened
    invalid_requestInvalid grant_type parameter or parameter missing.
    Missing parameter. “code” is required
    Invalid refresh token
    Your request did not contain a grant type.
    The code parameter is missing for the authorization code grant type.
    The refresh token has expired or is malformed.
    unauthorized_clientThe grant type is unauthorized for this client_idYour application is not authorized to use this grant type
    invalid_grantAuth code doesn’t exist or is invalid for the client.
    The authorization code has expired
    Verify the authorization code is set correctly in your request.
    Your application likely needs to get a new authorization code.
    invalid_clientThe client credentials are invalid
    redirect_uri_mismatchThe redirect URI is missing or do not matchEither a redirect uri is not configured for your application or the uri in the request does not match the configured URI.
    insecure_redirect_uriThe URI is either not a custom protocol or not HTTPS.Your application sent a bad redirect URI i.e. HTTP instead of HTTPS
    invalid_redirect_uriThe redirect_uri scheme is invalid per the RFC. A common problem is the first character being something besides a letter.Your application sent an invalid URI.
    refresh_token
    required
    A valid refresh token
    client_id
    required
    client_id gotten from Box in Initial Setup
    client_secret
    required
    client_secret gotten from Box in Initial Setup
    grant_type
    required
    Must be refresh_token
    device_idOptional unique ID of this device
    device_nameOptional human readable name for this device
    HTTP StatusError CodeWhat happened
    400invalid_requestThe request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed
    401invalid_tokenThe access token provided is expired, revoked, malformed or invalid for other reasons. The client may request a new access token and retry the protected resource request
    403insufficient_scopeThe request requires higher privileges than provided by the access token



    출처 - http://developers.box.com/oauth/













    'Security > OAuth' 카테고리의 다른 글

    OAuth 2.0 구현  (2) 2014.01.01
    OAuth 2.0 이해  (0) 2013.12.29
    OAuth 1.0a 이해  (0) 2013.12.29
    OAuth  (0) 2012.05.22
    Posted by linuxism

    댓글을 달아 주세요