103 views
# (OpenID Connect Core 1.0) 6. Passing Request Parameters as JWTs ###### tags: `oauth2/oidc` 担当::@kyosu: [toc] 本文:https://openid.net/specs/openid-connect-core-1_0.html#JWTRequests OIDC では Authorization Request に署名および暗号化を可能にするため、以下の Authorization Request パラメータを定義する。 - `request` - **OPTIONAL** - このパラメータにより、OpenID Connect リクエストを単一の self-contained なパラメータとすることができ、任意で署名および暗号化を施せるようになる。パラメータ値は Request Object 値である (Section 6.1 参照)。Request Object は、各 Claim がリクエストパラメータとなる JWT である。 - Discovery 結果 の中で `request_parameter_supported` パラメータによりサポート状況が分かる - OP がこのパラメータをサポートしていないにも関わらず RP がこれを利用する場合、OP は request_not_supported エラーを返すこと (**MUST**) - `request_uri` - **OPTIONAL** - このパラメータにより、値そのものではなく参照を送ることが可能になる。request_uri 値は https スキーマで始まる URL であり, Request Object 値を含むリソースへの参照となる。参照先の Request Object は、リクエストパラメータを含む JWT である。 - Discovery 結果の中で `request_uri_parameter_supported` パラメータによりサポート状況が分かる。 - OP がこのパラメータをサポートしていないにも関わらず RP がこれを利用する場合、OP は request_uri_not_supported エラーを返すこと (**MUST**) これらのパラメータを利用したリクエストは JWT として表現され(この JWT は Request Object と呼ばれる)、その値もしくは参照が送信される。 リクエストを参照渡しすることで、長大なリクエストを扱いやすくなる。(メリットの詳細は 6.2.4. “request_uri” Rationale を参照) 上記のパラメータのいずれかを利用する場合は、同一リクエスト中で他方を利用してはならない。(**MUST NOT**) :::info Google, MS, Slack の各社で提供している OP のサポート状況を確認してみる。 - Google - https://accounts.google.com/.well-known/openid-configuration - いずれのパラメータも存在しない - MS - https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration - request_uri_parameter_supported パラメータは false - request_parameter_supported パラメータは存在せず - Slack - https://slack.com/.well-known/openid-configuration - request_parameter_supported パラメータは fals - request_uri_parameter_supported パラメータは true https://openid.net/specs/openid-connect-discovery-1_0.html の仕様では以下のようになっている。 - request_uri_parameter_supported - OPTIONAL. Boolean value specifying whether the OP supports use of the request_uri parameter, with true indicating support. If omitted, **the default value is true**. - request_parameter_supported - OPTIONAL. Boolean value specifying whether the OP supports use of the request parameter, with true indicating support. If omitted, **the default value is false**. つまり、省略されている場合は request_uri_parameter_supported は true, request_parameter_supported は false と default値となる。 google はいずれも省略されているが、[認証 URI パラメータ](https://developers.google.com/identity/openid-connect/openid-connect?hl=ja#authenticationuriparameters) を見る限り request_uri はサポートされていなそう 参考 - [zenn: OpenID Connect のリクエストオブジェクト(Request Object)を調べてみた](https://zenn.dev/nhosoya/articles/629f8db46de3bf43a7b9) ::: ## 6.1. Passing a Request Object by Value - request を利用する際には JWT に含まれる OIDC パラメータ値が OAuth2.0 リクエストシンタックスで送信されるパラメータにとって代わる。しかし、Request Object を利用する場合にでも、パラメータを OAuth2.0 リクエストシンタックスでも送信することができる。(**MAY**)こうすることで、キャッシュ可能で署名済(および暗号化済)の Request Obuject 値に静的なリクエストパラメータを含め、リクエストごとに可変パラメータ (state, nonce 等)を OAuth2.0 パラメータとして送信することなどが可能となる。 - リクエスト自体を有効な OAuth 2.0 Authorization Request とするため, response_type および client_id パラメータは OAuth 2.0 リクエストシンタックスでリクエストに含まねばならない (**MUST**)。これは OAuth 2.0 で必須とされている (**REQUIRED**)。もし Request Object にもこれらと同じパラメータが含まれている場合は、2つのパラメータは一致しなければならない (**MUST**)。 - scope パラメータが Request Object に含まれる場合でも、scope パラメータは OAuth 2.0 リクエストシンタックスで openid scope を含んだ形で送信しなければならない (**MUST**)。これにより下位レイヤーの OAuth 2.0 処理系に、当該リクエストが OpenID Connect リクエストであることを明示することができる。 - Request Object は、署名付きでも良いし、署名無しの平文でも良い。平文の場合、JWS ヘッダーに none アルゴリズム ([JWA] 参照) を指定すること。署名付きの場合、Request Object は iss (issuer) および aud (audience) を含むべきである (**SHOULD**)。RP 以外の主体に署名されているのでない限り、iss 値は RP の Client ID とすべきである (**SHOULD**)。aud 値には OP の Issuer Identifier URL を含めるべきである (**SHOULD**)。 - Request Object は JWE [JWE] を用いて暗号化することもできる (**MAY**)。また署名無しで暗号化のみを適用することもできる (**MAY**)。署名と暗号化を同時に利用する場合は, 署名後に暗号化すること (**MUST**)。これは Nested JWT となる ([JWT](https://datatracker.ietf.org/doc/html/rfc7519) 参照)。 - request および request_uri パラメータは, Request Object 中に含んではならない (**MUST NOT**)。 以下は base64url エンコードと署名を施す前段階の、Request Object 中の Claim の例 ``` { "iss": "s6BhdRkqt3", "aud": "https://server.example.com", "response_type": "code id_token", "client_id": "s6BhdRkqt3", "redirect_uri": "https://client.example.org/cb", "scope": "openid", "state": "af0ifjsldkj", "nonce": "n-0S6_WzA2Mj", "max_age": 86400, "claims": { "userinfo": { "given_name": {"essential": true}, "nickname": null, "email": {"essential": true}, "email_verified": {"essential": true}, "picture": null }, "id_token": { "gender": null, "birthdate": {"essential": true}, "acr": {"values": ["urn:mace:incommon:iap:silver"]} } } } ``` RS256 アルゴリズムで上記 Request Object に署名した結果の Request Object 値 ### 6.1.1. Request using the "request" Request Parameter Client は Authorization Request を Authorization Endpoint に送信する。 具体例は[本文](https://openid.net/specs/openid-connect-core-1_0.html#RequestParameter)を参考 ## 6.2. Passing a Request Object by Reference - request_uri Authorization Request パラメータにより、OpenID Connect リクエストを参照渡し可能になる。このパラメータは、Request Object そのものが値として渡されるのではなく、Request Object が指定された URL から取得されるという点以外は、request パラメータと同等である。 - サーバーは Request URI 参照先のコンテンツをキャッシュしても良い (**MAY**)。もし参照先のリソースが可変の場合は, URI フラグメントとしてコンテンツの SHA-256 ハッシュの Base64URL エンコード値を含めるべきである (**SHOULD**)。 もし URI フラグメント値が変わった場合は、古いフラグメント値を含む URI に紐づいたキャッシュ値はもはや有効でない。 - Client が [OpenID Connect Dynamic Client Registration 1.0](https://openid.net/specs/openid-connect-registration-1_0.html) [OpenID.Registration] Section 2.1 で定義される request_uris パラメータを用いて request_uri を事前登録することも可能である (**MAY**)。OP は, 事前登録済の request_uri 値以外の利用を許可しないということを、require_request_uri_registration ディスカバリパラメータで示すことができる。 - Request URI は全体で 512 ASCII 文字を超えてはならない (**MUST NOT**)。 - URL 参照先のリソースは、Request Object でなければならない (**MUST**)。Request Object が Authorization Server に検証可能な方法で署名されていない限り。request_uri のスキーマは https でなければならない (**MUST**)。request_uri 値は Authorization Server が到達可能でなければならず (**MUST**)、Client にも到達可能であるべきである (**SHOULD**)。 ### 6.2.1. URL Referencing the Request Object Client は Request Object をローカルもしくはリモートの Server にアクセス可能な URL に配置する。この URI が Request URI (request_uri) である。 Request Object が Claim リクエストを含む場合、その Request Object は Authorization Server 以外の何者にも知られてはならない (**MUST NOT**)。例えば, request_uri はそのライフタイムに応じて適切なエントロピーを持っていなければならない (**MUST**)。再び利用することの無いのが明らかな場合や適切なタイムアウト後には、そのコンテンツを削除することが推奨される (**RECOMMENDED**)。ただしなんらかのアクセスコントロールが実施されている場合はその限りではない。 以下は Request URI 値の例 ``` https://client.example.org/request.jwt# GkurKxf5T0Y-mnPFCHqWOMiZi4VS138cQO_V7PZHAdM ``` ### 6.2.2. Request using the "request_uri" Request Parameter 以下は request_uri パラメータを使った Authorization Request の例 ``` https://server.example.com/authorize? response_type=code%20id_token &client_id=s6BhdRkqt3 &request_uri=https%3A%2F%2Fclient.example.org%2Frequest.jwt %23GkurKxf5T0Y-mnPFCHqWOMiZi4VS138cQO_V7PZHAdM &state=af0ifjsldkj&nonce=n-0S6_WzA2Mj &scope=openid ``` ### 6.2.3. Authorization Server Fetches Request Object - Request を受けると, Authorization Server は参照先の Request Object を取得するため、request_uri に HTTP GET リクエストを送らなければならない (**MUST**)。ただし Request Object がキャッシュ済の場合を除く。Request Object を取得すると、Authorization Server は Authorization Request を取得するため Request Object をパースする。 - RP はリクエストごとに異なるパラメータを用いる場合は、リクエストごとにユニークな URI を用いるべきである (**SHOULD**)。もしくは Authorization Server が request_uri 参照先のコンテンツをキャッシュするのを防ぐこと。 以下は Request Object フェッチ例である。 ``` GET /request.jwt HTTP/1.1 Host: client.example.org ``` ### 6.2.4. "request_uri" Rationale request_uri を利用する理由として以下が挙げられる。 1. リクエストパラメータセットが長大になり、ブラウザの URI 長制限を超える. リクエストパラメータを参照渡しすることで, この問題を回避できる。 2. リクエスト全体を値として渡すより, request_uri を渡す方がリクエストレイテンシを抑えることができる。 3. RP が送ってくる Claim は、基本的に不変である。request_uri は、事前に不変のリクエストパラメータセットを用意しておき。 時には事前に署名や暗号化を施しておくことを可能にする。(request_uri 値は, 特定の不変なリクエストパラメータに対する "artifact" となる) 4. Registration 時に不変なリクエストパラメータを事前登録しておくことで。OP は Registration 時にリクエストパラメータを事前に検証済にした状態でキャッシュすることができる。これにより、OP はリクエストを受け取った際にコンテンツを取得しにいく必要がなくなる。 5. Registration 時に不変なリクエストパラメータを事前登録しておくことで。OP は顧客保護などの視点から送られてくるであろうリクエストの事前審査を行うことができる。事前審査を行う主体は、OP 自身なこともあれば、 サードパーティであることもあろう。 ## 6.3. Validating JWT-Based Requests request ないしは request_uri Authorization Request パラメータを利用する場合, Authentication Request の検証には 3.1.2.2, 3.2.2.2 および 3.3.2.2 に加えて更なるステップが必要となる。このステップとは, Request Object を含む JWT の検証と, Request Object 自体の検証である. ### 6.3.1. Encrypted Request Object もし Authorization Server が Discovery ドキュメント [OpenID.Discovery] 中の request_object_encryption_alg_values_supported と request_object_encryption_enc_values_supported で JWE 暗号化アルゴリズムを公表している場合、またはその他の手段により暗号かアルゴリズムを明らかにしている場合, Client はそれらのアルゴリズムを利用して JWT を暗号化する。 Authorization Server は JSON Web Encryption [JWE] の仕様に従って JWT を復号しなければならない (**MUST**)。 Request Object は署名されているかもしれず、署名無しの平文かもしれない (**MAY**)。前者の場合, 署名検証は Section 6.3.2 に従うこと (**MUST**)。 復号に失敗した場合、Authorization Server はエラーを返さねばならない (**MUST**)。 ### 6.3.2. Signed Request Object 署名検証を行うには、JWS ヘッダーの alg パラメータが Client Registration 時の request_object_signing_alg、もしくはその他の手段により事前登録された値と一致しなければならない (**MUST**)。署名は client_id とアルゴリズムに対して適切な鍵を用いて行わなければならない (**MUST**)。 署名検証に失敗した場合, Authorization Server はエラーを返さねばならない (**MUST**)。 ### 6.3.3. Request Parameter Assembly and Validation Authorization Server は、Request Object 値と OAuth 2.0 Authorization Request パラメータから (request と request_uri を除いて) Authorization Request パラメータを集約しなければならない (**MUST**)。Request Object と OAuth Authorization Request パラメータに同じパラメータが含まれる場合、 Request Object に含まれるパラメータを用いること。その後 Authorization Server は, 集約された Authorization Request パラメータを用いて、3.1.2.2, 3.2.2.2 および 3.3.2.2 に従って, 利用されているフローに応じて通常通りリクエストを検証する。