Revocation 與 Introspection
OAuth 2.0 對於授權流程的規範非常清楚,但它僅僅只定義到 client 拿到 token 而已。
但有兩件事並沒有在 RFC 6749 裡定義:
- 使用者要如何撤銷授權,也就是讓 token 失去作用
- resource server 要如何檢驗 token
這兩件事分別在 2013 年的 RFC 7009 - OAuth 2.0 Token Revocation 與 2015 年的 RFC 7662 - OAuth 2.0 Token Introspection 裡定義。
Token Revocation
RFC 7009 定義了 client 要如何主動地撤銷(revocation)授權。以「透過 Facebook 登入 iT 邦幫忙」這個範例為例,在需要做撤銷的時機即為「登出」。因此在登出的時候需要呼叫 Facebook 提供的 revocation endpoint。
這是一個非常簡單的協定,直接參考 RFC 7009 的範例:
POST /revoke HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token
此 API 需使用 POST 方法,並且必須對 client 做驗證。參數說明如下:
名稱 | 必要 | 說明 |
---|---|---|
token | REQUIRED | 想要撤銷的 token |
token_type_hint | OPTIONAL | token 類型的提示 |
因為 token 會有多種類型,如 access token 或 refresh token,因此若有提示將有助於授權服務器最佳化處理。而以撤銷的目的來說,不管是成功處理,或是 client 傳了一個無效的 token,授權伺服器皆可回傳給 client 200 的回應。
而相對的若是出現錯誤,則可以參考 RFC 6749 裡面對錯誤回應的定義,RFC 7009 則是多定義了 unsupported_token_type
,它代表授權服務無法處理 token_type_hint
所表示的類型(如 refresh token)
Token Introspection
類似地,RFC 7662 是定義如何檢查 token 的資訊,就 token endpoint 回傳的資訊畢竟還是不夠用。這個協定定義了一個 API 稱之為 introspection endpoint,它能提供更多 token 的相關資訊。
這個協定也非常簡單,參考 RFC 7662 的範例:
POST /introspect HTTP/1.1
Host: server.example.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
token=mF_9.B5f-4.1JqM&token_type_hint=access_token
此 API 需使用 POST 方法,並且必須對 client 做驗證。參數說明如下:
名稱 | 必要 | 說明 |
---|---|---|
token | REQUIRED | 想要檢查的 token |
token_type_hint | OPTIONAL | token 類型的提示 |
成功回應會是一個 JSON object,因為是檢查,所以回傳的資訊有定義很多:
名稱 | 必要 | 說明 |
---|---|---|
active | REQUIRED | token 是否還可用 |
scope | OPTIONAL | 使用者實際授權的範圍 |
client_id | OPTIONAL | 是哪個 client 要求授權 |
username | OPTIONAL | 使用者 ID |
token_type | OPTIONAL | token 的格式,如 access token |
exp | OPTIONAL | Token 失效時間 |
iat | OPTIONAL | Token 發行時間 |
nbf | OPTIONAL | Token 需要過了這個時間點才能開始使用 |
sub | OPTIONAL | 使用者識別碼 |
aud | OPTIONAL | 允許接受 ID Token 的單位 |
iss | OPTIONAL | 發行單位 |
jti | OPTIONAL | JWT 的 ID |
其中因為 active
是必填項,代表此 API 可以拿來讓 resource server 做為檢查用。這裡也可以注意到有許多欄位是 JWT 曾看到過的,所以可以聯想得到這個 API 有某種程度是在做類似 JWT 的自我驗證的事。
另外也許有人會好奇,introspection 的使用情境應該比較像 GET,怎麼會用 POST?這是因為 RESTful 在討論的是 guideline,而不是協定或規範,因此考量的點是不同的。舉個例,不管是 OAuth 2.0 或是 OpenID Connect,所有 HTTP 呼叫大多都是 GET 或 POST;編碼都是 application/x-www-form-urlencoded
,這主要是為了考慮向下相容性。而至於為何用 POST,推測應該是因為避免讓 access log 出現 token 的資訊。
額外一提
在整個流程所參與到的角色來說,有 authorization endpoint、token endpoint 或今天提到的兩個 endpoint,都算是授權伺服器來的 metadata,相關訊息是由 RFC 8414 定義的。