「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>JWTとOAuth2.0#f5007063]] * 目次 [#m5c50d67] #contents *概要 [#a089122f] -OAuth 2.0 JWT Bearer Token Flowとも呼ばれる。 -[[OAuth]] 2.0 / [[OIDC>OpenID Connect]]を拡張するアサーションの仕様で、[[RFC 7521>#pae256bf]], [[7523>#i523cb7d]]によって構成されている。 -[[OAuth]] 2.0では「クライアントは1回のリクエストにおいて二つ以上の認証方式を利用してはならない (MUST NOT).」と言われている。 -Tokenエンドポイントで、[[JWT]]([[JWS]]) で強化されたクライアント認証を使用して、OAuth 2.0のAccess Tokenを要求する方法を定義。 *クライアント認証 [#y8528205] 以下は、既定のクライアント認証が「[[無い場合>#f99e77d4]]」と「[[有る場合>#m4421be9]]」で場合分けした概要説明。 **(既定の)クライアント認証なしの場合 [#f99e77d4] -(既定の)クライアント認証を使用しない(別のクライアント認証として[[JWT]]([[JWS]]) を組み込む)。 -[[用例>#xd03a507]]にもあるGoogleやMicrosoft、SalesforceなどのWebAPI認証の方式として採用されている。 ***概要 [#wb2404fe] 事前に信頼関係を構築できるシステムからユーザによる認証・認可手順なしに直接Access Tokenを取得する。 -クライアントと事前に鍵交換して、 -クライアントの[[Self-Issued Assertion>#n8fdd9f7]]で署名する。 ***フロー [#d21e8fa8] [[JWT]](JWS)作成のための証明書を生成 or 取得する。 -証明書を登録する。 --Client側(秘密鍵) --Resource Server(Authorization Server)側(公開鍵) -Clientで[[JWT]](JWS)を署名し、Resource Server(Authorization Server)にリクエスト、 -Resource Server(Authorization Server)で[[JWT]](JWS)を検証し、Access Tokenをレスポンス。 -Clientから、Access Tokenを使用してResource Server(Authorization Server)にアクセスする。 **(既定の)クライアント認証ありの場合 [#m4421be9] -(既定の)クライアント認証を使用する(既定のクライアント認証に[[JWT]]([[JWS]]) を組み込む)。 -こちらは、[[用例>#xd03a507]]では紹介されていないが、[[OpenID Connectの既定のクライアント認証>OpenID Connect#y7bdab62]]のユースケース ***概要 [#m8c572cd] 以下に(既定の)クライアント認証をしてAccess Tokenを取得する。 -事前に信頼関係を構築できるシステム -既存のユーザによる認証・認可フロー ***フロー [#zb3d8932] -Client Credentialsグラント種別(既存フロー)と併用するユースケース --[[サーバ信頼セキュリティ モデル]]的。 --Client Credentialsなので「[[(既定の)クライアント認証をしない場合>#f99e77d4]]」のフローと大差ない。 -Authorization Codeグラント種別(既存フロー)と併用するユースケース --[[ベース クライアント セキュリティ モデル]]的。 --(既定の)クライアント認証として「[[OIDCでJWTのクライアント認証をする場合>OpenID Connect - クライアント認証#h9b10c6c]]」が参考になる。~ ※ ベース クライアント(≒ Resource Owner)の識別に[[JWT]]中のsubクレームの値を使用するため。 などのユースケースのフローがある。 ※ 仕様として定義されているのは、Tokenエンドポイントに対するリクエスト部のみ。 *仕様(7521) [#pae256bf] -単体では利用できず、[[RFC 7522, 7523のサブ仕様>#c65d5829]]の共通部分を抽象化した仕様。 -ClientとResource Server(Authorization Server)を統合するような状況下での利用が想定されている。 --Resource Ownerとしてのエンド・ユーザの介入を必要としない。 --client_secretを必要としない(Client Credentialsグラント種別の)代替メカニズム。 **フレームワーク [#v20f3211] [[ココ>JWT Secured Authorization Request (JAR)#m5a17a21]]とリンクしている。 ***Assertion Created by Third Party [#vf7e7da7] こちらも、[[用例>#xd03a507]]では紹介されていないが、~ Authorization Server(STS)によってAssertionを生成する。 -フロー Relying Party Client Token Service | | | | | 1) Request Assertion | | |------------------------>| | | | | | 2) Assertion | | |<------------------------| | 3) Assertion | | |<-------------------------| | | | | | 4) OK or Failure | | |------------------------->| | | | | | | | ***Self-Issued Assertion [#n8fdd9f7] ローカルでAssertionを生成する。 -フロー Relying Party Client | | | | 1) Create | | Assertion | |--------------+ | | | | | 2) Assertion | | |<-------------+ | 3) Assertion | |<-------------------------| | | | 4) OK or Failure | |------------------------->| | | | | **アサーション [#h34941bb] これを使って[[アクセストークン・リクエスト>#a82c2f7a]]する。 ***文脈上 [#i1c8aa27] この文脈上でのアサーションは、 -Authorization Serverは、 --一般的に認可付与の短命表現で、~ アサーションの有効期間を越えるアクセストークンを発行すべきでない。 --アサーション許可要求に応答して ---リフレッシュトークンが発行せず、 ---アクセストークンを短い寿命で発行する。 -Clientは、 --同じアサーションを使用して新しいアサーションを要求したり、 --有効・若しくは新しいアサーションを使用して、~ 期限切れのアクセストークンをリフレッシュしたり、 >できる。 ***タイプ [#h0cefaa0] -[[Bearer Assertions(持参人切符)>トークン#b38de47f]] --本仕様に適したタイプのアサーション --アサーションを所有しているすべてのエンティティは、 ---関連するリソースへのアクセスを取得するために(暗号鍵の所持を証明することなく)アサーションを使用できる。 ---誤用を防止するために、アサーションは、保管・移送における露見から保護する必要がある。 ---権限のない当事者にアサーションを漏らさないために、安全な通信チャネルを使用。 -[[Holder-of-Key Assertions(記名式切符)>トークン#b38de47f]] --本仕様に適さないタイプのアサーション(確かに仕様名からして ... だったら書くな。と、) --アサーションを提示するエンティティは、関連するリソースにアクセスするには、追加の暗号資料の所持を証明する必要がある。 --従って、 ---Authorization Server(STS)は、アサーションにキー識別子をバインドする。 ---Clientは、アサーションを提示するときに、その識別子に対応するキーを~ 知っていることをResource Server(Authorization Server)に示す必要がある。 --鍵所有者アサーションシステムのベースラインとして使用することができるが、場合によっては、以下が必要になる。 ---(秘密鍵の所有証明をサポートするための)追加のメカニズム ---セキュリティモデルの変更(例えば、 オーディエンスの要件を緩和するため)。 ***クレームセット [#p574a133] 以下のクレームが必要。 -必須 --iss~ Client認証に使用する。 ---[[Assertion Created by Third Party>#vf7e7da7]]の場合、~ Authorization Server(STS)のID = [[IDトークン>OpenID Connect#ofb73c59]]のissの値と同じになる。 ---[[Self-Issued Assertion>#n8fdd9f7]]の場合、~ client_id = [[IDトークン>OpenID Connect#ofb73c59]]のaudの値と同じになる。 --sub~ Resourceへのアクセス許可を付与する先を決定する。 ---[[サーバ信頼セキュリティ モデル]]の場合、~ client_id = [[IDトークン>OpenID Connect#ofb73c59]]のaudの値と同じになる。 ---[[ベース クライアント セキュリティ モデル]]の場合、~ Resource OwnerのID = [[IDトークン>OpenID Connect#ofb73c59]]のsubの値と同じになる。~ ※ Authorization Codeグラント種別(既存フロー)と併用するユースケース --aud~ Resource Server(Authorization Server)のID = [[IDトークン>OpenID Connect#ofb73c59]]のissの値と同じになる。 --exp -オプション --nbf --iat --jti --Assertion ID~ アサーションの一意の識別子。 ---他のエンティティが誤って同じ識別子を割り当てないことを保証しなくてはならない。 ---ワンタイム使用アサーションのメッセージ重複排除を必要とする実装によって使用される可能性がある。 --認可リクエストに設定するパラメタ --[[(既定の)クライアント認証なし>#f99e77d4]]~ 必要に応じて、認可リクエストに設定するパラメタを追加 ---scope~ [[(既定の)クライアント認証なし>#f99e77d4]]=[[Googleの例>#f5ac0fc6]]など、~ (既定の)クライアント認証を使用しない場合、scopeが必要になる。 --[[(既定の)クライアント認証あり>#m4421be9]] 認可リクエストに設定したパラメタを使用するので不要 ***署名 [#h4756c73] -署名またはメッセージ認証コードを生成する -アルゴリズムは任意(この仕様の範囲外) **パラメタ [#aed15519] -TLS(Transport Layer Security)が必須。 -アサーションの認可付与としての使用を定義。 ***grant_type [#eef72461] -[[(既定の)クライアント認証なし>#f99e77d4]]~ urn:ietf:params:oauth:grant-type:* --urn:ietf:params:oauth:grant-type:saml2-bearer --urn:ietf:params:oauth:grant-type:jwt-bearer -[[(既定の)クライアント認証あり>#m4421be9]]~ 既存のフローのgrant_typeを使用する。 --grant_type=client_credentials --grant_type=authorization_code~ authorization_codeなので、codeも必要(code=XXXX) ***scope [#x0b3b1ff] 要求された範囲は、[[OAuth 2.0 [RFC6749]>OAuth#v698197b]]の3.3節に記述されているとおり。 -[[(既定の)クライアント認証なし>#f99e77d4]]~ [[Googleの例>#f5ac0fc6]]など、既定のクライアント認証を使用しない場合、 --認可リクエストが存在しないので、 --[[クレームセット>#p574a133]]中には必要になる。 -[[(既定の)クライアント認証あり>#m4421be9]] --認可リクエストとして送信済みなので、 --[[クレームセット>#p574a133]]中からは不要になる。 ***client_id [#c3be6c2e] パラメタに依存するクライアント認証の形式が使用されている場合にのみ必要。 -[[(既定の)クライアント認証なし>#f99e77d4]]~ --認可リクエストが存在しないので、 --[[クレームセット>#p574a133]]中には別の形式で(iss、subとして)必要になる。 -[[(既定の)クライアント認証あり>#m4421be9]] --認可リクエストで、client_idが必要になる。 --が、[[クレームセット>#p574a133]]中には別の形式で(iss、subとして)必要になる。 ---[[サーバ信頼セキュリティ モデル]]:client_id = iss = sub ---[[ベース クライアント セキュリティ モデル]]:client_id = iss ≠ sub ***assertion [#k4e1e004] -[[(既定の)クライアント認証なし>#f99e77d4]]~ [[RFC7523>#i523cb7d]]のアサーションを参照。 -[[(既定の)クライアント認証あり>#m4421be9]]~ 不要 ***client_assertion_type [#y8e7d02b] -[[(既定の)クライアント認証なし>#f99e77d4]]~ 不要 -[[(既定の)クライアント認証あり>#m4421be9]]~ urn:ietf:params:oauth:grant-type:* --urn:ietf:params:oauth:grant-type:saml2-bearer --urn:ietf:params:oauth:grant-type:jwt-bearer ***client_assertion [#d6680711] -[[(既定の)クライアント認証なし>#f99e77d4]]~ 不要 -[[(既定の)クライアント認証あり>#m4421be9]]~ [[RFC7523>#i523cb7d]]のアサーションを参照。 **リクエスト・レスポンス [#u7d06247] ***アクセストークン・リクエスト [#a82c2f7a] -[[(既定の)クライアント認証なし>#f99e77d4]] --ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3AX-bearer& assertion=SAML2 or JWT assertion -[[(既定の)クライアント認証あり>#m4421be9]] --grant_type=authorization_code版 ---ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded ---ボディ grant_type=authorization_code& code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3AX-bearer& client_assertion=SAML2 or JWT assertion --grant_type=client_credentials版 ---ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded ---ボディ grant_type=client_credentials& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3AX-bearer& client_assertion=SAML2 or JWT assertion ***アクセストークン・レスポンス [#m7f17c23] 仕様中に明記なし。 ***エラー・レスポンス [#u137f3a9] -[[OAuth 2.0 [RFC6749]>OAuth#v698197b]]で定義されているエラー応答を構成 --https://tools.ietf.org/html/rfc6749#section-5.2 -[[(既定の)クライアント認証なし>#f99e77d4]]~ アサーションが有効でないか期限が切れた場合、 --Authorization Serverは、 ---"error"パラメータの値は "invalid_grant"エラーコードでなければならない。 ---"error_description"または "error_uri"パラメータを使用して、~ アサーションが無効とみなされた理由に関する追加情報を含めることができる。 --例 ---ヘッダ HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store ---ボディ { "error":"invalid_grant", "error_description":"Audience validation failed" } -[[(既定の)クライアント認証あり>#m4421be9]] --Authorization Serverは、 ~ アサーションが有効でないか複数のクライアント認証メカニズムが使用されている場合、 ---"error"パラメータの値は "invalid_client"エラーコードでなければならない。 ---"error_description"または "error_uri"パラメータを使用して、~ クライアントのアサーションが無効であると考えられた理由に関する追加情報を含めることができる。 --例 ---ヘッダ HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store ---ボディ { "error":"invalid_client" "error_description":"assertion has expired" } **セキュリティに関する考慮事項 [#c569fe33] -[[RFC 7522, 7523>#c65d5829]]などを使用すれば、大方問題ない。 -その他、 --SSL/TLSを使用する。 --Assertion IDを実装する。 *仕様(7523) [#i523cb7d] [[RFC 7521>#pae256bf]]のアサーションに[[JWT(JWS)アサーション>#s121ce30]]を使用したもの。 **[[JWT]](JWS)アサーション [#s121ce30] これを使って[[アクセストークン・リクエスト>#yf148536]]する。 ***ペイロード(クレームセット) [#od912bf1] -[[コチラ>#p574a133]]を参考に、 -必須(MUST) --"iss" (issuer) claim --"aud" (audience) claim --"sub" (subject) claim --"exp" (expiration time) claim~ -してもよい(MAY) --"iat" (issued at) claim --"jti" (JWT ID) claim~ = Assertion ID --"nbf" (not before) claim~ トークンを受け入れてはならない前の時間を識別する。 ***[[JWT]](JWS)の例 [#f5ac0fc6] -以下、RFCの[[JWT]](JWS)~ よくよく確認すると、URLはなに?(Scheme?) --ヘッダ {"alg": "ES256"、 "kid": "16"} --ペイロード { "iss":"https://jwt-idp.example.com", "sub":"mailto:mike@example.com", "aud":"https://jwt-rp.example.net", "nbf":1300815780, "exp":1300819380, "http://claims.example.com/member":true } -以下、Googleの[[JWT]](JWS)~ よくよく確認すると、subが無かったりする。 --ヘッダ { "alg": "RS256", "typ": "JWT" } --ペイロード { "iss":"サービスアカウントのメールアドレス", "scope":"利用するAPIのスコープ", "aud":"https://www.googleapis.com/oauth2/v3/token", "exp":"トークンの有効期限To", "iat":"トークンの有効期限From", } **パラメタ [#jab8a61d] -[[仕様(7521)のパラメタ>#aed15519]]と同じ。 -client_assertionだけ、以下のような注釈有リ。 --1つの[[JWT]](JWS)、複数の[[JWT]](JWS)を含んではならない。 **リクエスト・レスポンス [#ne5367ec] ***アクセストークン・リクエスト [#yf148536] -[[(既定の)クライアント認証なし>#f99e77d4]] --ヘッダ POST /token.oauth2 HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer& assertion=...JWS... -[[(既定の)クライアント認証あり>#m4421be9]] --ヘッダ POST /token.oauth2 HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=authorization_code& code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer& client_assertion=...JWS... ***アクセストークン・レスポンス [#o199c57d] 仕様中に明記がないが、Googleでのレスポンスは以下の通り。 { "access_token":"XXXXXXXXXX", "token_type":"bearer", "expires_in":nnnnn } ※ ポイント : refresh_tokenを返さない。 ***エラー・レスポンス [#n2b1c5ca] [[仕様(7521)のエラー・レスポンス>#u137f3a9]]と同じ。 **署名アルゴリズム [#feca38aa] 本仕様中に記載はないが、[[コチラ>OpenID%20Connect#h9b10c6c]]を参考にするとイイ。 本仕様中に記載はないが、[[コチラ>OpenID Connect#h9b10c6c]]を参考にするとイイ。 *参考 [#uea38a81] **RFC 7521, 7522, 7523 [#c65d5829] -RFC 7521 - Assertion Framework for~ OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7521 --RFC7522(SAMLアサーション) ---RFC 7522 - Security Assertion Markup Language (SAML) 2.0 Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7522 --RFC7523(JWTアサーション) ---RFC 7523 - JSON Web Token (JWT) Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7523 **用例 [#xd03a507] ***Googleの例 [#pe004c1a] 以下を見ると、 -C#とCoreTweetを使って簡単にTwitterへツイートするbotを作る - 酢ろぐ!~ http://blog.ch3cooh.jp/entry/20140808/1407464147 --Google Analytics API を使って前日の PV を取得するコードを C# で書いてみた - しばやん雑記~ http://blog.shibayan.jp/entry/20140803/1407059293 通常の[[OAuth]] 2.0の -[[Authorization Codeグラント種別>OAuth#yfeb403d]] -[[Implicitグラント種別>OAuth#m5c2d510]] 以外に、 [[クライアント証明書(pfx形式の電子証明書)>証明書#sd119f77]]を使って、~ サービスアカウントで認証する方法がある模様。 ちなみに、ここでは、Google.Apis.Analytics Client Libraryに~ 処理がラッピングされていたため。詳細が不明だったが、 以下を見ると、このClient Libraryの中では、[[JWT]]が使用されている模様。 -JWTを使ってGoogleAPIのアクセストークン取得する - Carpe Diem~ http://christina04.hatenablog.com/entry/2015/06/04/224159 -IdM実験室: [JWT/OAuth]Service Accountを使ってGoogle APIを利用する --http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api.html --http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api_5.html これが、 >「JWT bearer token authorizationグラント種別」 の用例である模様。 -GoogleのOAuth 2.0実装からみえたClientの扱い - r-weblife~ http://d.hatena.ne.jp/ritou/20121104/1352036133 上記のサイトには、 >Service Accounts = JWT Bearer Token Profile であることが明記されている。 ***Microsoft ([[AzureAD>Microsoft Azure Active Directory]]) の例 [#vdf678b9] [[Google>#pe004c1a]]と同様に、以下を見ると、 -Azure AD : ログインをしない Backend Server-Side アプリの開発 (Daemon など) – Tsmatz~ https://blogs.msdn.microsoft.com/tsmatsuz/2015/04/09/azure-ad-backend-server-side-deamon-service/ -Azure ADに登録されているAPI用のアクセストークンをJWTで取得するには | hrendoh's memo~ http://blog.hrendoh.com/active-directory-dotnet-daemon-certificate-credential/ --Authenticating to Azure AD in daemon apps with certificates | Microsoft Azure~ https://azure.microsoft.com/ja-jp/resources/samples/active-directory-dotnet-daemon-certificate-credential/ 通常の[[OAuth]] 2.0の -[[Authorization Codeグラント種別>OAuth#yfeb403d]] -[[Implicitグラント種別>OAuth#m5c2d510]] 以外に、 >「JWT bearer token authorizationグラント種別」 をサポートしている模様。 ただし、処理は、[[ADAL(Active Directory Authentication Library)>https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-authentication-libraries]]~ にラップされているため[[JWT]]作成処理の詳細などを見ることは出来ない。 -active-directory-dotnet-daemon-certificate-credential/Program.cs~ at master · Azure-Samples/active-directory-dotnet-daemon-certificate-credential~ https://github.com/Azure-Samples/active-directory-dotnet-daemon-certificate-credential/blob/master/TodoListDaemonWithCert/Program.cs ***Salesforceの例 [#w40dd954] 以下のQiita記事を参照すると、Salesforceは、 -OAuth 2.0 JWT べアラートークンフロー -OAuth 2.0 SAML ベアラーアサーションフロー の2つのフローをサポートしている模様。 -OAuth2 JWT Bearer Token フローを使ってSalesforceへアクセスする - Qiita~ http://qiita.com/stomita/items/4542ce1b48e5fa849ef1 --help.salesforce. ---OAuth 2.0 JWT べアラートークンフロー~ https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&language=ja&type=0 ---OAuth 2.0 SAML ベアラーアサーションフロー~ https://help.salesforce.com/articleView?id=remoteaccess_oauth_SAML_bearer_flow.htm&language=ja&type=0 >原理はほぼ同じで、[[SAML]]より[[JWT]]のほうが動作環境的な制約は少ないとのこと。 ---- Tags: [[:IT国際標準]], [[:認証基盤]], [[:クレームベース認証]], [[:OAuth]]