MS_JWTBearerGrant - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
- 戻る(JWTとOAuth2.0)
- JWT bearer token authorizationグラント種別
- OpenID Connect - クライアント認証
- OAuth 2.0 拡張
OAuth 2.0 JWT Bearer Token Flow とも呼ばれる。
-
より高度なClient Credentials グラント種別的仕組み
(ユーザによる認証・認可手順なしに直接 Access Token を取得する)。 -
OAuth 2.0 では
「クライアントは 1 回のリクエストにおいて二つ以上の認証方式を利用してはならない (MUST NOT)」
と言われている。 -
Token エンドポイントで、JWT(JWS) で強化されたクライアント認証を使用して、
OAuth 2.0 の Access Token を要求する方法を定義。
補足(何が嬉しいのか):
client_secretは
共有秘密なので、認可サーバ側にも同じ値が保存され、
通信のたびにネットワークに流れる。
JWT アサーションは秘密鍵で署名した短命の JWT を毎回作って送るため、
- 秘密の値そのものは決して流れない
- 認可サーバは公開鍵だけを持てばよい
exp/jtiで再利用を防げるという利点がある。
Google / Microsoft / Salesforce のサーバ間 API 認証が
いずれもこの方式を採るのはこのためである。
- 以下は、既定のクライアント認証が
「有る場合」と
「無い場合」で「場合分け」した概要説明。 - 前者は既存のグラントタイプ中に組み込み、
後者は新設されたurn:ietf:params:oauth:grant-type:jwt-bearerと言う
新しいグラントタイプを使用する。 - 注:「既定のクライアント認証が無い場合 = Public クライアントの場合」と言う事ではない
(そもそも Public クライアントでの利用は想定されていない)。
クライアントの身元も独立して検証したい場合は、既存のグラントタイプ中に組み込む。
移行メモ(衍字): 「クライアントの身元も独立して検証したい場合は前者は、」の
重複を整理した。
- 既存の「IdP-SP/RP」のクライアント認証に、
Self-Issued Assertionで署名した JWT(JWS) を組み込む。 - こちらは、用例では紹介されていないが、
OpenID Connect の既定のクライアント認証のユースケース
-
Client Credentials グラント種別(既存フロー)と併用するユースケース
- サーバ信頼セキュリティ モデル的。
- Client Credentials なので
「(既定の)クライアント認証をしない場合」の
フローと大差ない。
-
Authorization Code グラント種別(既存フロー)と併用するユースケース
- ベース クライアント セキュリティ モデル的。
- (既定の)クライアント認証として
「OIDC で JWT のクライアント認証をする場合」が参考になる。
※ ベース クライアント(≒ Resource Owner)の識別に JWT 中のsubクレームの値を使用するため。
などのユースケースのフローがある。
※ 仕様として定義されているのは、Token エンドポイントに対するリクエスト部のみ。
「JWT の発行者の信頼だけで十分」若しくは「クライアント特定が不要・不可」な場合は
新設されたグラントタイプを使用する。
- (既定の)クライアント認証を使用しない
(別の信頼できる他システムが発行した JWT(JWS) を使用する。 -
用例にもある Google や Microsoft、Salesforce などの
WebAPI 認証の方式として採用されている。
JWT(JWS) 作成のための証明書を生成 or 取得する。
- 単体では利用できず、RFC 7522, 7523 のサブ仕様の共通部分を抽象化した仕様。
- Client と Resource Server(Authorization Server)を統合するような状況下での利用が想定されている。
- Resource Owner としてのエンド・ユーザの介入を必要としない。
-
client_secretを必要としない(Client Credentials グラント種別の)代替メカニズム。
JWT Secured Authorization Request (JAR)とリンクしている。
(既定の)クライアント認証ありの場合、
ローカルで Assertion を生成する。
- フロー
Relying
Party Client
| |
| | 1) Create
| | Assertion
| |--------------+
| | |
| | 2) Assertion |
| |<-------------+
| 3) Assertion |
|<-------------------------|
| |
| 4) OK or Failure |
|------------------------->|
| |
(既定の)クライアント認証なしの場合で、
用例で紹介されていないが「別の信頼できる他システム」によって Assertion を生成する。
- フロー
Relying
Party Client Token Service
| | |
| | 1) Request Assertion |
| |------------------------>|
| | |
| | 2) Assertion |
| |<------------------------|
| 3) Assertion | |
|<-------------------------| |
| | |
| 4) OK or Failure | |
|------------------------->| |
| | |
これを使ってアクセストークン・リクエストする。
この文脈上でのアサーションは、
-
Authorization Server は、
- 一般的に認可付与の短命表現で、
アサーションの有効期間を越えるアクセストークンを発行すべきでない。 - アサーション許可要求に応答して
- リフレッシュトークンを発行せず、
- アクセストークンを短い寿命で発行する。
- 一般的に認可付与の短命表現で、
-
Client は、
- 同じアサーションを使用して新しいアサーションを要求したり、
- 有効・若しくは新しいアサーションを使用して、
期限切れのアクセストークンをリフレッシュしたり、
できる。
補足(リフレッシュ トークンが要らない理由): クライアントは
いつでも自分で新しいアサーションを作れる(秘密鍵を持っているため)ので、
リフレッシュ トークンを預かって管理する必要がない。
後述の Google の例で「refresh_token を返さない」のはこのためである。
-
- 本仕様に適したタイプのアサーション
- アサーションを所有しているすべてのエンティティは、
- 関連するリソースへのアクセスを取得するために
(暗号鍵の所持を証明することなく)アサーションを使用できる。 - 誤用を防止するために、アサーションは、保管・移送における露見から保護する必要がある。
- 権限のない当事者にアサーションを漏らさないために、安全な通信チャネルを使用。
- 関連するリソースへのアクセスを取得するために
-
Holder-of-Key Assertions(記名式切符)
-
本仕様に適さないタイプのアサーション(確かに仕様名からして ... だったら書くな。と、)
-
アサーションを提示するエンティティは、関連するリソースにアクセスするには、
追加の暗号資料の所持を証明する必要がある。 -
従って、
- Authorization Server(STS) は、アサーションにキー識別子をバインドする。
- Client は、アサーションを提示するときに、その識別子に対応するキーを
知っていることを Resource Server(Authorization Server)に示す必要がある。
-
鍵所有者アサーションシステムのベースラインとして使用することができるが、
場合によっては、以下が必要になる。- (秘密鍵の所有証明をサポートするための)追加のメカニズム
- セキュリティモデルの変更(例えば、オーディエンスの要件を緩和するため)。
-
補足(アサーションとアクセス トークンは別物): ここで
「Bearer」「Holder-of-Key」と言っているのは
クライアントが送るアサーションの話であって、
結果として発行されるアクセス トークンの話ではない。
仕様名が「JWT bearer token」なのは前者を指す。
発行されるアクセス トークンを記名式にする話は
「OAuth2.0 Proof of Possession」以降の仕様が扱う。
以下のクレームが必要。
-
必須
-
iss
Client 認証に使用する。-
Self-Issued Assertionの場合、
client_id= ID トークンのaudの値と同じになる。 -
Assertion Created by Third Partyの場合、
Authorization Server(STS) の ID = ID トークンのissの値と同じになる。
-
-
sub
Resource へのアクセス許可を付与する先を決定する。-
サーバ信頼セキュリティ モデルの場合、
client_id= ID トークンのaudの値と同じになる。 -
ベース クライアント セキュリティ モデルの場合、
Resource Owner の ID = ID トークンのsubの値と同じになる。
※ Authorization Code グラント種別(既存フロー)と併用するユースケース
-
-
aud
Resource Server(Authorization Server)の ID =
ID トークンのissの値と同じになる。 -
exp
-
-
オプション
-
nbf -
iat -
jti -
Assertion ID
アサーションの一意の識別子。- 他のエンティティが誤って同じ識別子を割り当てないことを保証しなくてはならない。
- ワンタイム使用アサーションのメッセージ重複排除を必要とする実装によって使用される可能性がある。
-
認可リクエストに設定するパラメタ
-
(既定の)クライアント認証あり
認可リクエストに設定したパラメタを使用するので不要 -
(既定の)クライアント認証なし
必要に応じて、認可リクエストに設定するパラメタを追加
-
-
- 署名またはメッセージ認証コードを生成する
- アルゴリズムは任意(この仕様の範囲外)
- TLS(Transport Layer Security)が必須。
- アサーションの認可付与としての使用を定義。
-
(既定の)クライアント認証あり
既存のフローのgrant_typeを使用する。grant_type=client_credentials-
grant_type=authorization_code
authorization_codeなので、code も必要(code=XXXX)
-
(既定の)クライアント認証なし
urn:ietf:params:oauth:grant-type:*jwt-bearersaml2-bearer
要求された範囲は、OAuth 2.0 [RFC6749]の 3.3 節に記述されているとおり。
-
- 認可リクエストとして送信済みなので、
- クレームセット中からは不要になる。
-
(既定の)クライアント認証なし
Google の例など、既定のクライアント認証を使用しない場合、- 認可リクエストが存在しないので、
- クレームセット中には必要になる。
パラメタに依存するクライアント認証の形式が使用されている場合にのみ必要。
-
- 認可リクエストで、
client_idが必要になる。 - が、クレームセット中には別の形式で(
iss、subとして)必要になる。-
サーバ信頼セキュリティ モデル:
client_id=iss=sub(対象者はクライアント) -
ベース クライアント セキュリティ モデル:
client_id=iss≠sub(対象者は認証されたユーザ)
-
サーバ信頼セキュリティ モデル:
- 認可リクエストで、
-
- 認可リクエストが存在しないので、
-
クレームセット中には別の形式で(
iss、subとして)必要になる。
(既定の)クライアント認証ありに対応するパラメタ。
-
client_assertion_type
urn:ietf:params:oauth:grant-type:*urn:ietf:params:oauth:grant-type:saml2-bearerurn:ietf:params:oauth:grant-type:jwt-bearer
-
client_assertion
RFC7523のアサーションを参照。
移行メモ(正誤):
client_assertion_typeの値は
urn:ietf:params:oauth:**client-assertion-type**:jwt-bearerである
(grant-typeではない)。
後述のリクエスト例では正しくclient-assertion-typeと書かれている。
(既定の)クライアント認証なしに対応するパラメタ。
RFC7523のアサーションを参照。
-
-
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
-
-
-
-
ヘッダ
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
-
仕様中に明記なし。
-
OAuth 2.0 [RFC6749]で定義されているエラー応答を構成
-
-
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" }
-
-
-
(既定の)クライアント認証なし
アサーションが有効でないか期限が切れた場合、-
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" }
-
-
移行メモ(例の記述): 1 つ目のエラー例の JSON は、
元ページでは"error":"invalid_client"の行末にカンマが無かったため補った。
-
RFC 7522, 7523などを使用すれば、大方問題ない。
-
その他、
- SSL/TLS を使用する。
- Assertion ID を実装する。
RFC 7521のアサーションにJWT(JWS) アサーションを使用したもの。
これを使ってアクセストークン・リクエストする。
-
アサーションのクレームセットを参考に、
-
必須(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
トークンを受け入れてはならない前の時間を識別する。
-
-
以下、RFC の JWT(JWS)
よくよく確認すると、URL はなに?(Scheme?)-
ヘッダ
{"alg": "ES256", "kid": "16"} -
ペイロード
{ "iss":"https://jwt-idp.example.com", "sub":"mailto:[email protected]", "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" }
-
補足(上記 2 つの疑問への答え):
- 「URL はなに?」 …
iss/audの値は
URI 形式の識別子であって、実際にアクセスできる必要はない
(mailto:スキームが使われているのもこのため)。
ただし実装によってはaudに Token エンドポイントの実 URL を要求する。- 「
subが無い」 … Google のサービス アカウントは
iss自身に対して権限を要求する(=subがissと同じ)ため、
省略されている。
他のユーザになりすまして API を呼ぶ
ドメイン全体の委任を使う場合は、subに対象ユーザの
メール アドレスを入れる。
- 仕様(7521)のパラメタと同じ。
-
client_assertionだけ、以下のような注釈有リ。
移行メモ(読み取り): 上記は
「client_assertionには JWT を 1 つだけ含めること
(複数含めてはならない)」という意味である。
-
-
ヘッダ
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...
-
-
-
ヘッダ
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...
-
仕様中に明記がないが、Google でのレスポンスは以下の通り。
{
"access_token":"XXXXXXXXXX",
"token_type":"bearer",
"expires_in":nnnnn
}※ ポイント : refresh_token を返さない。
本仕様中に記載はないが、
「OpenID Connect - クライアント認証」を参考にするとイイ。
-
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
- RFC 7522 - Security Assertion Markup Language (SAML) 2.0 Profile
-
RFC7523(JWT アサーション)
- RFC 7523 - JSON Web Token (JWT) Profile
for OAuth 2.0 Client Authentication and Authorization Grants
https://tools.ietf.org/html/rfc7523
- RFC 7523 - JSON Web Token (JWT) Profile
-
以下を見ると、
- C#とCoreTweetを使って簡単にTwitterへツイートするbotを作る - 酢ろぐ!
http://blog.ch3cooh.jp/entry/20140808/1407464147- Google Analytics API を使って前日の PV を取得するコードを C# で書いてみた - しばやん雑記
http://blog.shibayan.jp/entry/20140803/1407059293
- Google Analytics API を使って前日の PV を取得するコードを C# で書いてみた - しばやん雑記
通常の OAuth 2.0 の
以外に、
クライアント証明書(pfx 形式の電子証明書)を使って、
サービスアカウントで認証する方法がある模様。
ちなみに、ここでは、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を利用する
これが、
「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 Azure Active Directory)
Googleと同様に、以下を見ると、
- 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/
- Authenticating to Azure AD in daemon apps with certificates | Microsoft Azure
通常の OAuth 2.0 の
以外に、
「JWT bearer token authorization グラント種別」
をサポートしている模様。
ただし、処理は、
ADAL(Active Directory Authentication Library)
にラップされているため 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
補足(ADAL は廃止): ADAL は 2022 年 12 月にサポート終了し、
後継は **MSAL(Microsoft Authentication Library)**である。
証明書によるクライアント認証(private_key_jwt)は
MSAL でもWithCertificate()として同じ形で提供されている。
以下の 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.com
- 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
- OAuth 2.0 JWT べアラートークンフロー
- help.salesforce.com
Tags: IT国際標準, 認証基盤, クレームベース認証, OAuth