Pushed authorisation requests (PAR) in the OAuth 2.0 SDK

2019-10-26

The brand new Pushed Authorisation Requests (PAR) draft is now supported in v6.17 of the OAuth 2.0 / OpenID Connect SDK. PAR is a simple mean to up the security of authorisation requests, by making them integrity protected and confidential, and if the OAuth client has credentials - also authenticated.

The security of regular authZ requests

With regular OAuth 2.0 the client passes the request parameters encoded into the redirection URL that sends the user's browser (agent) for login and consent to the authorisation server.

GET /authz?response_type=code
 &client_id=123
 &state=ri4saex8
 &scope=upload_doc
 &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: c2id.com

Because the URL is submitted via the browser, the query parameters are exposed to the user and can potentially be tampered with. Applications therefore cannot rely on the authorisation request being authenticated, integrity protected or confidential. Do we have a solution for applications which require these security properties?

Securing authZ requests with JWT

The OAuth 2.0 extension for JWT-secured authorisation requests (JAR) allows the parameters to be authenticated and integrity protected by means of JWS. If JWE is applied to the digitally signed or HMAC-protected JWT, the request parameters become confidential. JAR has been a feature of OpenID Connect and is readily supported by the Connect2id server.

In order to secure authorisation requests with JAR the client needs to perform JOSE cryptography at the application layer. This is relatively easy with libraries such as Nimbus JOSE+JWT, but still, few developers take advantage of the extra security of JAR, unless the application is required to conform to a hardened OAuth 2.0 profile, such as FAPI.

PAR security works without application layer cryptography

The new PAR spec allows OAuth clients to submit their authorisation requests in a way that guarantees their integrity and confidentiality, without the need to deal with cryptography at the application layer. It also works for public clients without credentials.

PAR's solution is simple - a new endpoint at the authorisation server where clients can POST their authorisation request directly. If the client is confidential it will be required to authenticate as it does at the token endpoint.

Example HTTP POST of an authorisation request where the client authenticates with its client_secret:

POST /par HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

response_type=code
&client_id=123
&state=ri4saex8
&scope=upload_doc
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

For a successful POST the server will return a handle, in the form of a URI, typically a URN, which is valid for some limited time and may be single use.

HTTP/1.1 201 Created
Cache-Control: no-cache, no-store
Content-Type: application/json

{
  "request_uri": "urn:ietf:params:oauth:request_uri:tioteej8",
  "expires_in": 60
}

The OAuth client then makes the actual authorisation request, passing the URI handle in the request_uri parameter. No other query parameters are needed!

GET /authz?request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3Atioteej8 HTTP/1.1
Host: c2id.com

The rest of the flow continues as usual for the requested response type.

No URL limits on the authZ request

PAR also removes potential size limitations on the authorisation request, to accommodate browsers which doesn't support long URLs.

What is the maximum length of a URL in different browsers?

PAR meshes nicely with JAR

The PAR endpoint accepts JARs submitted via the request parameter. An application which requires non-repudiation of the authorisation request can submit a signed JWT containing the parameters. On success the server will return the URI handle for the request_uri on the next step.

POST /par HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

request=eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ewogICAgImlzcyI6IC
JzNkJoZFJrcXQzIiwKICAgICJhdWQiOiAiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5j
b20iLAogICAgInJlc3BvbnNlX3R5cGUiOiAiY29kZSBpZF90b2tlbiIsCiAgICAiY2
xpZW50X2lkIjogInM2QmhkUmtxdDMiLAogICAgInJlZGlyZWN0X3VyaSI6ICJodHRw
czovL2NsaWVudC5leGFtcGxlLm9yZy9jYiIsCiAgICAic2NvcGUiOiAib3BlbmlkIi
wKICAgICJzdGF0ZSI6ICJhZjBpZmpzbGRraiIsCiAgICAibm9uY2UiOiAibi0wUzZf
V3pBMk1qIiwKICAgICJtYXhfYWdlIjogODY0MDAKfQ.Nsxa_18VUElVaPjqW_ToI1y
rEJ67BgKb5xsuZRVqzGkfKrOIX7BCx0biSxYGmjK9KJPctH1OC0iQJwXu5YVY-vnW0
_PLJb1C2HG-ztVzcnKZC2gE4i0vgQcpkUOCpW3SEYXnyWnKzuKzqSb1wAZALo5f89B
_p6QA6j6JwBSRvdVsDPdulW8lKxGTbH82czCaQ50rLAg3EYLYaCb4ik4I1zGXE4fvi
m9FIMs8OCMmzwIB5S-ujFfzwFjoyuPEV4hJnoVUmXR_W9typPf846lGwA8h9G9oNTI
uX8Ft2jfpnZdFmLg3_wr3Wa5q3a-lfbgF3S9H_8nN3j1i7tLR_5Nz-g

Making a PAR request with the OAuth 2.0 SDK

The OAuth 2.0 / OpenID Connect SDK was updated with new classes to support PAR:

Example usage:

// The PAR endpoint, obtained from AS metadata
URI endpoint = URI.create("https://c2id.com/par");

// Construct an OAuth 2.0 authorisation request as usual
AuthorizationRequest authzRequest = new AuthorizationRequest.Builder(
    new ResponseType("code"), clientID)
    .redirectURI(URI.create("https://example.com/cb"))
    .scope(new Scope("upload_doc"))
    .state(new State())
    .build();

// The client authenticates the same way as it's supposed at the
// token endpoint
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("chele3faiYieNg4taoy8ingai3eili3b");
ClientAuthentication clientAuth = new ClientSecretBasic(clientID, clientSecret);

// Create the PAR request and POST it
HTTPRequest httpRequest = new PushedAuthorizationRequest(
    endpoint, clientAuth, authzRequest)
    .toHTTPRequest();
HTTPResponse httpResponse = httpRequest.send();

// Process the PAR response
PushedAuthorizationResponse response = PushedAuthorizationResponse.parse(httpResponse);

if (! response.indicatesSuccess()) {
    System.err.println("PAR request failed: " + response.getErrorObject().getHTTPStatusCode());
    System.err.println("Optional error code: " + response.getErrorObject().getCode());
    return;
}

PushedAuthorizationSuccessResponse successResponse = response.toSuccessResponse();
System.out.println("Request URI: " + successResponse.getRequestURI());
System.out.println("Request URI expires in: " + successResponse.getLifetime() + " seconds");

// Construct the authZ request for the browser, with request_uri as
// the sole parameter
URI redirectURI = new AuthorizationRequest.Builder(requestURI)
    .endpointURI(URI.create("https://c2id.com/authz"))
    .build()
    .toURI()

OAuth 2.0 SDK release notes

version 6.17 (2019-10-25)

  • Adds support for OAuth 2.0 Pushed Authorization Requests (draft-lodderstedt-oauth-par-00), see PushedAuthorizationRequest, PushedAuthorizationResponse, PushedAuthorizationSuccessResponse, PushedAuthorizationSuccessResponse and AuthorizationServerEndpointMetadata classes.
  • Deprecates RequestObjectPOST classes.
  • Updates ErrorObject to support URL-encoded parameters.
  • Adds new AuthenticationRequestDetector utility.

Updates token validation in Nimbus JOSE+JWT 8

2019-10-21

Version 8 of the Nimbus JOSE+JWT library updates the token validation framework.

When creating a JOSEProcessor or JWTProcessor they can now be configured to accept only tokens with a given typ (type) header parameter. Use of this header parameter is recommended to prevent accidental or malicious passing of a JWS or JWE of another type which happens to rely on identical claims.

For this reason the new JWT Profile for OAuth 2.0 Access Tokens sets this header to "at+jwt".

For example:

{
  "alg" : "RS256",
  "typ" : "at+jwt",
  "kid" : "AhXoh4fe"
}

The DefaultJWTClaimsVerifier was also updated, to enable configuration of exact audience and other claim matching, lists of JWT claim names that must be present and claims which presence is prohibited.

Here are some sample validation rules for an access token:

  • Expected audience (aud): https://demo.c2id.com/userinfo
  • Exact match claims: iss = https://demo.c2id.com
  • Names of claims that must be present: sub, cid, expscp
  • Names of prohibited claims: nonce

Example token claims:

{
  "iss" : "https://demo.c2id.com",
  "aud" : "https://demo.c2id.com/userinfo"
  "sub" : "alice",
  "cid" : "000123",
  "exp" : 1460345736,
  "scp" : ["openid","email","profile"],
  "clm" : ["!5v8H"],
  "uip" : {"groups":["admin","audit"]}
}

Use of the new features is explained in the updated article for validating JWT-encoded access tokens.


Release notes

version 8.0 (2019-10-15)

  • Adds new JOSEObjectTypeVerifier interface for verifying the "typ" (type) header parameter of processed JOSE objects. A configurable DefaultJOSEObjectTypeVerifier is provided.
  • Updates the ConfigurableJOSEProcessor interface with methods for setting a JWS and a JWE JOSEObjectTypeVerifier (API breaking change).
  • Updates the DefaultJOSEProcessor and DefaultJWTProcessor classes to support JWS and JWE "typ" (type) header parameter verification via the new JOSEObjectTypeVerifier interface.
  • Makes JOSEObject.hashCode() and JOSEObject.equals() case insensitive.
  • Removes exception caching in DefaultJOSEProcessor and DefaultJWTProcessor (iss #229).
  • JWK.parseFromPEMEncodedObjects should throw a JOSEException on a missing PEM-encoded public key required to construct the JWK (iss #331).

version 8.1 (2019-10-15)

  • Extends DefaultJWTClaimsVerifier with configurable checks for "iat", "exp", "nbf", "iss" and "aud".

version 8.2 (2019-10-17)

  • Redesigns DefaultJWTClaimsVerifier to support complex audience checks, arbitrary exact claim matching, presence and prohibited checks.

Connect2id server 7.17 updates access tokens and introspection

2019-10-12

Updated token introspection

Connect2id server 7.17 updates JWT-secured introspection responses to the latest OAuth version 08 draft. Signed introspections are useful for meeting assurance and legal requirements in applications dealing with verified person data, personal certificates and qualified electronic signatures. The changes are detailed in the release notes.

New type header explicitly identifies JWTs that are access tokens

This release also takes a first step in implementing the new OAuth draft for interoperable JWT-encoded access tokens. The spec defines a minimal set of standard JWT claims for OAuth 2.0 servers that issue self-contained access tokens. All JWT-encoded access tokens issued by the Connect2id server will now include the "at+jwt" type designation in the JWT header.

Example JWT header for an access token:

{
  "alg" : "RS256",
  "typ" : "at+jwt",
  "kid" : "AhXoh4fe"
}

The prompt parameter is supported in plain OAuth 2.0 authorisation requests

The optional prompt parameter in OpenID authentication requests enables relying parties to check if an end-user is already logged in and has previously provided consent. It can also be used to force re-authentication, re-consent or a change in the active user account at the IdP:

  • prompt=none -- To check if the end-user is logged in and has previously given consent to the specified scope values. This is typically done from a hidden iframe. On success the server will issue an ID and access token, without requiring any interaction from the user. If the prompt=none request cannot be fulfilled the server will return a login_required, consent_required or a general interaction_required error, indicating that the relying party should repeat the request, but this time allow for user interaction.

  • prompt=login -- To force the end-user to be re-authenticated.

  • prompt=consent -- To force the end-user to re-consent the specified scope values.

  • prompt=select_account -- To hint the IdP to present the end-user with an account selection menu (in case the user has multiple accounts with the IdP).

All prompt values save for none can be combined, e.g. prompt=login consent.

The prompt parameter can also be useful for plain OAuth 2.0 authorisation requests, especially the consent and select_account values. For that reason the Connect2id server will now support it for all authorisation requests.

Note that the id_token_hint parameter cannot be used in conjunction with prompt for a plain OAuth 2.0 authorisation request.

Maintenance updates

This release also updates over a dozen underlying modules and libraries to their latest stable versions.

Download

To download a ZIP package of Connect2id server 7.17:

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

SHA-256: 06417bab6594d37f34f5a4445bfe6bfa2bd14f077a71afbf38033849e561ef95

As WAR package only:

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

SHA-256: adb747202305c33758a268f7118685f2706d44dbdab132aa66cfbff1601b3ea7

Questions?

Contact Connect2id support.


Release notes

7.17 (2019-10-12)

General

  • Issues JWT-encoded access tokens will now include the JOSE header parameter type ("typ") set to "at+jwt". Applies to signed as well as nested (signed and encrypted) access tokens. This explicit marking of access tokens is intended to prevent potential confusion with other JWT types, such as OpenID tokens. See JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens (draft-ietf-oauth-access-token-jwt-02), section 2.1.

  • Updates support for JWT Response for OAuth Token Introspection to draft-ietf-oauth-jwt-introspection-response-08.

  • The OpenID "prompt" parameter is now also supported with plain OAuth 2.0 authorisation requests.

Web API

  • /token/introspect

    • Introspection responses now include the JWT ID ("jti") claim for identifier-based access token, set to the first 8 bytes of the SHA-256 hash of the token identifier value.

    • Applies audience restriction to introspected access tokens. If the access token is specified with an audience which doesn't match the caller (client_id), typically that of a resource server, it will be marked as invalid (active=false).

    • Minimises the reported audience of introspected access tokens. If the access token is specified with multiple audiences, of which one matches the caller (client_id), only the caller will be included in the "aud" parameter; any other values (client_id's of resource servers) will be omitted in the response.

    • JWT-secured responses now return JWTs with a type ("typ" header) set to "token-introspection+jwt".

    • JWT-secured responses now always include the issued-at ("iat") claim, set to the time when the response was issued, which will override any token "iat" claim.

    • JWT-secured responses now always include the JWT IT ("jti") claim, see above for details.

  • /authz-sessions/rest/v3/

    • The OpenID "prompt" parameter is now also supported with plain OAuth 2.0 authorisation requests. The prompt values "none", "login", "consent" and "select_account" will be handled identically to OpenID authentication requests. Note that the "id_token_hint" parameter cannot be used in conjunction with "prompt" for a plain OAuth 2.0 authorisation request.

Dependency changes

  • Upgrades to com.nimbusds:c2id-server-sdk:4.6

  • Upgrades to com.nimbusds:oauth2-oidc-sdk:6.16.2

  • Upgrades to com.nimbusds:oauth2-authz-store:13.3.1

  • Updates to com.nimbusds:oidc-session-store:12.0.4

  • Updates to com.nimbusds:nimbus-jose-jwt:7.9

  • Updates to com.nimbusds:common:2.35

  • Updates Infinispan to 9.4.16.Final

  • Updates to com.nimbusds:infinispan-cachestore-redis:9.2.8

  • Updates to com.nimbusds:infinispan-cachestore-ldap:3.1.2

  • Updates to com.unboundid:unboundid-ldapsdk:4.0.12

  • Updates to com.nimbusds:infinispan-cachestore-sql:3.1.5

  • Updates to com.zaxxer:HikariCP:3.4.1

  • Updates to org.jooq:jooq:3.11.12

  • Updates to org.mariadb.jdbc:mariadb-java-client:2.4.4

  • Updates to com.h2database:h2:1.4.199

  • Updates to commons-codec:commons-codec:1.13

  • Updates to org.apache.commons:commons-collections4:4.4

  • Updates to commons-io:commons-io:2.6

  • Updates Dropwizard Metrics to 4.0.6

  • Updates Log4j to 2.12.1

Nimbus JOSE+JWT 7.9 fixes an unchecked exception vulnerability

2019-10-07

Nimbus JOSE+JWT 7.9 fixes vulnerabilities in the code which may result in the library throwing an unchecked Java exception on certain malformed JWT or JOSE input.

Uncaught exceptions (CWE-248) could result in a crash (potential information disclosure) or a potential authentication bypass, depending on how the library is integrated into an application.

Users are advised to upgrade.

The CVSSv3 score is 6.0 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L/E:F/RL:O/RC:C.

The vulnerability was allocated CVE-2019-17195.

We thank the Oracle Cloud Infrastructure (OCI) Security Research Team and their member, Devin Cook, for the discovery and reporting.


Release notes

version 7.9 (2019-10-05)

  • Adds new static null-safe Base64.from(String) and Base64URL.from(String) methods.
  • Makes JWKSet and KeyUse serializable (iss #330).
  • Fixes NPE when parsing JOSE header with missing or null "alg" (iss #332). Allocated CVE-2019-17195.
  • Fixes IllegalArgumentException when parsing JOSE header with null "typ" (iss #333). Allocated CVE-2019-17195.
  • Fixes NPE when parsing JOSE header with null "crit" (iss #334). Allocated CVE-2019-17195.
  • Fixes NPE when parsing JOSE header with null "jwk" (iss #335). Allocated CVE-2019-17195.
  • Fixes NPE when parsing JOSE header with null BASE64 or BASE65URL encoded parameters (iss #336). Allocated CVE-2019-17195.
  • Fixes IllegalArgumentException when parsing JWE header with null "zip" (iss #337). Allocated CVE-2019-17195.
  • Catch unexpected exceptions in JSONObjectUtils.parse and rethrow as ParseException. Allocated CVE-2019-17195.

Connect2id server 7.16 with token introspection update

2019-09-09

This is a mini update to the Connect2id server which updates the token introspection endpoint to include the optional expiration ("exp") parameter in the response for identifier-based access tokens.

This update also fixes two issues. See the release notes below for more information.

Download

To download a ZIP package of Connect2id server 7.16:

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

SHA-256: b85b9fea360c38b2287c5f44559c9cc3092aa6bad6eec013504f824107659486

As WAR package only:

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

SHA-256: d3db91263ad1773fa475f1003ed3f53144629fb0983c3e0de1fea8396930a2d5

Questions?

Contact Connect2id support.


Release notes

7.16 (2019-09-09)

Web API

  • /token/introspect -- Includes the optional expiration (exp) parameter in introspection responses for identifier-based access tokens. See OAuth 2.0 Token Introspection (RFC 7662), section 2.2.

Resolved issues

  • Fixes a bug which resulted in a HTTP 500 error when reading an OAuth 2.0 client registration with an empty JWK set ("jwks") from DynamoDB (issue server/480).

  • Fixes a bug which affected setting of the "exp" and potentially other JWT claims in calls to the AccessTokenIssueEventListener SPI (issue authz-store/164).

Dependency changes

  • Updates to com.nimbusds:oauth2-authz-store:12.4