token request

トークンエンドポイント (OAuth)

[104] トークンエンドポイント (token endpoint) は、 クライアントアクセストークンを発行する認可鯖上のエンドポイントです。

仕様書

OAuth 1.0 トークン要求

[8] クライアントは、資源所有者認可の後、 トークン要求 (token request) によりトークンcredentialsから得ることができます。

[9] トークン要求は、クライアントcredentialsと (トークンcredentialsのかわりに) 一時credentialsを使って認証された要求です >>7

oauth_token一時credentials識別子となります。

[10] トークン要求は、原則として要求メソッド POST を使います >>7が何らかの方法で他の要求メソッド広告した場合には、 そちらを使うこともできます >>7

[11] トークン要求は、が何らかの方法で広告したトークン要求エンドポイント要求URLとして使います >>7

[105] このエンドポイントないし URLOAuth 1.0 は特に名前を与えていませんでしたが、 OAuth 2.0トークンエンドポイントに相当します。

[13] は、トークン要求保安輸送路を使わなければなりません >>7

[12] クライアントは、資源所有者認可の結果得られた検証符号 (を資源所有者経由で知ったもの) を oauth_verifier 引数に指定しなければなりません >>7

[132] Twitter xAuth はそのかわりに x_auth_password, x_auth_username, x_auth_mode の指定を求めています >>131

[138] OAuth Session Extension はそのかわりに oauth_session_handle を指定し、また一時credentialsのかわりに現行のアクセストークンを使うことで、 アクセストークンの更新ができるとしています >>137

[139] 後の OAuth 2.0更新トークンに相当する機能です。

[171] クライアントoauth_body_hash 引数を指定するべきではありません >>170

[14] は、トークン要求を受信したら次の点を確認しなければなりません >>7

[19] 確認できたなら、状態符号 200MIME型 application/x-www-form-urlencodedpayload body応答とします >>7

[195] Twitterapplication/x-www-form-urlencoded を使いながらも、 Content-Type: には text/html を指定します。このためクライアントContent-Type: ヘッダーを無視しなければなりません。

[20] payload body には次の引数を含めなければなりません >>7

payload body (application/x-www-form-urlencoded)
oauth_token
トークン識別子
oauth_token_secret
トークン共有秘密

[136] OAuth Session Extension は更に次の引数を追加しています。

[192] Twitter は次の引数を追加しています。

[177] Flickr は次の引数を追加しています >>176

[169] はてなは次の引数を追加しています >>168

[184] Dropboxuid 引数を追加しています >>183

[187] Evernoteedam_noteStoreUrledam_userIdedam_expires を追加しています >>186

[135] OAuth 1.0 本体仕様としてはエラー時の応答については規定していません。 OAuth Problem Reporting Extension は報告方法を規定しており、 実装によってはこれに対応しています。

OAuth 2.0 トークンエンドポイント

[35] 認可鯖トークンエンドポイント (token endpoint) は、 クライアント認可承諾更新トークンを使ってアクセストークンを得るために使うものです。 トークンエンドポイントは、 暗示的承諾型以外の承諾型 (認可符号資源所有者合言葉credentialsクライアントcredentials) で使います。 >>34

トークンエンドポイントへの要求

[36] クライアントトークンエンドポイントの位置を知る方法は OAuth の仕様の範囲外とされていますが、普通はサービスドキュメントで示されます >>34

[38] トークンエンドポイントTLS を使わなければなりません >>34, >>89アクセストークン更新トークンを転送する場合は HTTPS鯖認証を使わなければなりません >>89クライアントRFC 6125 により認可鯖TLS証明書を検証しidentity認証しなければなりません >>89

[37] トークンエンドポイントURLapplication/x-www-form-urlencoded 形式の query を含んでも構いません。素片識別子を含んではなりませんquery が含まれる場合、引数を追加するときにはそのまま残さなければなりません>>34

[199] feedlyContent-Type: application/json を指定することで JSON payload body によって引数を指定することを認めています >>197

[48] クライアントは、認可符号からアクセストークンを得るためにトークンエンドポイント要求を送信する場合、 application/x-www-form-urlencoded payload body により次の引数を指定します >>52

payload body (application/x-www-form-urlencoded)
grant_type
authorization_code でなければなりません >>52
code
受信した認可符号を指定しなければなりません >>52
redirect_uri
認可エンドポイントへの要求で redirect_uri 引数を指定した場合は、同じ値を指定しなければなりません >>52
client_id
クライアント認証しない場合は指定しなければなりません >>52, >>34
code_verifier
PKCE

[120] Azureresource 引数を追加しています >>119

[150] Salesforcecode_verifier, format を追加しています >>149

[50] クライアントは、資源所有者credentials からアクセストークンを得るため (資源所有者合言葉credentialsフロー) にトークンエンドポイント要求を送信する場合、 application/x-www-form-urlencoded payload body により次の引数を指定します >>61

payload body (application/x-www-form-urlencoded)
grant_type
password でなければなりません >>61
username
資源所有者利用者名を指定しなければなりません >>61
password
資源所有者合言葉を指定しなければなりません >>61
scope
アクセス要求の適用範囲を指定できます >>61

[66] クライアントは、クライアントcredentials からアクセストークンを得るため (クライアントcredentialsフロー) にトークンエンドポイント要求を送信する場合、 application/x-www-form-urlencoded payload body により次の引数を指定します >>65

payload body (application/x-www-form-urlencoded)
grant_type
client_credentials でなければなりません >>65
scope
アクセス要求の適用範囲を指定できます >>65

[125] Azureresource 引数を追加しています >>124

[146] reddit は場合によって grant_type=https://oauth.reddit.com/grants/installed_client を使います。また device_id 引数を追加しています。 >>145

[2] クライアントは、更新トークン からアクセストークンを得るためにトークンエンドポイント要求を送信する場合、 application/x-www-form-urlencoded payload body により次の引数を指定します >>1

payload body (application/x-www-form-urlencoded)
grant_type
refresh_token でなければなりません >>1
refresh_token
クライアントに発行されている更新トークンを指定しなければなりません >>1
scope
アクセス要求の適用範囲を指定できます >>1。 元々資源所有者承諾された適用範囲以外を指定してはなりません >>1。 省略すると、元々資源所有者承諾された適用範囲を表します >>1

[122] Azureresource 引数を追加しています >>119

[158] Salesfoceformat 引数を追加しています >>157

[203] assertion を使う場合は、 grant_type 引数assertion の種別を表す絶対URLassertion 引数assertion の値とします。 scope 引数も指定できます。 >>202

[70] 例えば SAML 2.0 が拡張の承諾型を規定しています。

[69] クライアントは、拡張の承諾型の規定に従いトークンエンドポイント要求を送信する場合、 grant_type 引数絶対URLを指定し、 必要に応じて追加の引数も指定します >>68

[116] GoogleOAuth 1.0 から OAuth 2.0 への移行のために grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1 を提供していました。 OAuth 2.0 クライアント認証OAuth 1.0 による HTTP認証、省略可能な scope 引数を指定することで、 更新トークンを得ることができるものです。

[123] Azuregrant_type という名前で response_type 引数に相当するものを指定させています >>119, >>124

[41] 要求引数は、複数指定してはなりません >>34

[160] SurveyMonkeypayload body ではなく URL queryapi_key 引数を指定することを求めています >>159

[189] GitLab要求payload bodyJSON によって引数を指定させています >>188

[39] クライアントトークンエンドポイントへの要求POST 要求メソッドを使わなければなりません >>34

[162] Facebook >>164fouresquare >>161GET を使っているようです。

クライアント認証

[22] クライアントは、トークンエンドポイントrevokeエンドポイントへの要求で、 client_id 引数を指定できます。また、 場合によっては認証に必要な情報を指定しなければなりません。

[23] 認可サーバーは、トークンエンドポイントrevokeエンドポイントで、 場合によってはクライアント認証を行わなければなりません。

[24] 詳細は、OAuth 2.0クライアント認証を参照。

[25] TLSクライアント認証とは関係ありません。

トークンエンドポイントの処理

[83] 認可鯖は、認識できない引数を無視しなければなりません >>34

[40] 要求引数に値が含まれなければ、指定されなかったものと扱わなければなりません >>34

application/x-www-form-urlencoded= が含まれない場合を指しているのでしょうか? 空文字列が指定された場合と区別する必要があるということでしょうか??

[54] 認可鯖は、認可符号からアクセストークンの発行を求められている場合、 認可符号が妥当なものであることを確認しなければなりません >>52認可符号は1回しか使えません。

[100] 攻撃者は大量の要求クライアントに適当な認可符号を与え、認可鯖にアクセスさせることで、 間接的に認可鯖HTTP接続を枯渇させる DoS攻撃を試みるかもしれません。 認可鯖には攻撃者の情報がほとんど届かず、対策が難しい攻撃です。 認可鯖は不適切な認可符号があまりに多いクライアントには誤り応答を返すべきかもしれません >>99

[53] 認可鯖は、認可符号からアクセストークンの発行を求められている場合、

のいずれかを満たすことを確認しなくてはなりません >>52, >>89

[102] 攻撃対象のクライアントがいわゆるOAuthログインを実装している場合において、攻撃者の有するクライアントに攻撃対象の資源所有者を誘導して認可符号を取得し、その認可符号を攻撃対象のクライアントに与えることで、攻撃者が攻撃対象クライアントにおける攻撃対象資源所有者になりすましてログインできてしまいます >>101公開クライアントに関してこれを防ぐことはできません。

[43] つまり実行環境非公開のウェブサーバー内部でトークンエンドポイントを呼び出す Webサービスのような利用形態なら、認可鯖が適切に検査していれば、 クライアントcredentials が流出しない限りにおいて、 たとえ認可符号が流出したとしても攻撃は防げます。 ところが一般配布されるスマートフォンアプリのような利用形態だと、 クライアントcredentials は攻撃者も入手可能な状態にあるので、 認可符号の流出は致命的な問題になります。

[44] 流出の可能性として考えられるのは、

などでしょうか。

[54] 認可鯖は、認可符号からアクセストークンの発行を求められている場合、 認可エンドポイントへのアクセス時に redirect_uri 引数が指定されていたなら本要求にも redirect_uri 引数が含まれており、両者の値が一致することを確認しなければなりません >>52, >>89

[62] 認可鯖は、資源所有者credentials からアクセストークンの発行を求められている場合、 指定された credentials を検証しなければなりません >>52

[3] 認可鯖は、更新トークンからアクセストークンの発行を求められている場合、 指定された更新トークンを検証しなければなりません >>1クライアント認証可能であれば、正しいクライアントか検証しなければなりません >>89

[63] 認可鯖は、回数制限や警告などにより、資源所有者合言葉credentials総当たり攻撃からエンドポイントを保護しなければなりません >>52

[95] 認可鯖CSRF 対策が必要です。資源所有者credentials を第三者に漏らしてしまう形の攻撃は難しそうですが、認可鯖 (や間接的にクライアント) に対する DoS攻撃や、 CSRF を引き起こされた被害者たる Webブラウザーの利用者への嫌がらせには使えるかもしれません。

[96] その性質上、CSRF 対策用のトークンを指定させるような方法は使えません。 Origin: ヘッダーの値とクライアントの登録情報を比較して不適切な要求を検出するのがよいでしょうか。

トークンエンドポイントの応答

[56] 認可鯖は、アクセストークンの発行を求められている場合、 要求が妥当であり認可されたなら、アクセストークンを発行します >>55, >>64, >>67, >>68, >>1

[4] 認可符号資源所有者合言葉credentials、拡張の承諾型では、 更新トークンも発行することもできます >>55, >>64, >>68。 ただしクライアント認証していない場合には発行するべきではないかもしれません >>89

[5] クライアントcredentialsでは、 更新トークンを発行するべきではありません >>67

[6] 更新トークンからアクセストークンを求めている場合には、 新しい更新トークンを発行しても構いません。その適用範囲 (scope) は元の更新トークンと同じでなければなりません。 その場合には認可鯖は古い更新トークンを取り消し (revoke) して構いませんし、クライアントは古い更新トークンを破棄しなければなりません>>1

[72] その場合には、 200 応答で次の引数JSON (application/json) payload bodyJSONオブジェクトの名前と値 (文字列なら JSON文字列数値なら JSON数値) に含めます >>71

payload body (JSONオブジェクト)
[73] access_token
認可鯖が発行したアクセストークンを指定しなければなりません >>71
[74] token_type
発行したトークンの種類を指定しなければなりません >>71
[75] expires_in
アクセストークン寿命単位で指定するべきです >>71
[76] refresh_token
同じ認可承諾を使って新しいアクセストークンを得られる更新トークンを指定できます >>71
[77] scope
クライアントが要求した適用範囲アクセストークン適用範囲が異なるなら、指定しなければなりません。同じ場合も指定できます。 >>71
[107] id_token
OpenID Connect の場合には指定しなければなりません >>108

[78] どれが文字列でどれが数値かは明確ではありませんが、 expires_in数値、それ以外は文字列と思われます。

[106] アクセストークン型によっては、更に追加の引数を指定する必要があるかもしれません。

[117] grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1 では、 refresh_token (更新トークン) のみが返されることになっていました。

[121] Azureresource 引数expires_on 引数を追加しています >>119

[134] ヤマレコtoken_type 引数を指定せず、 成功時でも error 引数error_message 引数 (独自) を指定するようです >>133

[148] Instagramtoken_type 引数を指定せず、 user 引数 (独自) を指定するようです >>147

user の値は JSONオブジェクトです。

[173] BitlyapiKey 引数 (独自) を指定するようです。 ただし非推奨で削除予定とあります。 >>172

[179] Herokuuser_idsession_nonce を指定するようです >>178

[182] Yahoo!xoauth_yahoo_guid を指定するようです >>181

[198] feedlyplan を指定するようです >>197

[143] foursquare など >>161, >>163, >>142, >>172token_type 引数を指定しないようです。

[194] Facebooktoken_type 引数を指定しません。 expires_in ではなく expires 引数time_t 値を指定するようです。

[152] Salesforcetoken_type 引数を指定しないようです。 独自の id, instance_url, issued_at, signature を指定するようです。 >>149, >>156, >>157

[151] Salesforce要求format 引数を指定した場合に応答が他のMIME型になるようです >>149, >>157

[167] GitHub要求Accept: を指定した場合に応答が他の MIME型になるようです。既定値は application/x-www-form-urlencoded になっているようです。 >>166

[193] Facebook応答application/x-www-form-urlencoded を使うようです。ただし Content-Type: はなぜか text/plain; charset=UTF-8 になります。

[30] その後 JSON に修正 (非互換変更) されています >>29


[42] 応答引数は、複数指定してはなりません >>34

[79] 更に、 Cache-Control: no-storePragma: no-cache を含めなければなりません >>71

[80] クライアントは、認識できない名前の引数を無視しなければなりません >>71


[56] 認可鯖は、アクセストークンの発行を求められている場合、 クライアント認証に失敗したか要求が非妥当であったなら、 誤り応答を返します >>55, >>64, >>67, >>68, >>1

[88] その場合には、 400 応答で次の引数JSON (application/json) payload bodyJSONオブジェクトの名前と値 (文字列なら JSON文字列数値なら JSON数値) に含めます >>87

payload body (JSONオブジェクト)
[84] error
誤り符号を指定しなければなりません >>87
[85] error_description
人間可読誤りの説明を指定して構いません >>87
[86] error_uri
人間可読誤りの説明を含むWebページURL を指定して構いません >>87

[126] 誤り符号によっては、他の HTTP 状態符号を使うこともあるようです。

[127] Azuretimestamptrace_idcorrelation_iderror_codes を追加しています >>128

[51] errorinvalid_client の場合には、 401 応答とすることもできます。 クライアントAuthorization: ヘッダー認証を試みた場合には、 401 応答WWW-Authenticate: ヘッダー (auth-scheme要求で指定されたもの) を使って応答しなければなりません >>87

メモ

[196] draft-richer-oauth-xml-01 - Alternate Encoding for OAuth 2 Token Responses ( 版) https://tools.ietf.org/html/draft-richer-oauth-xml-01

[26] Twitter Login にも CSRF 脆弱性ができやすい罠が!? - OAuth.jp (Nov Matake著, ) http://oauth.jp/blog/2014/06/23/csrf-on-twitter-login/

Access Token 取得時のリクエストの署名に、Request Token Secret を使わなくてもいいんです。なので Session に紐づいた Request Token Secret が空の場合にそれをそのまま空文字列として処理してしまう RP は、正常に Access Token を受け取れてしまいます。

つまり、攻撃者が被害者にこんな URL を踏ませると、被害者は攻撃者の Twitter アカウントを使ってあなたのサイトにログインできてしまう可能性があるのです。

https://client.example.com/callback?

oauth_token=<request-token-authorized-by-attacker>&

oauth_verifier=<valid-oauth-verifier>

[27] Private-Webmention - IndieWeb () https://indieweb.org/Private-Webmention

Link: https://aaronpk.example/token; rel="token_endpoint"

[28] token-endpoint - IndieWeb () https://indieweb.org/token-endpoint

[29] Changelog(更新履歴) - Graph API ( ()) https://developers.facebook.com/docs/apps/changelog#v2_3_changes

access_tokenのコードを交換した際に返されるhttps://www.facebook.com/v2.3/oauth/access_tokenの応答フォーマットが、URLエンコードされるのではなく、有効なJSONを返すようになりました。 この応答の新しいフォーマットは、{"access_token": {TOKEN}, "token_type":{TYPE}, "expires_in":{TIME}}です。RFC 6749のセクション5.1に準拠するために、このアップデートを行いました。

[31] SlackOAuth 2.0 対応していることになっているが、トークンエンドポイント相当は似て非なる、 互換性のない別物。