LoginSignup
6
5

More than 5 years have passed since last update.

OAuth2 Token Exchangeのサンプルを見てみた

Last updated at Posted at 2016-06-06

RFCに載ってるサンプル

まだDraftですがOAuth2のトークン交換のためのプロトコルが公開されています。
この仕様を利用することで、ベースとなる共通のトークンを1つだけ発行し、それを各コンポーネントで共有するといった設計が可能となります。

token exchange.png

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に使うのは、セキュリティ的にどうなんだろうか?
  • フロントサーバが毎回トークン交換してるとオーバーヘッドがが大きいので、アプリ側で交換を実施して、交換済みのトークンをフロントサーバに送った方がよい気がする(セキュリティ的には望ましくない?)。
  • 実装してるサービスあるのか?
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5