Request objects in OAuth 2.0 and OpenID Connect

2019-05-15

The request object originally appeared as an OpenID Connect feature to secure parameters in the authentication request from tainting or inspection when the browser of the end-user is sent to the OpenID provider server. OAuth 2.0 recently caught up with its own specification for general use of request objects in authorisation requests. This is a guide when and how to employ them.

Why secure auth requests?

When the end-user browser is sent to the OpenID provider with a regular authentication request its parameters simply get URL-encoded in the query string.

https://c2id.com/login?response_type=code
 &client_id=123
 &scope=openid
 &redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb
 &state=obiange2

This means the end-user as well as any malicious XSS injected into the relying party (RP) website can potentially view and modify the request parameters. But for the protocol itself this doesn't represent a security issue. Why?

  • The request parameters are not secret and in the case of scope, claims and state shouldn't convey sensitive information in plain text.

  • If a critical request parameter gets tampered with, the validation and processing that follow, by the OpenID provider or the RP, will detect that and produce an error.

For instance, the OpenID provider checks that the redirect_uri matches a redirection URI registered for the particular client_id, and later, at the token endpoint the client (if confidential) gets authenticated. The state parameter is validated by the RP when it gets passed back with the authorisation response.

Still, there are applications which need OpenID authentication requests with additional security:

  • Authenticity, integrity and non-repudiation of the requested scope and claims, typically for legal purposes.

  • Approval of the request by a third party for compliance with a privacy / personal data collection policy.

  • Keeping the requested scope, claims or a custom parameter confidential from the end-user.

  • In deployments with multiple OpenID providers and dynamic client registration to guard against IdP mix-up attacks.

Moving sensitive request parameters into a JWT

The natural candidate solution for securing the request parameters was the JSON Web Token (JWT). The JWT that carries the parameters is called request object in OpenID Connect.

The request object may include only those parameters deemed sensitive by the application, for example scope and claims, while keeping the rest unprotected, as regular URL-encoded query parameters. Security profiles, such as FAPI for OpenBanking and other financial-grade applications, may require all parameters to be present in the JWT.

Example JWT claims set for an OpenID authentication request:

{
  "response_type" : "code",
  "client_id"     : "123",
  "scope"         : "openid email profile",
  "redirect_uri"  : "https://client.example.com/cb",
  "state"         : "obiange2"
}

By signing the JWT the parameters receive integrity protection and the OpenID provider can assume they originate from the relying party (RP). By applying encryption to the JWT the parameters are made confidential between the RP and OpenID provider.

Passing the request object: by value vs URL

The request object itself can be passed by value in a request parameter, or by reference, in a request_uri parameter.

Passing the request object by URL instead of by value frees it from potential URL size restrictions in browsers.

Example OpenID authentication request where the request object is passed by value:

https://c2id.com/login?response_type=code
 &client_id=123
 &scope=openid
 &request=eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KICJpc3MiOiAiczZCaGRSa...

And by URL:

https://c2id.com/login?response_type=code
 &client_id=123
 &scope=openid
 &request_uri=https%3A%2F%2Fclient.example.com%2Frequest.jwt

Note the presence of the response_type, client_id and scope as query parameters. They are there because of a requirement for the URL query parameters to still parse into a valid OAuth 2.0 authorisation request, with scope=openid to indicate an OpenID authentication request. The scope in the request object supersedes, always, and can include additional scope values.

Support for request objects in OpenID authentication requests has been present in the Connect2id server since version 6.0.

OAuth 2.0 also adopts request objects

Request objects can also be useful in general OAuth 2.0 and the OAuth working group is finalising a specification for that, called JWT Secured Authorization Request (JAR).

The JAR spec relaxes the requirement for the URL query parameters to parse into a valid OAuth 2.0 authorisation request, so clients can send authorisation requests that consist of only the request or request_uri parameter at the top level, with all other parameters going into the JWT:

https://c2id.com/login?request_uri=https%3A%2F%2Fclient.example.com%2Frequest.jwt

General OAuth 2.0 support for request objects was introduced in Connect2id server version 7.12.

How to find out if an AS / OP supports request objects

How can a developer or dynamic client find out if a particular Authorisation server (AS) or OpenID provider (OP) supports requests objects? By checking the following parameters in the published AS / OP metadata:

  • request_parameter_supported -- If true indicates support for passing request objects by value.
  • request_uri_parameter_supported -- If true indicates supports for passing request objects by URL.
  • require_request_uri_registration -- If passing request objects by URL is supported, whether the URLs need to mentioned in the client registration.
  • request_object_signing_alg_values_supported -- If signed request objects are supported, list of the supported JWS algorithms.
  • request_object_encryption_alg_values_supported -- If encrypted request objects are supported, list of the supported JWE algorithms.
  • request_object_encryption_enc_values_supported -- If encrypted request objects are supported, list of the supported JWE methods.

Example server metadata showing support for HMAC-SHA256-protected (JWS algorithm HS256) as well as RSA signed (JWS algorithm RS256) request objects, which the client can pass by value or URI:

{
  "request_parameter_supported"                 : true,
  "request_uri_parameter_supported"             : true,
  "request_object_signing_alg_values_supported" : [ "HS256", "RS256" ]
}

Registering a client for request objects

The JWS and / or JWE algorithms for securing the request object JWTs need to be set in the client's metadata when it's registered with the AS / OP.

Algorithm choice

Choose cryptographic algorithm that's supported by the AS / OP and also minimally appropriate for the required security.

Integrity protection

If nothing else but protection against tampering of the authorisation parameters is required, choose an HMAC based JWS algorithm, such as HS256, HS384 or HS512. The client must then secure the request object JWT with an HMAC computed from the client_secret as key.

Example minimal registration for the code grant with HS256 secured request objects:

POST /c2id/clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"              : [ "https://client.example.org/callback" ],
  "request_object_signing_alg" : "HS256"
}

Authenticity, integrity and non-repudiation

If the requirement is to make the request object digitally signed, choose a JWS algorithm from the RSxxx / PSxxx family for RSA-based public key cryptography or from the ESxxx family for EC-based cryptography.

To sign the request objects the client needs to generate a public / private key pair. The client must store the private key securely and will use it to sign the request object JWTs. The AS / OP server needs to have access to the matching public key, in order to check the JWT signatures.

The client has a choice of two methods to make its public key(s) available to the AS / OP:

  • By putting its public keys in JSON Web Key (JWK) set format in the jwks client metadata parameter.

  • By publishing its keys, also in JWK set format, at a URL reachable by the AS / OP, and registering that URL in the jwks_uri client metadata parameter.

Example minimal registration for the code grant with RS256 secured request objects; the AS / OP can get the public client JWK set to validate the RS256 signatures from the given client URL:

POST /c2id/clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"              : [ "https://client.example.org/callback" ],
  "jwks_uri"                   : "https://client.example.org/jwks.json",
  "request_object_signing_alg" : "RS256"
}

Confidentiality

To make request parameters confidential, the client needs to encrypt the request object, and register an appropriate JWE algorithm and method for that.

Note that encryption can be applied after JWS signing, to create a nested JWT that ensures the properties of authenticity, integrity and non-repudiation as well as the confidentiality. If the combination or integrity and confidentiality is required, just register the client for JWE encryption, as all standard JWE encryption methods have the cryptographic property of authenticated encryption.

The actual encryption is of two types:

  • Symmetric -- Using the client_secret to derive an AES key that is shared between the client and the AS / OP.

  • Public key -- Encryption to a public RSA or EC key which the AS / OP has made available in its own published JWK set. The URL of the server JWK set can be found out by checking the AS / OP metadata.

Example minimal registration for the code grant with nested (signed and RSA public-key encrypted) request objects:

POST /c2id/clients HTTP/1.1
Host: demo.c2id.com
Content-Type: application/json
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6

{
  "redirect_uris"                 : [ "https://client.example.org/callback" ],
  "jwks_uri"                      : "https://client.example.org/jwks.json",
  "request_object_signing_alg"    : "RS256",
  "request_object_encryption_alg" : "RSA-OAEP-256",
  "request_object_encryption_enc" : "A128GCM"
}

Further reading

Connect2id server 7.11.1

2019-04-27

This is a maintenance release of the Connect2id server (for Java 11).

Deployments with a DynamoDB backend are advised to upgrade, especially if consent during the authorisation session is handled automatically (implicitly), without involving the end-user.

Deployments which process plain OAuth 2.0 authorisation requests where clients don't specify a scope explicitly should also upgrade.

Check out the release notes below for more information.

Download

To download a ZIP package of Connect2id server 7.11.1:

https://connect2id.com/assets/products/server/download/7.11.1/Connect2id-server.zip

SHA-256: c8a3b4c80d73609cf8617fbccccfefcc79d3120c836724f7cc87c30de191a8bb

As WAR package only:

https://connect2id.com/assets/products/server/download/7.11.1/c2id.war

SHA-256: d9be57eebb9e934b4c4cbb8a36e9d618dcdbde8d2ad0681247cc0c2f2e407e5f

Questions?

Contact Connect2id support.


Release notes

7.11.1 (2019-04-27)

Configuration

  • /WEB-INF/infinispan-*-dynamodb.xml

    • Upgrades the DynamoDB connector to 3.4.1 and the schema to v1.5 to add support for enabling strongly consistent DynamoDB reads.
  • /WEB-INF/infinispan-stateless-dynamodb.xml

    • Enables strongly consistent DynamoDB reads for "op.consentSessionMap" to prevent possible false 404 errors during authorisation sessions (/authz-sessions/rest/v3/) when consent is handled automatically (without any user interaction) and too quickly for eventual consistency.

Resolved issues

  • Fixes an NPE during the authorisation session when an undefined scope is submitted for an OAuth 2.0 authorisation request (issue server/445).

  • Fixes a non-critical NPE for a null UserInfo returned from the claims source for claims to be fed into the ID token (issue server/444).

  • Switches to strongly consistent DynamoDB reads for "op.consentSessionMap" to prevent possible false 404 errors during authorisation sessions (/authz-sessions/rest/v3/) when consent is handled automatically (without any user interaction) and too quickly for eventual consistency (issue server/442).

Dependency changes

  • Upgrades to com.nimbusds:infinispan-cachestore-dynamodb:3.4.1

Connect2id server 7.10.1

2019-04-27

This maintenance release of the Connect2id server backports selected fixes from Connect2id server 7.11 and 7.11.1 (for Java 11+) to 7.10 (for Java 8).

Check out the release notes below for more information.

Download

To download a ZIP package of Connect2id server 7.10.1:

https://connect2id.com/assets/products/server/download/7.10.1/Connect2id-server.zip

SHA-256: efec16fd1137a2ac5143488790d0cc15060be25f628b0b23db02d1b607aef0a9

As WAR package only:

https://connect2id.com/assets/products/server/download/7.10.1/c2id.war

SHA-256: 42c487dc87f0abb378d8dff07fcac3205c851fb63fbe847b976128c8956b61a0

Questions?

Contact Connect2id support.


Release notes

7.10.1 (2019-04-27)

Configuration

  • /WEB-INF/infinispan-*-dynamodb.xml

    • Upgrades the DynamoDB connector to 3.4.1 and the schema to v1.5 to add support for enabling strongly consistent DynamoDB reads.
  • /WEB-INF/infinispan-stateless-dynamodb.xml

    • Enables strongly consistent DynamoDB reads for "op.consentSessionMap" to prevent possible false 404 errors during authorisation sessions (/authz-sessions/rest/v3/) when consent is handled automatically (without any user interaction) and too quickly for eventual consistency.

Resolved issues

  • Fixes a bug which prevented the UserInfo from returning the subject in pairwise encrypted form when the OpenID relying party is registered for subject_type=pairwise (issue server/441).

  • Fixes a non-critical NPE for a null UserInfo returned from the claims source for claims to be fed into the ID token (issue server/444).

  • Switches to strongly consistent DynamoDB reads for "op.consentSessionMap" to prevent possible false 404 errors during authorisation sessions (/authz-sessions/rest/v3/) when consent is handled automatically (without any user interaction) and too quickly for eventual consistency (issue server/442).

Dependency changes

  • Upgrades to com.nimbusds:infinispan-cachestore-dynamodb:3.4.1