OAuth原理與Laravel Passport實作(3)
OAuth 2.0內建四種授權認證流程(Grant Flow)
在OAuth 2.0中所定義的授權流程有四種,這四種不一定都要實作,主要是看你的業務需求而定
參考 Spec 的 1.3. Authorization Grant與4. Obtaining Authorization
Authorization Code Grant
是授權認證流程中最嚴謹的,認證的流程主要是Client向Resource Owner請求Authorization Code然後Client拿到Authorization Code再向Authorization Server拿Access Token
PS: AuthorizationGrant內有Authorization Code
假設角色:
- 延續OAuth 角色互動關係的定義(系列1)
資料定義:
- User-Agent通常是指Web Browser
- Client Identifier是向Authorization Server申請的Client ID
- Redirection URI代表Authorization Code要回傳的網址,本次情境為圖片編輯網
- User authenticates代表Resource Owner授權動作
- Authorization Code就是包含在Authorization Grant的一種字串代碼
步驟:
- (A)圖片編輯網將小明的User-Agent轉址到Google OAuth認證授權頁,轉址採用Authorization Request請求,定義基本格式參數,如上圖就是Client Identifier與Redirection URI
- (B)小明在Google OAuth認證授權頁授權權限給圖片編輯網
- (C)Google OAuth認證授權頁在將小明User-Agent轉回Redirection URI並帶有Authorization Code,圖片編輯網就接收到Authorization Code
- (D)圖片編輯網再向Google Auth出示Authorization Code與Redirection URI
- (E)Google Auth認證Authorization Code與Redirection URI需與(A)的Redirection URI一樣後再回傳Access Token與Refresh Token(看業務邏輯)
請求流程:
- (A)Authorization Request -> (C)Authorization Response
- (D)Access Token Request -> (E)Access Token Response
適用場景:
- 需要 User-Agent 通常是可以Redirection(轉址)
- 可能需要核發Refresh Token
- 適合 Confidential Clients (需要保密的客戶),通常是部署在Server上的服務
(A)Authorization Request(GET)
由Client發起給Resource Owner,Resource Owner執行授權將Resource Owner的User-Agent轉址到Authorization Endpoint,這個轉址過程就是Authorization Request
User-Agent -> Authorization Endpoint
Authorization Endpoint下一章節會提到,簡單來說Authorization Server有一個服務端是用來接收授權認證的接口
請求參數:
response_type要填code
GET /oauth/authorize?client_id=3&redirect_uri=http%3A%2F%2Fclient.oauth.test%2Ftoken&response_type=code&scope=Email&state=1234 HTTP/1.1Host: service.oauth.test
(C)Authorization Response
Authorization Endpoint確認授權完成,將帶有Authorization Grant的User-Agent轉址到Redirection Endpoint,這過程就是Authorization Response
Authorization Endpoint -> User-Agent -> Redirection Endpoint
Redirection Endpoint下一章節會提到,簡單來說Client有一個Redirection Endpoint服務接口專門在接收Authorization Grant
參數:
Authorization Request發送後的Redirection Endpoint接口
Redirection Endpoint接口接收到Authorization Grant由於Authorization Request有帶state回來時也要判斷是否一樣,防止CSRF並且也會帶回來Authorization Code
GET /token?code=def50200927ae0c85cfb1a99a1394058463b4...&state=1234Host: client.oauth.test
Spec 4.1.2. Authorization Response是用302但是1.7. HTTP Redirections指出不強制使用302,依照各自實作細節決定
(D) Access Token Request(POST)
Client拿到Authorization Grant向Token Endpoint發出請求,這步驟為Access Token Request
Client -> Token Endpoint
Token Endpoint下一章節會提到,簡單來說Authorization Server有一個服務接口專門在接收Authorization Grant並發行Access Token
請求參數:
Spec 4.1.3. Access Token Request中只提到client_id並未說明要帶client_secret,但是client_id說請參考3.2.1. Client Authentication又參考2.3.1. Client Password確實是要帶client_secret做Client做認證,Laravel這邊的做法也是需要帶client_secret,猜想可能是這個原因
(E)Access Token Response
Authorization Server處理完Token Endpoint接收的Access Token Request請求,認證Authorization Code合法後將Access Token回傳給Client,這個回傳內容就是Access Token Response
Token Endpoint -> Client
參數:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"eyJ0eXAiOiJKV1QImI6ImEwZWI2YjY0NWY1OGMzZWU....",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"def5020074acbe6e2d9c855e3873874ff1ff0b04.....",
}
Implicit Grant
在Authorization Code中Client會先取得Authorization Grant再透過Authorization Code向Authorization Server取Access Token,而Implicit Grant會跳過Client取Authorization Grant直接向Authorization Server取Access Token
此流程Access Token是經由Redirection URI傳遞所以存在資料洩漏的風險,所以Resource Owner與其使用的設備是看的到,可以透過事先設定Redirection URI來防止Access Token傳給非認證的網站
Implicit Grant禁止發行Refresh Token
假設角色:
- 延續OAuth 角色互動關係的定義(系列1)
資料定義:
- User-Agent通常是指可以Redirection(轉址)
- Client Identifier是向Authorization Server申請的Client ID
- Redirection URI代表Access Token要回傳的網址
- User authenticates代表Resource Owner授權動作
- Web-Hosted Client Resource代表執行應用程式的Server,如手機本身
步驟:
- (A)圖片編輯網將小明的User-Agent轉址到Google OAuth認證授權頁,轉址採用Authorization Request請求,定義基本格式參數,如上圖就是Client Identifier與Redirection URI
- (B)小明在Google OAuth認證授權頁授權權限給圖片編輯網
- (C)Google OAuth認證授權頁在將小明User-Agent轉回Redirection URI並帶有Access Token,這時Access Token並非保存在Request而是以Fragment方式保存在User-Agent,也就是單純以#串在Redirection URI後面(稍後解釋)
- (D)此時User-Agent經由Redirection URI會先跑到Web-Hosted Client Resource
- (E)Web-Hosted Client Resource在將Redirection URI這段網址組成Script(網頁)回傳給User-Agent
- (F)User-Agent得到Script後解出Access Token
- (G)Client就拿到Access Token
Fragment就是指Url後面的#,這種Request是取不到資料的,所以才適合應用在JavaScript或是移動裝置應用程式上
http://client.oauth.test/token#access_token=eyJ0eXAiOiJKV1Q
(E)(F)這段組成Script部分我理解的不是很好,但就Laravel來說會在Redirection URI+’#’+Access Token,這是包含在headers一起回傳給Client
當Redirection URI回http://client.oauth.test/在Laravel中想用Request來取得完整URL在解析出#後的Access Token,這是沒辦法的,因為伺服器不會處理這種請求的參數,所以只能利用JavaScript這類去取得Browser上的URL再來解析取得Access Token
Laravel中配置Implicit Grant流程
切到oauth_service專案
cd oauth_service
到app/Providers/AuthServiceProvider.php加上
Passport::enableImplicitGrant();
response_type要填token
執行http://client.oauth.test/authorize回到/token時Request內並不會包Access Token,所以這個route只能做View的輸出讓JavaScript來幫我們解析Access Token
在resources/view新增一個implicit_token.blade.php內容為以下
<script>
console.log(location.hash.split('&'));
</script>
將/token route改成以下
Route::get('/token', function (Request $request) {
return view('implicit_token');
});
瀏覽http://client.oauth.test/authorize讓JavaScript取出Access Token
適用場景:
- 需要 User-Agent 通常是指可以Redirection(轉址)
- JavaScript應用程式
- 移動裝置應用程式
請求流程:
- (A)Authorization Request -> (C)(D)(E)Authorization Response
(A)Authorization Request(GET)
同Authorization Code的(A)Authorization Request
(C)(D)(E)Authorization Response
Authorization Endpoint確認授權完成,將Access Token以Fragment方式串在Redirection URI後面包在User-Agent回傳到Redirection URI,這部分就是Authorization Response
Authorization Endpoint ->User-Agent
參數:同Authorization Code的(E)Access Token Response
Resource Owner Password Credentials Grant
該流程將Resource Owner 的帳號密碼當成Authorization Grant讓Client直接向Authorization Server做認證取Access Token,此流程非常信任Client才適用,像是第三方所開發的應用程式,如內建或官方應用程式,非必要請勿將此流程開發給第三方使用
假設角色:
- 延續OAuth 角色互動關係的定義(系列1)
資料定義:
- Resource Owner Password Credentials指的是Resource Owner帳密
步驟:
- (A)圖片編輯網想存取小明的Google雲端圖片所以請小明授權Google OAuth的存取權限,所以小明提供他在Google雲端上的帳密
- (B)圖片編輯網向Google OAuth提交小明Google雲端上的帳密
- (C)Google OAuth認證圖片編輯網與小明的帳號為合法則回傳Access Token與Refresh Token(可選)
在OAuth原理與Laravel Passport實作(2)中有有執行過以下,這個指令已建置Resource Owner Password Credentials流程的Client ID與secret
php artisan passport:install
每一種Grant Flow都有對應的Client ID與secret,拿Implicit Grant來當作Resource Owner Password Credentials的Client ID與secret是不合法的
更改/token route
grant_type要更改為password
username/password小明的帳密
Authorization更改成Resource Owner Password Credentials的Client ID與secret
適用場景:
- 內建或官方應用程式,需非常信任Client
請求流程:
- (A)Authorization Request and Response -> (B)Access Token Request
- (B)Access Token Request -> (C)Access Token Response
(A)Authorization Request and Response
Resource Owner向Client取得帳密,這個段就是Authorization Request
如何向Resource Owner取帳密,屬於自行實作細節
(B)Access Token Request(POST)
Client拿到Resource Owner帳密後向Token Endpoint請求Access Token,這段就是Access Token Request
Client -> Token Endpoint
請求參數:
(C)Access Token Response
Token Endpoint認證合法後回傳Access Token與Refresh Token(可選),這個回傳就是Access Token Response
Token Endpoint -> Client
參數:同Authorization Code的(E)Access Token Response
Client Credentials Grant
將Client的Client ID與secret當作Authorization Grant向Authorization請求Access Token,意思就是Client自己去請求Access Token時或Protected Resources屬於Client情況
假設角色:
- 延續OAuth 角色互動關係的定義(系列1)
資料定義:
- Client Authentication指的是Client ID與secret
步驟:
- (A)圖片編輯網想存取自己放在Google雲端上的圖片,利用之前向Google OAuth註冊時所拿到的帳密向Google OAuth授權存取
- (B)Google OAuth認證Client ID與secret合法後回傳Access Token與Refresh Token(不建議)
在OAuth原理與Laravel Passport實作(2)中有有執行過以下,這個指令已建置Resource Owner Password Credentials流程的Client ID與secret
php artisan passport:install
每一種Grant Flow都有對應的Client ID與secret,拿Implicit Grant來當作Client Credentials的Client ID與secret是不合法的
更改/token route
grant_type要更改為client_credentials
Authorization更改成Client Credentials的Client ID與secret
適用場景:
- Resource Owner就是Client
- 部署在Server上的應用程式
請求流程:
(A)Access Token Request ->(B)Access Token Response
Authorization Request and Response
因為不存在Resource Owner且Client ID與secret就是Authorization Grant所以不需要此流程
(A)Access Token Request(POST)
Client發送Client ID與secret向Token Endpoint請求Access Token,這動作就是Access Token Request
Client -> Token Endpoint
請求參數:
(B)Access Token Response
Token Endpoint認證Client ID與secret合法後回傳Access Token與Refresh Token(不建議),回傳這個動作就是Access Token Response
Token Endpoint -> Client
參數:同Authorization Code的(E)Access Token Response