Share
Embed
簡單易懂的 OAuth 2.0
Note: 300+ Pages ,推薦下載 PDF
這年頭不管什麼 app 都要串別人的 API ,但如果你要造 API 給別人串,除了規劃 endpoint 和 JSON 資料結構之外,還有更重要的「存取管制」,以及「user 的存在」,例如,你會希望 API request 可以知道「要改哪個 user 的資料」,但不希望 client 儲存 user 的帳號密碼。
利用 OAuth 2 通訊協定,可以實作出 API 的存取管制,讓 API 得知要操作的對象 user 是誰,並且讓你做出像 Facebook 登入那樣子的登入流程。然而 OAuth 2.0 的 spec 根本就是個 [tl;dr] 的東西,但沒讀過 spec 也沒辦法輕鬆實作,更別說套現成的 gem 擋在 API 的前面。本演講會簡單介紹 OAuth 2 是怎麼一回事,並示範如何從零建立一個用 OAuth 2 鎖住的 Grape API。若您沒有 Ruby / Rails 的經驗,也可以大略得知製造 OAuth 2.0 API 鎖的方法。
延伸閱讀:
* 我 Blog 裡面的 OAuth 2 相關文章 http://blog.yorkxin.org/tags/OAuth
* Demo 的簡單 OAuth 2 Guard 實作 https://github.com/chitsaou/oauth2-api-sample
Yu-Cheng Chuang
November 26, 2013
Transcript
303 slides
-
• ⇯č⊫ტӵĎ • Rails Developer at KKBOX, working at the
KKTIX team • chitsaou, @yorkxin, blog.yorkxin.org -
Today’s Target • ᆩ֡ OAuth 2 Protocol ᄸ喁 • ु֤
99% ࠎᧄ OAuth 2 ֻ֥ٚ API ໓ࡱ • ᆩ֡ᄸ喁Ⴈ OAuth 2 ⅞֥ API -
Agenda • OAuth 2 ൞മ喁ĤॖၛଦῲἓખĤ • OAuth 2 ๙⇫⇐קᄸ喁 •
⚧ᄯ OAuth 2 Provider ֥ٚم • ֻ၂ՑႨ Rails + Grape API ᆜކ OAuth 2 ࣼഈ൭ -
OAuth 2.0 • ಆ “The OAuth 2.0 Authorization Framework” •
Authorization (n.) ൱ -
The Old-School Way… • App ေ℻ೆ≷ὂૡđὕ℥ૼ҂⁙۞ • ေྐ App ҂ଦ֥ૡ⁙۞
• ࣼෘ App ޓܭđФἓሼὕ൞㢻ࣷ • ҂ܵྐ҂ྐđّᆞ൞҂ྐ…… -
OAuth ೂޅࢳ㢯≾ἠ↜ⅳ • ᅟิ܂ܲٚࢸ૫đॖၛ൱ӱൔႨ⊷ਘ • ӱൔթ֥൞ Token ط٤≷ὂૡ ္Ⴈ Token
ಀյ API • Token ॖၛἲקթ౼ữčscopes, ೂğݺႶਙіĎ • Token Ⴕ௹ཋطॖၛ⅗ℭӜ⇍č҂ஃФἓሼĎ -
OAuth 2 䥰૫֥࢘ • Resource Owner - ⊷ਘ∭Ⴕᆀđ๙ӈ൞ದ (User) •
Client - ࠧ App đေթ౼ User ֥⊷ਘ֥ӱൔ • Authorization Server - ⊺ܵ၂్൱൙↩ • Resource Server - Client ạ≾䥰ଦ⊷ਘđࠧ API -
ದ Ἶ¯¯ ൱ἡ ӱൔ 䪌wॖၛಀ۵ଛᅟଦ֥⊷ਘx You Facebook API Resource
Owner Client Resource Server Authorization Server -
Resource Owner = User • ࣼ൞ᅟ֥ User • API ঘ֥֞൞۵
User ႵἬ֥⊷ਘ • ২ೂݺႶẪaྐࡱ⤨ಸ • ൱с⇜ῂႮЧದ⃤ሱ -
Resource Owner = Client • ≾⊕౦㣐㢻Ⴕದ֥թᄝb • ২ğ܄Ῐ⊷ਘ • Twitter
Ẁ㬪 App-Only Authorization • Facebook Ẁ㬪 App Access Token -
Client • User ൱ἡֻٚӱൔđ≾ἠӱൔࣼ൞ Client • ২ğFacebook ഈ֥䵔↰a൭Ὠഈ֥ App •
ܲٚӱൔ္ෘč২ೂ൭Ὠ App aም૫ AppĎ -
Client с⇜൙༵䩏⤳ • “Client Registration” • Client ID • Client
Secret čℶ㬪ૡĎ • Redirect URI ← ≾ἠޓᇗေ -
Redirect URI • User Чದ⃤ሱᆭᗥđْ߭ݔ֞ Client • ေ൙༵ᆷקđ҂၂ᇁ≣҂ॖ Redirect Ἶಀ
• ॖၛᆷק؟⊾đ๙ӈ൞၂⊾đࠇ൞Ῐⅽ၂ᇁ • ቋݺ൞ HTTPS č҂ルᇅđ২ೂ൭Ὠ App ࣼḰ҂֞Ď -
Public v.s. Confidential Client • ۴ῌwି҂ିЌὊ⊷ਘxῲ⃯ٳ • Confidential - Server-Side
Application • Public - ൭Ὠ App / ም૫ӱൔ / JavaScript App / Browser Extension -
Client Authorization (⊈) • ԛൕ Client ID + Secret ཟ
Auth. Server ⊈ሱ࠭ • ္ࣼ൞䪌 Client ေ֨ೆ֞ Auth. Server • ᆺℳႨ Confidential Client -
Client • Ⴕ ID / Secret Ⴈᧄ⊈ • Ⴈ Redirect
URI Ќ⏟´ఖ⊨ᆶ֞ᆞ֥ Client • Public / Confidential Ⴕ۲ሱℳႨ֥൱ੀӱ -
Endpoints • Authorization Endpoint - Ⴈῲἡ User Чದ൱ • Token
Endpoint - Ⴈῲ Client ౼֤ᆇᆞ֥ Token • Redirection Endpoint - Client Ⴈῲ൬⊷ਘႨ -
Authorization Endpoint • ἡ User Чದ൱ • ൞၂ἠ∉ • ଦ֥֞൞
“Grant” č൱⊯Ďط҂൞ Token • User ճڭᆭᗥđ⊨߭ Client ֥ Redirect URI -
Redirection Endpoint • Ⴈῲạ⏟´ఖࢤ൬ Auth. Server ῲ֥⊷ਘ • Ῐᄝ Client
ط҂൞ Auth. Server • Client 䩏⤳ℭေ⇔֥ “Callback URL” • Auth. Server ⇼⊈ Redirect URI ൞ڎཌྷژҌ⊨ᆶ -
SSL! SSL! SSL! • Auth. Server ഈ૫֥ Endpoints с⇜ഈ HTTPS
• Client с⇜⇼⊈ SSL Certificate ൞ڎކ۬ • Client Redirection Endpoint ҂ルᇅđିഈቋݺഈ ᅟ → ቋݺഈ ൭Ὠ / ም૫ App → 㢻Ḱمॖၛ҂ေഈ -
Resource Server • Client с⇜ԛൕ Token ҌିΆಀଦ⊷ਘ • Client ᆺေԛൕ
Token ࣼିΆಀଦ⊷ਘ • ॖၛႨ Scope ཋᇅ Token ିⴺ౼Ⴈ֥⊷ਘữ -
• RFC 6749: The OAuth 2.0 Authorization Framework • 77
pages (PDF) • RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage • 19 pages (PDF) tl;dr -
OAuth 2.0 Spec(s) • RFC 6749 - ק∕∻ Token ނứႵἬ֥
Protocol • RFC 6750 - ק∕wBearer Tokenxᄸ喁Ⴈ -
RFC 6749: OAuth 2 Protocol • ק∕ਔ OAuth 2 ֥࢘aọٚൔ
• ק∕ਔ⊷ਘႵଧུaᄸ喁 • ק∕ਔނứa㍤ứ Token ֥֩ Protocol • ἲਔ 4 ⊕ӈᾖwℳކႨ OAuth 2 ֥ੀӱx -
RFC 6750: Bearer Token • RFC 6749 ᆺἲק൱ٚൔđ㢻ἲק API ᄸ喁Ẳ
• RFC 6750 ק∕၂⊕ࢡቓ “Bearer” ֥ Token Type • ۲⊕ type Ⴕ҂Ẳمđ Bearer ൞ᆰࢤ == ᾋҰ • ၂ओὐࢳℴğwᆰࢤଦῲࣼିႨđ҂Ⴈ⃐ῲ⃐ಀx -
Client ID / Secret • Ⴈᧄ Client ⊈čClient ֨ೆ֞ Auth.
ServerĎ • 䩏⤳֥ℭީứἡđ⁙ࣼྛ • HTTP Basic Auth ࠇЇᄝ Form 䥰૫č࣌Ⴈ URLĎ -
HTTP Basic Auth ID = abc, Secret = 123 abc:123
concat with `:` YWJjOjEyMw== base64() Authorization: Basic YWJjOjEyMw== Basic Auth Header -
Token(s) • Access Token - յ API Ⴈ֥ • Refresh
Token - Access Token Ἶ௹ॖၛ㍤ứྍ֥ -
Access Token • ཟ Resource Server ေ⊷ਘđႨ Access Token •
ॖၛḳ၂⊾ Scope • ॖၛ℟௹ཋđॖၛӜ⇍ (Revoke) • ൱ੀӱ֥ଢṌࣼ൞ေଦ֞ Access Token -
Refresh Token • ㍤ứ Access Token Ⴈđᆺẖ֞ Auth. Server •
ḳק၂ἠ Access Tokenđ⅗ Access Token ၂ఏނứ • ႨἾࣼാི ྍ֥ Access Token ḳྍ֥ Refresh Token -
Scopes • Ⴈῲіൕwॖၛթ౼ଧུ⊷ਘx֥ཋữ • ೂwݺႶẪxawཌྷோx • ॖၛ A cover B
đằಖ Set ൞ቋᾏẪ֥ቓم -
State • Ⴈῲٝᆸ CSRF ۾ὧ • Client 㲗 Browser 㲗
Auth. Server ൞ޓາ↿ˀ • State ẖ֞ Auth. Server ࣼေჰٿ҂ọْ߭ • Client ⇼⊈ᆭ • ⁙ᆴࣼྛđ္ॖၛႨ HMAC ⃐ -
౼֤൱֥ੀӱ 1. Client ཟ Res. Owner ౼֤ “Grant” č൱⊯Ď 2.
Client Ⴈ “Grant” ཟ Authorization Server ㍤ Token 3. Token ଦ֞ਔđॖၛಀյ API ᆜἠ Protocol ቋₒ֥ᄝ≾䥰 -
ቋӈᾖ֥ Scenario Ⴕᅟ Facebook đ༐ຬᄝପഈ૫֥ User ἡ֥ᅟཋđॖၛồ౼ପ User ֥⊷ਘ
Resource Owner Client Token Resource Server Ἶ Facebook ֥ Authorization Server -
Auth Code Grant Flow • Grant ൞ऎⅴ֥ሳԱđẀቔ Code • ླေῂἾ
Browser • ℳႨᧄwᅟx≾⊕ Client -
Resource Owner Browser Client ! Authorization Server ※Ӓሱ spec Authorization
Endpoint Token Endpoint Redirection Endpoint -
Resource Owner Browser Client ! Authorization Server (A) (A) ID,
Redirect URI, Scope, State ※Ӓሱ spec Authorization Endpoint Token Endpoint Redirection Endpoint -
Resource Owner Browser Client ! Authorization Server (A) (A) ID,
Redirect URI, Scope, State (B) (B) ↜ Resource Owner ※Ӓሱ spec Authorization Endpoint Token Endpoint Redirection Endpoint -
Resource Owner Browser Client ! Authorization Server (A) (A) ID,
Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Grant Code, Scope, State ※Ӓሱ spec Authorization Endpoint Token Endpoint Redirection Endpoint -
Resource Owner Browser Client ! Authorization Server (A) (A) ID,
Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Grant Code, Scope, State (D) Grant Code, Client Auth ※Ӓሱ spec Authorization Endpoint Token Endpoint Redirection Endpoint -
Resource Owner Browser Client ! Authorization Server (A) (A) ID,
Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Grant Code, Scope, State (D) Grant Code, Client Auth (E) Token ※Ӓሱ spec Authorization Endpoint Token Endpoint Redirection Endpoint -
https://graph.facebook.com/oauth/authorize? response_type=code &client_id=567672586646825 &redirect_uri=http://localhost:3000/users/ auth/facebook/callback &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &scope=email іൕ Authorization
Code Grant Flow Client ID Redirect URI Authorization Endpoint -
https://graph.facebook.com/oauth/authorize? response_type=code &client_id=567672586646825 &redirect_uri=http://localhost:3000/users/ auth/facebook/callback &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &scope=email іൕ Authorization
Code Grant Flow Client ID Redirect URI Client ֥ State čٝ CSRF Ď Authorization Endpoint -
https://graph.facebook.com/oauth/authorize? response_type=code &client_id=567672586646825 &redirect_uri=http://localhost:3000/users/ auth/facebook/callback &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &scope=email іൕ Authorization
Code Grant Flow Client ID Redirect URI Client ֥ State čٝ CSRF Ď མေ⃪֥ཋữčScopesĎ Authorization Endpoint -
Authorization Server ֥ọቔ 1. ۴ῌ Client ID ᅳ Client 2.
Redirect URI ۵൙༵䩏⤳֥ཌྷژ • ҂ᆞ≣ေ₵ấ↪đ҂ॖ⊨߭ἐ URI 3. མണ⃪֥ scope ᆞč۬ൔa⤨ಸ֩Ď 4. 㢻↜ⅳࣼ↜ Resource Owner ေ҂ေ൱ (B) -
Authorization Server ֥ọቔ • ᄍ⇝đ≣⊨߭ Client đڸഈ Grant Code •
҂ᄍ⇝đ≣⊨߭ Client đ❣ڸഈấ↪⇫༏ • Ⴕẖ state Ἶῲđ≣ჰٿ҂ọڸഈ -
(D) ଦ Code ㍤ Token • Client ᄝᗥቓ≾ࡱ൙ • POST
֞ Auth. Server ֥ Token Endpoint ㍤ Token • Client Authentication • grant_type=code, code, redirect_uri, client_id (Ᾱ Public Client) -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback Token Endpoint ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback Token Endpoint Client Authentication ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback Token Endpoint іൕwଦ֥֞൱⊯൞ Grant Codex Client Authentication ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback Token Endpoint іൕwଦ֥֞൱⊯൞ Grant Codex Grant Code Client Authentication ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
POST /oauth/access_token HTTP/1.1 Host: graph.facebook.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=authorization_code &code=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &redirect_uri=http%3A%2F%2Flocalhost %3A3000%2Fusers%2Fauth%2Ffacebook%2Fcallback Token Endpoint іൕwଦ֥֞൱⊯൞ Grant Codex Grant Code ჰ Redirect URI Client Authentication ※ ൙ℯഈ Facebook Ⴈ GET đ҂ކṌ⊵đ༯ⅾ⃪ሱྛₔṘ -
Authorization Server ֥ọቔ • Client Authentication (ID / Secret)
ᆞ • ᅳ֞ἐ Grant Code đః Redirect URI ၂ଆ၂∄ • 㢻↜ⅳ֥ὐࣼứ Token -
(E) ứ Token • Client ֥ Token Request ֥ Response
• ൞ JSON Response • ॖၛ၂⟸ứ Refresh Token • User ൱֥ Scope ∻ണ⃪ℭ҂၂ᇁ≣ေڸഈ -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } Access Token -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } Access Token іൕ≾ἠ Token ൞ Bearer Token -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } Access Token іൕ≾ἠ Token ൞ Bearer Token 3600 ૰ᆭᗥἾ௹ -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } Access Token іൕ≾ἠ Token ൞ Bearer Token 3600 ૰ᆭᗥἾ௹ Access Token Ớ∣֥ Refresh Token -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } Access Token іൕ≾ἠ Token ൞ Bearer Token 3600 ૰ᆭᗥἾ௹ Access Token Ớ∣֥ Refresh Token scope ∻ണ⃪ℭ ҂၂ᇁ≣ေڸഈ -
൭Ὠ App / ም૫ App • ℶ㬪 Public đClient Authentication
҂ॖྐ • Token Request ေڸഈ Client ID Ќ Token ứἡᆞ֥ Client • App ⅹܥק URI đೂ kktix-app:oauth2-callback -
What about JavaScript App • “User-Agent-Based Client” • Public Client
• Redirect Endpoint ္㢻Ḱمⅹሱị Protocol • Auth. Code Grant Flow ҂ॖႨđᄸ喁ḰĤ -
Implicit Grant Flow • ⊦⁽ἡ Public Client Ⴈ • Grant
҂ẖ֞ Client đᆰࢤứ Token • ҂ῂἾ Token Endpoint • ứ֥ Token ๙ӈ൞؋ི௹đࢆ֮Ф֥ἀ↿ • ҂ἡ Refresh TokenđἾ௹ᇗྍണ⃪ੀӱ -
Resource Owner Browser Client (JS) ! Authorization Server ※Ӓሱ spec
Client’ (Web Server) -
Resource Owner Browser Client (JS) ! Authorization Server ※Ӓሱ spec
Authorization Endpoint Client’ (Web Server) Redirection Endpoint -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Token (in Frag.), Scope, State ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Token (in Frag.), Scope, State ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint (D) GET Redirect URI (no Token) -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Token (in Frag.), Scope, State (E) JavaScript (to Decode Token) ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint (D) GET Redirect URI (no Token) -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Token (in Frag.), Scope, State (E) JavaScript (to Decode Token) ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint (D) GET Redirect URI (no Token) (F) -
Resource Owner Browser Client (JS) ! Authorization Server (A) (A)
ID, Redirect URI, Scope, State (B) (B) ↜ Resource Owner (C) Token (in Frag.), Scope, State (E) JavaScript (to Decode Token) ※Ӓሱ spec Authorization Endpoint Client’ (Web Server) Redirection Endpoint (D) GET Redirect URI (no Token) (G) Assign Access Token (F) -
(C) ~ (G) ളസଊℿ • (C) Auth. Server ࢡ Browser
⊨߭ Redirect URI • https://client.com/oauth2/callback#access_token=… • (D) Browser ಀ GET ἐ URL đ҂ݣ # č฿ྟĎ • Token ሱọЌᄝ Browser ֥ Fragment Part 䥰૫ -
(C) ~ (G) ളസଊℿ • (E) ᄜ❟߭၂ἠ JavaScript Ⴈῲࢳԛ #
䥰૫֥ Token • (F) Browser ሱọ run ≾ἠ JavaScript ࢳԛ Token • (G) Ϝࢳԛῲ֥ Token ❟ἡ JavaScript App -
෮ၛ㬪喁ླေ Client’ ٳദ • JavaScript ҂ିῘ Redirection Endpoint ෮ၛႨ Web
Server Ῐ • 䥰૫ࣼ൞၂ἠ JavaScript code Ⴈῲࢳԛ Token ❣ẖἡ JavaScript App (ᆇ Client) -
https://graph.facebook.com/oauth/authorize? response_type=token &client_id=567672586646825 &redirect_uri=http://localhost:3001/jsapp/ facebook/callback &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &scope=email іൕ Implicit
Grant Flow Client ID Redirect URI Client ֥ State čٝ CSRF Ď Authorization Endpoint -
https://graph.facebook.com/oauth/authorize? response_type=token &client_id=567672586646825 &redirect_uri=http://localhost:3001/jsapp/ facebook/callback &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &scope=email іൕ Implicit
Grant Flow Client ID Redirect URI Client ֥ State čٝ CSRF Ď མေ⃪֥ཋữčScopesĎ Authorization Endpoint -
http://localhost:3000/jsapp/facebook/ callback# token=AQABIWdeO3miePq0uH2VCUvhGr- voXz3zunrCiX5Bz9IFF8m82bmP(...) &state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 &token_type=Bearer &expires_in=3600 Redirection Endpoint
Access Token ჰٿ҂ọ֥ State ᆴ іൕ≾ἠ Token ൞ Bearer Token 3600 ૰ᆭᗥἾ௹ -
Redirection Endpoint ֥⤨ಸ <script> var access_token = [extract token from
frag]; // store token in local storage or cookie </script> -
Implicit Grant Flow Usage • Facebook JavaScript SDK • ൭Ὠ
App aም૫ App ္ℳႨ Facebook: WebView ᾄⅹܥק Redirect URI ሂԛ #access_token -
ห⦁ᇿၩ൙⇊ • 㬪ࢆ֮ Token Фἀ↿đ๙ӈứ؋ི௹֥ Token • ၹ㬪ॖି⢔ᄯ Token 刈ἡ
Client đ෮ၛс⇜⇼⊈ᆭ • Facebook: “Token Debug Endpoint” -
What if ሱ㸗ሱႨĤ • ሱ࠭⇔֥ script མေႨ Token ಀյ API
• Server App ၘῂթਔ≷ὂૡđམڿӮ OAuth 2 -
Resource Owner Client ! Authorization Server ※Ӓሱ spec Token Endpoint
(A) Username, Password -
Resource Owner Client ! Authorization Server (B) Client Auth, Username,
Password, Scopes ※Ӓሱ spec Token Endpoint (A) Username, Password -
Resource Owner Client ! Authorization Server (B) Client Auth, Username,
Password, Scopes (C) Token ※Ӓሱ spec Token Endpoint (A) Username, Password -
Resource Owner Password Credentials Grant Flow • ླေ൞ Resource Owner
ۚ؇ྐῳ Client • ቔ∊༢ⅼ⤨ࡹ֥∣ႨӱൔčOS X ֥ Twitter ᆜކĎ • ܲٚ∣ႨӱൔčGitHub.appĎ • ః⦁֥ੀӱ҂ℳႨ -
Resource Owner Password Credentials Grant Flow • No “state” ၹ㬪҂ῂἾ
Browser • No “Redirect URI” ၹ㬪㢻Ⴕ redirection • ᆰࢤ POST ಀ Token Endpoint ଦ Token -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email Token Endpoint -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email Token Endpoint Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email Token Endpoint іൕwଦ֥֞൱⊯൞ User ֥ Passwordx Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email Token Endpoint іൕwଦ֥֞൱⊯൞ User ֥ Passwordx Credentials Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=password &username=chitsaou &password=12345678 &scope=email Token Endpoint іൕwଦ֥֞൱⊯൞ User ֥ Passwordx Credentials Client Authentication མေ⃪֥ཋữčScopesĎ -
Client ! Authorization Server (A) Client Auth, Scopes (B) Token
※Ӓሱ spec Token Endpoint -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=client_credentials &scope=search_timeline -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=client_credentials &scope=search_timeline Token Endpoint -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=client_credentials &scope=search_timeline Token Endpoint Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=client_credentials &scope=search_timeline Token Endpoint іൕw Client ေണ⃪ Token ሱႨx Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=client_credentials &scope=search_timeline Token Endpoint іൕw Client ေണ⃪ Token ሱႨx Client Authentication མေ⃪֥ཋữčScopesĎ -
4 built-in grant flows • Authorization Code • Implicit •
Resource Owner Password Credentials • Client Credentials -
Errors on Authorization Endpoint 1. ҂ԛ ClientaRedirect URI ҂ژ 2.
Ṛ⅂ẖấ / Authorization Server 㢻ℯቔଖུۿି 3. Resource Owner ऋ䌉൱ 4. Internal Server Error -
Client ҂֤aRedirect URI ҂ژ • Redirect URI 㢻ἡ / ҂ᆞ
/ 㢻൙༵䩏⤳ • ေℶ㬪۾ὧđ҂ॖၛ Redirect ֞ἐ Redirect URI • ေิൕࣞۡ⇫༏ἡ Resource Owner -
ఃấ↪ • ေ⊨߭ Redirect URI ཟ Client ۡᆩấ↪ • ᄝ
URI ᗥ૫ڸഈ error parameters • Auth Code Grant Flow - Ⴈ Query ?error=... • Implicit Grant Flow - Ⴈ Fragment #error=... -
Error Parameters • error - Error Code đсแđ༯⇈ • error_description
- ᾏẪ䪌ૼấ↪ • error_uri - ၂ἠᆶᆷ֞⇈↱䪌ૼ∉ • state - ẖ߭ Client ֥ state ჰᆴđᆭభႵἡࣼсแ • ଖུὕἡ error_subcode čႭఃᇏἽ֥ᅟĎ -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 Redirection Endpoint -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 Redirection Endpoint ấ↪ -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 Redirection Endpoint ấ↪ ᾏඍấ↪൞喁 -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 Redirection Endpoint ấ↪ ᾏඍấ↪൞喁 ु⇈↱䪌ૼ֥ URL -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 Redirection Endpoint ấ↪ ჰٿ҂ọ֥ State ᆴ ᾏඍấ↪൞喁 ु⇈↱䪌ૼ֥ URL -
http://localhost:3000/users/auth/facebook/ callback? error=access_denied &error_description=User Denies Authrization &error_uri=https://doc.example.com/...
&state=446c63696b24b4b6687cdff62eabce3a9c9d63 33d7c807e6 # Implicit Flow: ㍤Ӯ Fragment Parameter -
error = Meaning invalid_request 㢻ἡсေṚ⅂aἡਔ҂ᆞ֥Ṛ⅂a ᇗ♶ἡṚ⅂aࠇఃჰၹẹᇁ↥مࢳồb unauthorized_client Client ҂ሙႨ≾⊕ Response
Type ῲ౼֤ Authorization Codeb unsupported_response_type Authorization Server ҂ᆦჱႨ≾⊕ Response Typeb invalid_scope ෮ေ֥ scope ҂ᆞa ҂ૼa↥مࢳồb Client ᄯӮ֥ấ↪ -
error = Meaning server_error Authorization Server მ֞ၩຓ֥౦㣐ط ↥مẕ⃪b temporarily_unavailable Authorization
Server ӑ≘ࠇ→ྩᇏđ ↥مẕb Authorization Server Internal Server Error -
error = Meaning server_error Authorization Server მ֞ၩຓ֥౦㣐ط ↥مẕ⃪b temporarily_unavailable Authorization
Server ӑ≘ࠇ→ྩᇏđ ↥مẕb Q: 㬪喁҂ିႨ 500 ߭Ĥ Authorization Server Internal Server Error A: ၹ㬪 500 ҂ᆦჱ Location ⊨ᆶđerror ẖ҂߭ Client -
Errors on Token Endpoint 1. Auth. Server ҂֤ Client 2.
Ṛ⅂ẖấ / Authorization Server 㢻ℯቔଖུۿି 3. ൱⊯ (Grant) ҂ᆞ 4. Internal Server Error -
߭∣ٚൔ • ၂ੰЇΆ JSON ߭ • ๙ӈ߭ 400 Bad Request
• Client ⊈ാḮ & Ⴈ Authorization Header ⊈ → ೖ WWW-Authenticate header -
Error Parameters (≅ Auth E.P.) • error • error_description •
error_uri • ଖུὕἡ error_subcode čႭఃᇏἽ֥ᅟĎ • No state (ၹ㬪㢻Ⴕ state ẖΆῲά) -
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 WWW-Authenticate: Basic Cache-Control: no-store Pragma:
no-cache { "error":"invalid_client", "error_description":"Client Authentication Failed", "error_uri":"https://doc.example.com/..." } -
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 WWW-Authenticate: Basic Cache-Control: no-store Pragma:
no-cache { "error":"invalid_client", "error_description":"Client Authentication Failed", "error_uri":"https://doc.example.com/..." } ۲Ⴕࡹ∗֥ Response Code -
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 WWW-Authenticate: Basic Cache-Control: no-store Pragma:
no-cache { "error":"invalid_client", "error_description":"Client Authentication Failed", "error_uri":"https://doc.example.com/..." } ۲Ⴕࡹ∗֥ Response Code Client Ἶ Basic Auth ⊈ാḮ≣ೖ≾ἠ header -
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 WWW-Authenticate: Basic Cache-Control: no-store Pragma:
no-cache { "error":"invalid_client", "error_description":"Client Authentication Failed", "error_uri":"https://doc.example.com/..." } ۲Ⴕࡹ∗֥ Response Code Client Ἶ Basic Auth ⊈ാḮ≣ೖ≾ἠ header ấ↪ -
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 WWW-Authenticate: Basic Cache-Control: no-store Pragma:
no-cache { "error":"invalid_client", "error_description":"Client Authentication Failed", "error_uri":"https://doc.example.com/..." } ۲Ⴕࡹ∗֥ Response Code Client Ἶ Basic Auth ⊈ാḮ≣ೖ≾ἠ header ấ↪ ᾏඍấ↪൞喁 -
error = Meaning invalid_client Client ⊈ാḮ Authorization Server ҂ԛ Client
ေ߭ 401 Unauthorized ೂݔ൞Ⴈ Basic Auth ෂԛ Client Auth đ≣ေڸഈ WWW-Authenticate: Basic -
error = Meaning invalid_grant ิԛ֥ Grant ࠇ൞ Refresh Token ҂ᆞa
Ἶ௹aФӜ⇍đࠇ Redirection URI ҂ژđ ࠇ۴Чࣼ҂൞ἡ≾ἠ Clientb ൱⊯҂ᆞ -
error = Meaning invalid_request 㢻ἡсေṚ⅂aἡਔ҂ᆞ֥Ṛ⅂a ᇗ♶ἡṚ⅂aࠇఃჰၹẹᇁ↥مࢳồb unauthorized_client Client ҂ሙႨ≾⊕ Response
Type ῲ౼֤ Authorization Codeb unsupported_grant_type Authorization Server ҂ᆦჱႨ≾⊕ Grant Typeb invalid_scope ෮ေ֥ scope ҂ᆞa ҂ૼa↥مࢳồb Client ᄯӮ֥ấ↪ -
error = Meaning — — Q: 㬪喁㢻ႵĤ Authorization Server Internal
Server Error A: ၹ㬪൞ Client ᆰࢤứ Request ֞ Serverđᆰࢤ₵ 500 ࣼྛ -
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache {
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "scopes":"email" } -
Bearer Token • RFC 6750 ק∕đ၂⊕ OAuth 2.0 ֥ Token
• ႨمቋᾏẪğԛൕ Token ἡ Resource Server • Token ⤨ಸ⁙ࣼྛ • Spec ᆺἲקԛൕ Token ֥ٚൔ & ấ↪⇫༏ -
ԛൕ Token ֥ٚم • (in Header) Authorization: Bearer 2YotnFZF... •
(in Body) &access_token=2YotnFZF... • (in URL) ?access_token=2YotnFZF... ҂ᾑ ቋᾑ -
Authorization: Basic XXXXXXXX • с⇜ᆦჱ • ᆰࢤϜ Token ሳԱ٢Ά Header
ࣼྛਔ ቋᾑ GET /me.json HTTP/1.1 Host: api.example.com Authorization: Bearer 2YotnFZF... -
in Request Body • ℳႨᧄ "Form" ᆭ ֥ request (POST, PATCH
etc.) • ҂ॖၛ൞ multi-part • Content-Type: application/x-www-form-urlencoded -
POST /api/articles HTTP/1.1 Host: api.example.com Content-Type: application/x-www-form- urlencoded title=Test%20Article
&content=%28ry%0A%0D &access_token=2YotnFZF... -
҂ᾑ in URL Query Param • ҂ᾑđၹ㬪ॖିФὸᄝ log 䥰 •
ေЌ response ൞ non-cacheable • Ⴕ Form ିႨࣼ᾽ਈႨ Form Body -
GET /api/articles?access_token=2YotnFZF... HTTP/1.1 Host: api.example.com HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8
Cache-Control: private (or no-store if not 200) -
߭∣ٚൔ • ၂ੰႨ WWW-Authenticate header ߭ấ↪ • Ⴕԛൕ Token đҌିڸഈః
Error Parameters • ※ 㢻ἲק҂ିᄜႨ JSON ߭ -
error = Status Meaning invalid_request 400 㢻ἡсေṚ⅂aἡਔ҂ᆞ֥Ṛ⅂ ᇗ♶ἡṚ⅂aᇗ♶ԛൕ Access Token
ࠇఃჰၹẹᇁ↥مࢳồb invalid_token 401 Access Token Ἶ௹aФӜ߭a↥مࢳồb Client ॖၛᇗྍണ⃪၂ἠ Token ᄜℷb insufficient_scope 403 Token ֥ scope ཋ҂ቀb Error ॖၛڸഈ scope= ῲิൕ෮ླཋb -
HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="The API" error="invalid_token" error_description="Token is
not usable." HTTP/1.1 403 Forbidden WWW-Authenticate: Bearer realm="The API", error="insufficient_scope", error_description="Scope not sufficient.", scope="friend_list photo" -
ປಆ㢻ԛൕ Access Token HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="The API"
GET /api/articles HTTP/1.1 Host: api.example.com -
Token Refresh • ଦ Access Token ނứℭ֥ Refresh Token ಀ㍤ứ
• ჰЧ㢻Ⴕứ Refresh Token đࣼ҂ି㍤ứ • POST ֞ Token Endpoint -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=refresh_token &refresh_token=tGzv3JOkF0XG5Qx2TlKWIA &scope=search_timeline -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=refresh_token &refresh_token=tGzv3JOkF0XG5Qx2TlKWIA &scope=search_timeline Token Endpoint -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=refresh_token &refresh_token=tGzv3JOkF0XG5Qx2TlKWIA &scope=search_timeline Token Endpoint Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=refresh_token &refresh_token=tGzv3JOkF0XG5Qx2TlKWIA &scope=search_timeline Token Endpoint іൕw Client ေ㍤ứྍ֥ Tokenx Client Authentication -
POST /token HTTP/1.1 Host: oauth.example.com Authorization: Basic YWJjOjEyMw== Content-Type: application/x-www-form-
urlencoded grant_type=refresh_token &refresh_token=tGzv3JOkF0XG5Qx2TlKWIA &scope=search_timeline Token Endpoint іൕw Client ေ㍤ứྍ֥ Tokenx Client Authentication scope ॖസđ҂ॖնᧄ Access Token ണ⃪Ἶ֥ཋ -
Service spec ཌྷಸ ᆦჱ֥ Grant Types scope ٳۯ Refresh Token
Client ⊈ Facebook ✕ Auth Code, Implicit, Client Cred. comma △ (ሱ⚧) GET GitHub ✕ Auth Code, Password (ሱ⚧) comma ✕ POST Twitter ̋ Client Cred. (↥ scope) ✕ Basic Google ✕ Auth Code, Implicit space ̋ POST Microsoft ✕ Auth Code, Implicit ĤĤĤ ̋ POST Dropbox ̋ Auth Code, Implicit (↥ scope) ✕ Basic, POST Amazon ̋ Auth Code, Implicit space ̋ Basic, POST Bitly ✕ Auth Code (϶ሱ⚧), Password (↥ scope) ✕ POST (Auth Code), Basic (Password) ྍশັѰ ✕ Auth Code comma ✕ Basic, GET ϵ ✕ Auth Code, Implicit comma ̋ POST BOX ✕ Auth Code (↥ scope) ̋ POST Basecamp ✕ Auth Code (↥ scope) ̋ POST -
⦁ದᄸ喁ቓ • ҂၂קေᆦჱ෮Ⴕ 4 ⊕ Grant Flow • ҂၂קေႵ Scope
• ҂၂קေႵ Refresh Token -
⦁ದᄸ喁ቓč҂ݺ֥ٚ૫Ď ✘ ్ Scope ޓ؟ದႨ `,` ✘ Client ⊈҂ᾖ֤ᆦჱ HTTP
Basic Auth ✘ Bearer Token ҂၂ק൞Ⴈ “Bearer” Authorization Header -
Ⴕ Spec ॖၛ Follow ࣼ Follow ✔ ్ Scope Ⴈॢ۬
✔ Client ⊈ᇀഒေᆦჱ Basic Auth ✔ Bearer Token ࣼႨ “Bearer” Authorization Header -
Client Registration (CRUD) • id • secret čℶ㬪ૡĎ • Redirect
URI ّᆞ҂൞ἡದὸ֥ ෮ၛള⁙ࣼྛ } ← ေ Developer ൙༵ᆷק -
Authorization Endpoint • ๙ӈῘᄝᇶᅟđٚьᆰࢤ User Ⴈ Cookie ֨ೆ • ⚧ቔ၂ἠ
Dialog User 㢯קေ҂ေᄍ⇝൱ • User ߭ճᆭᗥđRedirect ߭ Client • Redirect ߭ Client đ෮ၛေ༵Ќ Client ᆞ -
Authorization Endpoint halt if !(client_id and redirect_uri matches) error(invalid_scope) if
!(valid_scope?) error(unsupported_response_type) if !(valid_response_type?) # other errors (incomplete pseudo code) -
Authorization Endpoint result = ask_user_for_authorization! if result == Authorized then
if response_type == Code callback_params = generate_grant_code() else if response_type == Token callback_params = generate_token() else if result == Denied then callback_params = generate_error_code(access_denied) -
Authorization Endpoint if response_type == Code redirect_to_client_with_query(callback_params) else if response_type
== Token redirect_to_client_with_fragment(callback_params) -
Token Endpoint • ๙ӈῘᄝ API subdomain • ᅶ Spec ቓ
JSON Response ࣼྛ -
Token Endpoint authorize_client! or error(invalid_client) verify_redirect_uri! or error(invalid_request) error(invalid_scope) if
scope_given and !valid_scope? # other errors token = issue_token(expires_in: 30.days) token_response_by_json(token) -
“Resource Server Guard” fetch_token(from: header, form, query) error(401) if !(token_given?)
error(400) if !(token_decodable?) error(invalid_token) if expired? or revoked? error(insufficient_scope) if scope_sufficient? yield to API -
ֻ၂ՑčĎࣼഈ൭ • Ⴈ Devise ള User (Resource Owner) • Ⴈ
Doorkeeper ἒ Authorization Server • Ⴈ Grape ἒ API (Resource Server) • ሱ࠭ख़ Resource Server Guard ῲ⅞ API -
Why ሱ࠭ख़ Guard • doorkeeper_for ൞ Rails-Only • Rack::OAuth2 ປӮ؇ޓۚđс⇜ሱ࠭ᆜކ
• Warden::OAuth2 ۵ Devise वᄝ၂ఏ҂ࢳ • Grape::Middleware::Auth::Oauth2 ۴Ч㢻ቓປ ✔ Best Choice -
ᄯ API class SecretAPI < Grape::API namespace "secret" format :json
get "hello" do { greeting: "Hi,#{current_user.email}" } end end -
Ῐ Authorization Server $ gem install doorkeeper $ rails g
doorkeeper:install $ rails g doorkeeper:migration $ rake db:migrate -
℟ק⊈ Resource Owner ֥ٚൔ # ⊈ Resource Owner ֥ٚمđᆰࢤࢤ Devise
resource_owner_authenticator do current_user || warden.authenticate!(:scope => :user) end config/initializers/doorkeeper.rb ※ Ӓܲٚ໓ࡱ -
New Tables • oauth_application - Clients Registration • oauth_access_grant -
Stores Auth Grant Codes • oauth_access_token - ᆇᆞނứԛಀ֥ Access Tokensđ ЇݣỚ∣֥ Refresh Token č≁℟ἬṅĎ -
New Routes Action(s) Path Ⴈ new /oauth/authorize Authorization Endpoint create
/oauth/authorize User ⇝ॖ൱ℭ֥ action destroy /oauth/authorize User ऋ䌉൱ℭ֥ action show /oauth/authorize/:code Local ṦℷႨ update /oauth/authorize Ĥ create /oauth/token Token Endpoint show /oauth/token/info Token Debug Endpoint resources /oauth/applications Clients ܵࢸ૫ (CRUD) index /oauth/authorized_applications User ܵ൱Ἶ֥ Clients destroy /oauth/authorized_applications/:id -
Doorkeeper Built-In™ ✔ Authorization Endpoint & Token Endpoint ✔ Token
Debug Endpoint čᄝ Implicit Flow ⇼⊈ Token ֥ᆇℯྟĎ ✔ Client Registration Interface (CRUD) ✔ User ܵ൱Ἶ֥ Clients ֥ࢸ૫čॖ RevokeĎ -
Building Resource Server Guard • Fetch Access Token via Rack::OAuth2
• Find Access Token from Model • Validate if Token is not Expired && not Revoked • Validate if Token has Sufficient Scopes • If All Valid, Pass to Grape API -
Fetch Access Token via Rack::OAuth2 • use Rack::OAuth2::Server::Resource::Bearer • ൙ℯഈᆺἌ≡Ϝ
yield ԛῲ֥ Token թᄝଖẕ • ೂݔ Request ҂ầ Token ࣼᆰࢤ Pass ֞༯ἠ stack • ෮ၛᆺଦῲ Fetch Token -
included do |base| # OAuth2 Resource Server Authentication use Rack::OAuth2::Server::Resource::Bearer,
'The API' do |request| # Authenticator only fetches the raw token string # Must yield access token to store it in the env request.access_token end end -
Find Access Token Instance • Doorkeeper::AccessToken.authenticate • → #find •
returns nil if not found -
Validate the Token • OAuth2::AccessTokenValidationService.validate • ᾋҰႵ㢻Ⴕ Expired a Revoked
• ॖၛẖ scopes Ṛ⅂ΆಀᾋҰ scope Ⴕ㢻Ⴕ -
def validate(token, scopes: []) if token.expired? return EXPIRED elsif
token.revoked? return REVOKED elsif !self.sufficent_scope?(token, scopes) return INSUFFICIENT_SCOPE else return VALID end end Token#expired?, Token#revoked? ൞ Doorkeeper ⤨ࡹ֥ -
def sufficent_scope?(token, scopes) if scopes.blank? # no scope required =>
any token is valid return true else # scopes required #=> Check sufficiently by Set comparison required_scopes = Set.new(scopes) authorized_scopes = Set.new(token.scopes) return authorized_scopes >= required_scopes end end ≾൞ቋᾏẪ֥ࠢކбᾱ ॖၛ၇ླℯቔဆෘم -
ቓ guard! ᄝ Grape 䥰૫Ẳᇾ class SecretAPI < Grape::API get
"hello" do guard! { greeting: "Hi,#{current_user.email}" } end end -
def guard!(scopes: []) token_string = get_token_string() if token_string.blank? raise
MissingTokenError elsif ( access_token = find_access_token(token_string) ).nil? raise TokenNotFoundError (in helpers block) -
def guard!(scopes: []) token_string = get_token_string() if token_string.blank? raise
MissingTokenError elsif ( access_token = find_access_token(token_string) ).nil? raise TokenNotFoundError ༵ሂԛ Token String (in helpers block) -
def guard!(scopes: []) token_string = get_token_string() if token_string.blank? raise
MissingTokenError elsif ( access_token = find_access_token(token_string) ).nil? raise TokenNotFoundError ༵ሂԛ Token String ሂ֥֞൞ॢሳԱđіൕ㢻ἡ Token (in helpers block) -
def guard!(scopes: []) token_string = get_token_string() if token_string.blank? raise
MissingTokenError elsif ( access_token = find_access_token(token_string) ).nil? raise TokenNotFoundError ༵ሂԛ Token String ሂ֥֞൞ॢሳԱđіൕ㢻ἡ Token Ⴕἡᅳ҂֞đ൞ Invalid Token (in helpers block) -
else case validate_access_token(access_token, scopes) when Oauth2::AccessTokenValidationService ::INSUFFICIENT_SCOPE raise InsufficientScopeError.new(scopes) when
Oauth2::AccessTokenValidationService::EXPIRED raise ExpiredError when Oauth2::AccessTokenValidationService::REVOKED raise RevokedError when Oauth2::AccessTokenValidationService::VALID @current_user = User.find(access_token .resource_owner_id) ennnd -
else case validate_access_token(access_token, scopes) when Oauth2::AccessTokenValidationService ::INSUFFICIENT_SCOPE raise InsufficientScopeError.new(scopes) when
Oauth2::AccessTokenValidationService::EXPIRED raise ExpiredError when Oauth2::AccessTokenValidationService::REVOKED raise RevokedError when Oauth2::AccessTokenValidationService::VALID @current_user = User.find(access_token .resource_owner_id) ennnd Scope ҂ژ -
else case validate_access_token(access_token, scopes) when Oauth2::AccessTokenValidationService ::INSUFFICIENT_SCOPE raise InsufficientScopeError.new(scopes) when
Oauth2::AccessTokenValidationService::EXPIRED raise ExpiredError when Oauth2::AccessTokenValidationService::REVOKED raise RevokedError when Oauth2::AccessTokenValidationService::VALID @current_user = User.find(access_token .resource_owner_id) ennnd Scope ҂ژ Ἶ௹ਔ -
else case validate_access_token(access_token, scopes) when Oauth2::AccessTokenValidationService ::INSUFFICIENT_SCOPE raise InsufficientScopeError.new(scopes) when
Oauth2::AccessTokenValidationService::EXPIRED raise ExpiredError when Oauth2::AccessTokenValidationService::REVOKED raise RevokedError when Oauth2::AccessTokenValidationService::VALID @current_user = User.find(access_token .resource_owner_id) ennnd Scope ҂ژ Ἶ௹ਔ Ӝ⇍ਔ -
else case validate_access_token(access_token, scopes) when Oauth2::AccessTokenValidationService ::INSUFFICIENT_SCOPE raise InsufficientScopeError.new(scopes) when
Oauth2::AccessTokenValidationService::EXPIRED raise ExpiredError when Oauth2::AccessTokenValidationService::REVOKED raise RevokedError when Oauth2::AccessTokenValidationService::VALID @current_user = User.find(access_token .resource_owner_id) ennnd Scope ҂ژ Ἶ௹ਔ Ӝ⇍ਔ OK ࣼ℟ current_user -
ቋᗥ൞ Error Response • Rack::OAuth2 䥰૫֥ᆰࢤଦῲႨ • ಌềğinsufficient_scope ҂ἡ WWW-Authenticate
• ၹ㬪ᅶ RFC 2617 ᆺႵ 401 ླေ߭≾ἠ Header -
error_classes = [MissingTokenError, TokenNotFoundError, ExpiredError, RevokedError, InsufficientScopeError] rescue_from *error_classes,
oauth2_bearer_token_error_handler (in included block) -
def oauth2_bearer_token_error_handler Proc.new {|e| response = case e when MissingTokenError
Rack::OAuth2::Server::Resource ::Bearer::Unauthorized.new when TokenNotFoundError Rack::OAuth2::Server::Resource ::Bearer::Unauthorized.new( :invalid_token,"Bad Access Token.") # etc. etc. end response.finish } end (in ClassMethods module) -
guard_all! class SecretAPI < Grape::API guard_all! get "hello" do {
greeting: "Hi,#{current_user.email}" } end end -
module ClassMethods def guard_all!(scopes: []) before do guard! scopes: scopes
end end end (in ClassMethods module) -
$ curl -i http://localhost:3000/api/v1/sample/secret HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="The
API" Content-Type: application/json Cache-Control: no-cache {"error":"unauthorized"} -
$ curl -i http://localhost:3000/api/v1/sample/secret \ > -H "Authorization: Bearer XXXXXXXX"
HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="Protected by OAuth 2.0", error="invalid_token", error_description="Token is expired. You can either do re-authorization or token refresh." Content-Type: application/json Cache-Control: no-cache {"error":"unauthorized"} č⁙แ TokenĎ -
$ curl -i http://localhost:3000/api/v1/sample/secret \ > -H "Authorization: Bearer 4ead67fc8917761a7f0cd1f0cae30e905fc93e0d2543032f58395e
5a55b9869e" HTTP/1.1 200 OK Content-Type: application/json {"greeting":"Hi, [email protected]"} -
Final Notes • Doorkeeper ≁℟㢻Ⴕ⅞Ῐ Client ֥ཋđὸ֤ေ⅞ • Doorkeeper ҂ିᆷקᆺῘଧུ
Flows Ῐਔ PR ὕ㢻 merge… • 㢻Ⴕྩ insufficient_scope Error ಌ WWW-Authenticate ֥↜ⅳ -
Conclusion • OAuth 2 Spec ồປҌᆩ֡ᄝἓખ • ồປ Spec →
෮Ⴕ API ෮Ⴕ Library ु֤ • ሱ࠭ᆜކ Grape ބ OAuth 2 ఃℯ㢻Ⴕޓₒ ᆺေ Spec ࣼ҂ₒ… -
Final Words • ၇ಖࡹ∗ಀồ specđၹ㬪സޓ؟↱ᾳ • Ⴍః൞ Security ֥҆ٺ •
Amazon ֥ OAuth 2 Login ໓ࡱቋᾑ -
References • RFC 6749 (Spec) tools.ietf.org/html/rfc6749 • RFC 6750 (Spec)
tools.ietf.org/html/rfc6750 • My Notes: blog.yorkxin.org/tags/OAuth • Many OAuth2-based API Documents