RFCに載ってるサンプル
まだDraftですがOAuth2のトークン交換のためのプロトコルが公開されています。
この仕様を利用することで、ベースとなる共通のトークンを1つだけ発行し、それを各コンポーネントで共有するといった設計が可能となります。
RFCにサンプルが載っているので、見てみましょう。
このサンプルでは、アプリとバックエンドサーバの間をフロントサーバが仲介し、トークンの交換を行うというシナリオになっています。
##アプリがフロントサーバに、リクエストを送る
GET /resource HTTP/1.1 Host: frontend.example.com Authorization: Bearer accVkjcJyb4BWCxGsndESCJQbdFMogUC5PbRDqceLTC
"accVkjcJyb4BWCxGsndESCJQbdFMogUC5PbRDqceLTC"が交換元となるアクセストークンです。
普通のOAuth2リクエストですね。
(この例では)アプリ側はトークン交換を意識せず、普通のOAuth2 APIと同じ感覚で使うことができそうです。
##フロントサーバが、認証サーバにトークン交換リクエストを送る
POST /as/token.oauth2 HTTP/1.1 Host: as.example.com Authorization: Basic cnMwODpsb25nLXNlY3VyZS1yYW5kb20tc2VjcmV0 Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&resource=https%3A%2F%2Fbackend.example.com%2Fapi%20&subject_token=accVkjcJyb4BWCxGsndESCJQbdFMogUC5PbRDqceLTC&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token
フロントサーバはアプリから受け取ったアクセストークンを認証サーバに転送し、新しいトークンを取得します。
その際に、grant_typeは"urn:ietf:params:oauth:grant-type:token-exchange"を指定し、subject_token_type=には"urn:ietf:params:oauth:token-type:access_token"を指定します(アクセストークンを元に交換する場合。例えばID Tokenの場合は"urn:ietf:params:oauth:token-
type:id_token")になります。
認証サーバはこのリクエストの内容と定められたポリシーを照らし合わせて交換の可否を決定します。
(例えばトークンのオーナーがサービスを退会してないかどうかを確認する等)
そして次のようなレスポンスが返ってくれば交換が成立です!!
HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-cache, no-store
{
"access_token":"eyJhbGciOiJFUzI1NiIsImtpZCI6IjllciJ9.eyJhdWQiOiJo
dHRwczovL2JhY2tlbmQuZXhhbXBsZS5jb20iLCJpc3MiOiJodHRwczovL2FzLmV
4YW1wbGUuY29tIiwiZXhwIjoxNDQxOTE3NTkzLCJpYXQiOjE0NDE5MTc1MzMsIm
F6cCI6InJzMDgiLCJzdWIiOiJiY0BleGFtcGxlLmNvbSIsInNjcCI6WyJhcGkiX
X0.vHJKtJ-zFIN75Tk7qGlmQsWPlvnChb2uSaGwPLvlWl64ts7-vvfwYDaVoXIQ
e_HkTVdljIzavVlPT60_b_9pDQ",
"issued_token_type":
"urn:ietf:params:oauth:token-type:access_token",
"token_type":"Bearer",
"expires_in":60
}
##フロントサーバは、入手したアクセストークンを使ってバックエンドサーバから情報を取得する
GET /api HTTP/1.1 Host: backend.example.com Authorization: Bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IjllciJ9.eyJhdWQ iOiJodHRwczovL2JhY2tlbmQuZXhhbXBsZS5jb20iLCJpc3MiOiJodHRwczovL2 FzLmV4YW1wbGUuY29tIiwiZXhwIjoxNDQxOTE3NTkzLCJpYXQiOjE0NDE5MTc1M zMsImF6cCI6InJzMDgiLCJzdWIiOiJiY0BleGFtcGxlLmNvbSIsInNjcCI6WyJh cGkiXX0.vHJKtJ-zFIN75Tk7qGlmQsWPlvnChb2uSaGwPLvlWl64ts7-vvfwYDa VoXIQe_HkTVdljIzavVlPT60_b_9pDQ
以上がサンプルは終わりです。
特に難しいところはありませんね。
#疑問
- 実はToken Refreshと実質的にやってることはそれほど変わらない?
- ID Tokenをsubject tokenに使うのは、セキュリティ的にどうなんだろうか?
- フロントサーバが毎回トークン交換してるとオーバーヘッドがが大きいので、アプリ側で交換を実施して、交換済みのトークンをフロントサーバに送った方がよい気がする(セキュリティ的には望ましくない?)。
- 実装してるサービスあるのか?