Revocation 與 Introspection

OAuth 2.0 對於授權流程的規範非常清楚,但它僅僅只定義到 client 拿到 token 而已。

但有兩件事並沒有在 RFC 6749 裡定義:

  1. 使用者要如何撤銷授權,也就是讓 token 失去作用
  2. 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 tokenrefresh 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 endpointtoken endpoint 或今天提到的兩個 endpoint,都算是授權伺服器來的 metadata,相關訊息是由 RFC 8414 定義的。

參考資料