The authn/OIDCRelyingParty login flow supports the use of a separate OpenID Provider (OP) to authenticate the subject, with the IdP acting as an OIDC Relying Party (RP) proxy (OAuth 2.0 Client). This is similar in concept to the SAML Proxy, but for OpenID Connect.

The Authorization Code Flow is the only supported OIDC authentication flow. Both Implicit and Hybrid flows, by default, use the fragment response mode which would require additional User-Agent processing (e.g. JavaScript in the browser) to extract the parameters from the fragment and post them back to the IdP’s callback endpoint.

Dynamic client registration is not supported at this stage.

Plugin Installation


Plugin ID


Depends On

Authentication Flow ID

Latest Version

Bug Reporting


Plugin ID


Depends On

Authentication Flow ID

Latest Version

Bug Reporting

OpenID Connect Relying Party Proxy








Enabling the Module

For a detailed guide on configuring modules, see the ModuleConfiguration topic. Once the plugin has been installed, its module should be enabled automatically for you:

Check Module Is Enabled
/%{idp.home}/bin$ ./module.sh -l ... Module: idp.authn.oidc.RP [ENABLED]

However, if you need to enable it you can using the module command:

Enable the module
/%{idp.home}/bin$ ./module.sh -e idp.authn.oidc.RP

Either manual or automatic module enablement will copy across the following configuration files from the jar:

Configuration files
jar:oidc-providermetadata-resolvers.xml -> conf/authn/oidc-rp-providermetadata-resolvers.xml jar:oidc-rp-credentials.xml -> conf/authn/oidc-credentials.xml jar:oidc-rp-client-secret-credential.xml -> conf/authn/oidc-rp-client-secret-credential.xml jar:oidc-claim-rules.xml -> conf/attributes/oidc-claim-rules.xml jar:oidc-rp-config.xml -> conf/authn/oidc-rp-config.xml jar:oidc-rp.properties -> conf/authn/oidc-rp.properties

Configuration Overview

The following requirements exist for this flow to operate:

  1. The Issuer Identifier of the upstream OpenID Provider must be known somehow.

  2. The OP must make available its configuration document at the well-known location - although this behaviour can be customized.

The following steps must be followed to enable the RP to communicate with an upstream OpenID Provider:

  1. Create a client with your OpenID Provider.

    1. Note your client_id and client_secret.

    2. If you want to enable asymmetric (public key) Request Object signature signing and or ID Token or UserInfo token encryption, register any public digital signature and encryption keys with the OP.

  2. Add your client_id to the property idp.authn.oidc.rp.client.clientId.

  3. Add your client_secret to the property idp.authn.oidc.rp.client.clientSecret.

  4. Add conf/authn/oidc-rp-client-secret-credential.xml to the IdP’s credentials.xml file.

  5. Add conf/oidc-credentials.xml to the IdP’s credentials.xml file.

  6. Establish the Proxy Issuer.

  7. Configure a Redirect URL.

  8. Configure the attribute filter to expose claims to the rest of the system.

  9. Change the login flow to OIDCRelyingParty in authn.properties.

    1. Note, if you want to use the RP inside an MFA flow, you will need to consider which c14n flow to run to produce a suitable principalName, see here.

  10. Add the OIDC.SSO profile to relying-party.xml

For finer control, see the Advanced Configuration topics. Make sure to adjust your Auditing requirements as appropriate.

Basic Configuration

This section describes the basic configuration options needed to set up a functioning OpenID Relying Party. Options in this section are limited to the following configuration file:

Configuration File


Configuration File



The properties file where most standard configuration options are found.


A credential used to hold the client_secret set in the properties file


Assymetric key credentails used by both RP and OP plugins

To enable the most basic functionality of the RP, the client_secret (set in the properties file) must get transformed into an internal Credential suitable for signing, authentication to the token endpoint, and possibly encryption. To do so, simply import the oidc-rp-client-secret-credentials.xml into conf/credentials.xml:

<import resource="authn/oidc-rp-client-secret-credential.xml" />

You also need to include the configuration for asymmetric keys, namely the oidc-credentials.xml configuration file. This is shared between the OP and the RP and is described in more detail in the Advanced Topics section.

<import resource="oidc-credentials.xml" />

Establish Proxy Issuer (OpenID Provider)

In the simplest case, the RP will be used with a single upstream OpenID Provider (OP) and you must set the issuer identifier (OP identifier) in the properties file:


idp.authn.oidc.rp.provider.proxyIssuer = <issuer identifier of upstream OP>

Setting up the RP as an OAuth 2.0 Client

Once you’ve registered with the OP, obtain the client identifier and client secret and set the following properties:


idp.authn.oidc.rp.client.clientId = <client_id received from the OP> idp.authn.oidc.rp.client.clientSecret = <client_secret received from the OP>

Note, it is possible the OP uses ‘certificate-based' authentication and will not give you a client secret by default. The RP does not support that authentication method yet, so you will need to generate a client secret to use.

Authentication Request

Redirection URI

You will need to specify a redirection URI as per the OAuth2.0 specification (RFC6749). This is the endpoint the OP will redirect the authentication response to via the end-users user-agent (browser). The redirection URI must exactly match the one that is registered with the OP. If only a single OP is configured (i.e. no discovery), the following property can be explicitly set:



Where <hostname> and <port> match that of your running IdP — the port can be omitted if your IdP uses the standard HTTP/HTTPS port e.g. 80 and 443 respectively. The endpoint itself needs only to be accessible by the end-user’s user-agent (browser).

Dynamic Redirect URI

Alternatively, you can let the RP plugin determine the redirect URI from the Host header sent from the client that issues the original (e.g. SAML) authentication request. To do so, comment out the idp.authn.oidc.rp.client.redirectURI property and then, in order to prevent HTTP Host header injection attacks (and possibly leaking your authorization code to a malicious actor), declare one or more comma-separated allowed 'origins' [RFC6454] in the property idp.authn.oidc.rp.client.redirecturl.allowedOrigins. Each origin is a combination of scheme, host, and port. For schemes where the default port is used e.g. HTTPS on port 443, the port can be omitted. For example, assuming a production IdP has a hostname of prod.example.com using the HTTPS scheme over the default port, and a matching development IdP has a hostname of dev.example.com running on a custom port 8443, the following origins would be sufficient:


idp.authn.oidc.rp.client.redirecturl.allowedOrigins = https://prod.example.com, https://dev.example.com:8443

This can be useful if you want to keep a single generic configuration between development, staging, and production servers, etc. Also, if a single IdP instance is serving requests from more than one virtual-host, each authentication request will need to be redirected back to the originating Hostname in order to successfully complete the request.


In OIDC, scopes request that certain sets of information are made available as claim values (see Scope Claims) and returned in the UserInfo response (although it is technically possible it could return them in the id_token if other response_types were allowed).

The openid scope is always applied to authentication requests, but further scopes can be added. In the simplest case where there is only one upstream OP, a comma-separated list of scopes can be added to the property idp.authn.oidc.rp.client.scopes, for example:


idp.authn.oidc.rp.client.scopes = profile,email

When dealing with more than one upstream OP, a RelyingParty scopes override would be required for each, for example:


<bean id="ExampleOP" parent="RelyingPartyByName" c:relyingPartyIds="https://upstream.op.example.com/"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:scopes="profile,email"/> </list> </property> </bean>

Forced Authentication

The RP’s default behaviour is to respect the forceAuthn requirement of the downstream SAML SP. However, this can be overridden per OP by setting the forceAuthn property of a suitable RelyingParty override.

In the OIDC world, requiring forced authentication amounts to setting the prompt authentication request parameter to login and the max_age parameter to 0 seconds. This forces the OP to prompt the End-User for reauthentication and return an error if unsuccessful. It also includes the auth_time claim in the ID Token response which the RP uses to determine if the authentication happened after the authentication request was issued.

Authentication Context Class Reference

The Authentication Context Class Reference (acr) is similar to the SAML <AuthnContextClassRef> construct and defines the level of authentication performed. The RP can request ACRs by adding them as an essential acr claim inside the Requested Claims object, or as a voluntary claim inside the acr_values request parameter.

By default, the RP tries to add ACR values as essential claims inside the Requested Claims object — whether that be inside the Request Object or as standard URL request parameters. If the OP does not support the claims parameter, the RP reverts to using the acr_values request parameter. Note, in doing so, this changes the requirement semantics from essential to voluntary.

To add ACR values, the RP looks at the defaultAuthenticationMethods RelyingParty configuration option. The global policy (which you could override per OP) either passes through or maps the original SP’s requirements into ACR values. If passed through, it is likely the upstream OP will not understand their semantics, hence a mapping list (bean) can be defined that translates between SAML-requested principals and OIDC ACR values. This bean should already be defined in the conf/authn/authn-comparison.xml file so you can uncomment it, for example:

<util:map id="shibboleth.oidc.PrincipalProxyRequestMappings"> <entry> <key> <bean parent="shibboleth.SAML2AuthnContextClassRef" c:classRef="http://example.org/ac/classes/mfa" /> </key> <list> <bean class="net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal" c:classRef="https://proxy.example.org/context2" /> </list> </entry> </util:map>

Of course, if you specified a RelyingParty override for defaultAuthenticationMethods, you could provide any logic you want, for example, always requesting a particular ACR value.

At this time, the RP does not take into consideration the acr_values_supported of the upstream OP. Hence, you could blindly request an ACR that is not supported. This could change in future versions.

Similarly, the response from the OP may contain the acrclaim which might need mapping back into a suitable value for the requesting SP. A mapping list (bean) can be defined that translates between OIDC ACR string values and SAML-requested principals. This bean should already be defined in the conf/authn/authn-comparison.xml file so you can uncomment it, for example:

<util:map id="shibboleth.PrincipalProxyResponseMappings"> <entry key="https://proxy.example.org/context2"> <list> <bean parent="shibboleth.SAML2AuthnContextClassRef" c:classRef="http://example.org/ac/classes/mfa" /> </list> </entry> </util:map>

Authentication Methods References

The Authentication Methods References (amr) describe the family of authentication methods used by the OpenID Provider to authenticate a subject. For example, multi-factor or username and password etc. You can not request which amr is used in the authentication request, but the OP can optionally return it in the id_token. If it does, it can be extracted and mapped into a Principal object, see Subject Population.

Authentication Response

Obtaining an ID Token

Upon successful authentication, the OP returns an OAuth 2.0 Authorization Response containing, importantly, an authorization code in the query parameters (unless a different response_mode was configured). The RP will immediately exchange (back-channel) the authorization code for an Access Token and ID Token. The HTTP Client, its security parameters, and the encoder and decoder can all be customised, but these are very much advanced configuration options, which shouldn’t need changing.

UserInfo Endpoint Request

The UserInfo Endpoint returns additional claims about an authenticated End-User. An HTTP GET or HTTP POST request is sent (using the access_token received in the authentication response) to the UserInfo endpoint, and either a plain JSON object is returned, or a signed and or encrypted JWT. Either contain the UserInfo claims about the authenticated end-user — including any specifically requested in the authentication request. The response is validated and the claims are merged with those in the id_token using a replaceable ‘merging strategy’ (see End-User Claims Merging). The merged claims are exposed to the rest of the flow for later translation, filtering, and extraction.

Requests to the UserInfo endpoints are enabled by default. To disable globally, set the following property:


idp.authn.oidc.rp.client.userinfo.enabled = false

Or disabled per OP by providing a RelyingParty override with the property p:retrieveUserInfoEndpointClaims="true|false" set.


Attribute Extraction and Filtering

Currently, IdPAttribute extraction is possible using the AttributeRegistryConfiguration. The plugin installation process will copy a file named oidc-claim-rules.xml to the conf/attributes/ directory. This file contains a default set of OIDC claims to IdPAttribute transcoding rules. To enable it, you must add an import to conf/attributes/default-rules.xml:

If you have already installed the OIDC OP plugin, it is possible you have already enabled the OIDC claim mapping rules below, and you can skip this step.

<import resource="oidc-claim-rules.xml" />

Once the results have been produced, the AttributeFilterConfiguration is applied. This is a reversal of the usual filtering process of outbound data and operates with the proxying IdP itself as the "requester" and the proxied OP as the "issuer". An example policy to allow through displayName, mail, and sn is shown below.


<AttributeFilterPolicy id="alwaysReleaseFromProxy"> <PolicyRequirementRule xsi:type="Issuer" value="https://proxy.example.org" /> <AttributeRule attributeID="displayName" permitAny="true" /> <AttributeRule attributeID="mail" permitAny="true" /> <AttributeRule attributeID="sn" permitAny="true" /> </AttributeFilterPolicy>

Note, attribute resolution and filtering rules are shared with the IdP. Take care not to overlap these rules in confusing ways.

Subject Population

As with any other login flow, the product will be an AuthenticationResult containing a Java Subject with some number of Principal objects. The content of the Subject produced automatically comprises:

  • If the incoming id_token contains the sub claim (it should always), then an OIDCSubjectIdentifierPrincipal is included that wraps the subject claim as is.

  • A ProxyAuthenticationPrincipal is included that will contain the issuer of the id_token as the proxied authorities i.e. the OpenID Provider. Note, this is far less complete than the SAML variant, as it does not contain a ‘chain' of proxied authorities i.e. if the request was proxied further.

  • Any IdPAttribute objects resulting from the initial extraction and filtering stage are wrapped in IdPAttributePrincipals.

What is not automatic is the mapping of OIDC Authentication Context Class References (acr) and Authentication Method References (amr) from the id_token into Principals that can, for example, be matched against requested principals sent by the downstream SAML SP. Internally, both are passed through translation functions that map the Method References and Context Class References into Principal objects. However, by default, the mapping list (bean) does not exist, and the default behaviour does nothing. To provide mappings you need to add the following list bean to conf/authn/authn-comparison.xml. The key is the OIDC AMR or ACR string value, the value is the Principal to populate for the Subject.


<!-- Mappings from Authentication Methods References and Authentication Context Class References in the claims of the id_token to Java principals about the subject. --> <util:map id="shibboleth.oidc.PrincipalProxyResponseMappings"> <entry key="pwd"> <list> <bean parent="shibboleth.SAML2AuthnContextClassRef" c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" /> </list> </entry> </util:map>

Storing Off Context Information In Private Credentials

The RP is capable of storing custom Principals into the Subject’s private credentials set after authentication using a strategy bean named shibboleth.authn.oidc.rp.ContextToPrivateCredentialsMappingStrategy. This allows, for example, saving off the OIDC access_token and refresh_token from the Token Endpoint for later use by the rest of the system.

A strategy that can map an access_token and refresh_tokeninto an OAuth2AccessTokenPrincipal and OAuth2RefreshTokenPrincipal is included by the RP but is not enabled by default. If you want that functionality, you can include the following bean in the oidc-rp-config.xml file:

<bean id="shibboleth.authn.oidc.rp.ContextToPrivateCredentialsMappingStrategy" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AccessTokenToPrivateCredentialsMappingStrategy"/>

Subject Canonicalization

The AuthenticationResult needs to be processed into a normalized principal name to expose to the rest of the system — or subsequent authentication flows. The result of authentication is an OIDC Subject Identifier alongside various claims wrapped inside IdPAttributes. In most cases, extracting the Subject Identifier claim and exposing it as a canonical principal name makes sense. In more advanced cases it is possible to extract one of the End-User claims returned from either the id_token or UserInfo response.

The default behavior provides the former: An inbuilt C14N flow takes the Subject Identifier out of the OIDCSubjectIdentifierPrincipal (populated from the “sub” claim from the OP) and exposes it as a canonical principal name for the subject. This is identical in function to the https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631621. If that is sufficient, no further configuration is necessary, although several properties can tweak the behavior including the configuration of name transformers (see Reference).

If you don’t want that behavior, then read on.

Attribute-Sourced C14N Example

Before you can enable attribute-sourced C14N, you need to ensure the claims are mapped into IdP Attributes using appropriate attribute transcoders (which should be the case by default if you have followed the installation, see Attribute Extraction), and, importantly, you have an attribute filter policy which permits the passthrough of the attribute you are basing the C14N on (see Attribute Filtering).

If you want to extract one of the End-User claims as the canonical principal name instead of the “sub” claim value, you need to disable the inbuilt C14N flow:


## Uncomment and set this to true idp.authn.oidc.rp.c14n.subjectidentifier.disabled = true

Then, as with a similar example in the SAML Proxy authentication flow, you need to configure the attribute post-login c14n flow via properties by pointing it at "<claimName>" as a source. The properties to enable this are commented out in conf/c14n/subject-c14n.properties and are noted below.


<!-- Remove comment tags to enable Attribute-based c14n --> <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" />


idp.c14n.attribute.attributeSourceIds = mail # Allows direct use of attributes via SAML proxy authn, bypasses resolver idp.c14n.attribute.resolveFromSubject = true idp.c14n.attribute.resolutionCondition = shibboleth.Conditions.FALSE

This should result in the mail attribute being presented as the canonical principal name of the subject.

Subject Canonicalization When Using the MFA Flow

If you are using the RP inside an MFA flow, the ‘inbuilt’ subject canonicalization flow above is not responsible for producing the final principal name (although the attribute-sourced flow would be if you use that). Inside the MFA flow, you need to decide which flow you want to produce the final principal name and configure it appropriately within the shibboleth.PostLoginSubjectCanonicalizationFlow list. By default the IdP will use the c14n/simple flow and base the result on any UsernamePrincipal it finds—for example, this would be the result of the Password flow if that was used as the first factor. If you wanted the same behavior described earlier, that is to use the 'sub' claim that comes back inside the ID Token, you’ll need to add the ‘inbuilt' flow to the shibboleth.PostLoginSubjectCanonicalizationFlow. For example:


<util:list id="shibboleth.PostLoginSubjectCanonicalizationFlows"> <!-- Add this bean to the top of the list if you want it to use the 'sub' claim from the ID Token --> <ref bean="c14n/OIDCSubjectIdentifier" /> ... </util:list>


Advanced Configuration


This section described advanced configuration options which can be skipped if a basic configuration is sufficient for your needs. Options in this section relate to the following configuration files:

Configuration File


Configuration File



The properties file where most standard configuration options are found.


Additional flow configure to modify flow behaviour e.g. a place to add custom beans.


Configuration of asymmetric keys for signing and encryption


Configuration of the OpenID Provider metadata resolvers

OpenID Provider Discovery

In addition to setting the upstream OP to use via static configuration taken from the properties file, you can also supply a lookup function to determine the issuer, using the bean shibboleth.authn.oidc.rp.discoveryFunction.

Alternatively, a new discovery service flow that runs prior to this flow could be developed, for example, based on WebFinger Discovery. Such a mechanism would likely need to follow the OpenID Discovery specification and produce an Issuer Identifier that can be set as the AuthenticatingAuthority on the AuthenticationContext. To enable discovery, set the following properties:


## Comment this property out # idp.authn.oidc.rp.provider.proxyIssuer = <something> ## Set this property to true idp.authn.oidc.rp.provider.discoveryRequired = true

JSON Web Key Set Document

Asymmetric Request Object signature signing and ID Token / UserInfo response encryption, both require the RP to publicly publish signing and encryption public keys in a Key Set Document. This is presented to the OP as the jwks_uri. To enable the profile endpoint, the following profile bean must be added to the shibboleth.UnverifiedRelyingParty bean:

  • OIDC.Keyset

The profile URI: /idp/profile/oidc/rp/keyset

There is a single, global, keyset profile. If multiple downstream OPs are used there is currently no way to present different keys to different OPs.

Advanced Authentication Request Options

Response Mode

The response_mode authentication request parameter (an OAuth 2.0 authorization parameter) defines how the authentication response parameters are returned to the RP (e.g. in the query string, or HTML form parameters). By default, the ‘queryresponse_mode is used by the RP — as it is the default mode for the ‘coderesponse_type the RP supports by default. You can, however, alter this by setting the responseMode profile configuration option. In cases where there is only a single upstream OP, we can achieve this by setting the idp.authn.oidc.rp.client.responseMode property e.g.:


idp.authn.oidc.rp.client.responseMode = query|form_post

Alternatively, this can be set per upstream OP using a relying party override:


<bean id="ExampleOP" parent="RelyingPartyByName" c:relyingPartyIds="https://downstream.op.example.com/"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:responseMode="form_post"/> </list> </property> </bean>

Only the ‘query’ and ‘form_post’ response modes are supported (see OAuth 2.0 Response Types, and OAuth 2.0 Form Post).

Requested Claims Hook

The RP can request individual claims to be returned in either the ID Token or UserInfo response, see Claims Parameter. Currently, there is no default mechanism for adding requested claims for an inbound SAML authentication request i.e. from requested attributes. There is however a hook that allows you to build requested claims dynamically per request. The hook is a simple Java Function that takes the entire authentication request context tree (the ProfileRequestContext) and returns a Nimbus OIDCClaimsRequest object. An example scripted function that requests the given_name in the ID Token and family_name in the UserInfo response is shown below.

<bean id="shibboleth.authn.oidc.rp.RequestedClaimsHook" parent="shibboleth.Functions.Scripted" factory-method="inlineScript" p:inputType="org.opensaml.profile.context.ProfileRequestContext" p:outputType="com.nimbusds.openid.connect.sdk.OIDCClaimsRequest"> <constructor-arg> <value> <![CDATA[ var requestedClaims = new com.nimbusds.openid.connect.sdk.OIDCClaimsRequest() .withIDTokenClaimsRequest(new com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest().add(new com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest.Entry("given_name"))) .withUserInfoClaimsRequest(new com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest().add(new com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest.Entry("family_name"))); requestedClaims; ]]> </value> </constructor-arg> </bean>

Requesting The ACR Claim

The requested claims hook can be used to request specific Authentication Context Class References by setting the acr claim with suitable values. Note, however, if the downstream SP requested certain authentication contexts, these will be added to the acr claim alongside those in the requested claims hook before being forwarded to the upstream OP (see ACR).


A login_hint request parameter can be set per OP using a Relying Party override. The override can either take a static value or a function that derives a login_hint from the Profile Request Context at runtime.


<util:list id="shibboleth.RelyingPartyOverrides"> <bean id="OP" parent="RelyingPartyByName" c:relyingPartyIds="https://op.example.com"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:loginHint="user@example.com"/> </list> </property> </bean> </util:list>

Request Object

Authentication request parameters can be signed and encrypted (as a JWT) and passed via the request authorization parameter. Authorization Request Object parameter support is disabled by default, but can be enabled globally by setting the property idp.oidc.requestobject.used to 'true', or per RelyingParty override using p:useRequestObject="true". Note, even if enabled, the downstream OP must support the use of the request parameter and advertise that fact in its metadata document using the request_parameter_supported value, otherwise, the RP will fall back to plain OAuth 2.0 request parameters.

The RP does not currently support the request_uri parameter to pass the request object by reference as opposed to by value.

Request parameters that are contained in the Request Object JWT supersede those passed by OAuth2.0 request syntax (e.g. the query string parameters, see OIDC Core). The RP does not currently support caching the Request Object, so there is no real benefit of sending variable (dynamic) request parameters as URI parameters and fixed parameters in the Request Object.


Request object signing is enabled by default but can be disabled globally by setting the idp.oidc.requestobject.signed property to ‘false’, or per relying-party override using p:signRequestObject="false". There seems little point in disabling request object signing, as that forms one of the main benefits of using the request object — to ensure the parameters of the request object have not been tampered with, and the authenticity of the object can be determined.

(Default) Symmetric Key MAC

The default configuration for signing the request object computes an authentication tag using the HS256 MAC algorithm (the only required JWS algorithm - see RFC7518). The symmetric key used is a derivative of the client_secret shared between the OP and RP. In most circumstances, that will be sufficient.

Asymmetric Key Digital Signature

If you did want to alter this behaviour you can. The simplest way is to uncomment the idp.signing.oidc.rs.key property and point it to a suitable asymmetric JSON Web Key credential (see the example below). The potential algorithms to use are defined by the order they appear in the default security configuration. The actual algorithm to use is the first of those that are also supported by the OP (as described in its metadata; request_object_signing_alg_values_supported) and the credential you defined in the JSON Web Key file. If none are compatible, an error will be returned.

The key use is sig for ‘signature’.

{   "p": "value",   "kty": "RSA",   "q": "value",   "d": "value",   "e": "AQAB",   "use": "sig",   "kid": "defaultRSASig",   "qi": "value",   "dp": "value",   "dq": "value",   "n": "modulus-value" }

You must register the public key components of this signing key with the OP, otherwise it will have no way to validate the JWT.

If you wanted to support one OP that used RSA signatures, and another that supported EC signatures, further keys can be added to the conf/oidc-credentials.xml using the bean shibboleth.oidc.SigningCredentials. The first key that supports the chosen algorithm with a given upstream OP will then be used.

More advanced customisation of Request Object signing would require a RelyingParty override with a new OIDC Security Configuration. Below is a simple example of how that might be accomplished.

<util:list id="shibboleth.RelyingPartyOverrides"> <bean id="OverrideOP" parent="RelyingPartyByName" c:relyingPartyIds="https://<op-issuer-id>"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:securityConfiguration-ref="overrideOPSecConfig" /> </list> </property> </bean> </util:list> <bean id="overrideOPSecConfig" parent="shibboleth.oidc.DefaultSecurityConfiguration"> <property name="jwtSignatureSigningConfiguration"> <bean id="shibboleth.oidc.SigningConfiguration" parent="shibboleth.oidc.BasicSignatureSigningConfiguration" p:signingCredentials-ref="shibboleth.oidc.SigningCredentialsFactory"> <property name="signatureAlgorithms"> <list> <util:constant static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_256" /> </list> </property> </bean> </property> </bean>

Only support the HS256 signature signing algorithm. In the RP, this would restrict the Request Object JWS to using MAC-based validation.


Request object encryption is disabled by default but can be enabled globally by setting the idp.oidc.requestobject.encrypted property to ‘true’, or per relying-party override using p:encryptRequestObject="true".

Asymmetric and Symmetric Key Encryption

There are no required JWE encryption algorithms the OP must support, hence the algorithm to use is chosen by selecting the first algorithm from the Security Configuration that the OP supports and that there is a resolvable credential for. If the OP does not describe any supported request object JWE encryption algorithms, the first algorithm from the security configuration that supports a resolvable credential is used.

Usable credentials are taken from the OP’s published JWK Set document and the configured client_secret. The default configuration specifies RSA encryption first, followed by AES Key Wrapping, and then Elliptic Curve Diffie Hellman Key Agreement.

AES Key Wrapping generates a key wrapping key derived from the client_secret.

While Direct Encryption using a key derived from the client_secret is supported internally, it is disabled by default.

For OPs that support Request Objects, it is likely the JWT will be encrypted using RSA Key Encryption e.g. RSA-OAEP.

More advanced customisation of Request Object encryption would require a RelyingParty override with a new Security Configuration.

Authentication Request Message Encoders

The default message encoder used by the RP encodes the OIDC authentication request (an OAuth 2.0 authorization request) using the HTTP GET method. This defaults to constructing the authentication request parameters using URI Query String Serialization. If you would rather use HTTP POST Form Serialization you can, by setting the following property:


idp.authn.oidc.rp.httpRequestMethod = GET|POST

Or again, this could be achieved per OP using a Relying Party override and the p:httpRequestMethod="POST|GET" property.

Advanced Authentication Response Options

ID Token Decryption and Signature Validation

Signature Validation

ID Tokens are always signed (by default using RS256), but the algorithm used can be changed using the id_token_signed_response_alg client metadata/registration value on the OP. Signature validation is performed by a configured TrustEngine. By default, the set of ‘trusted’ validation keys comes from the OP’s hosted JSON Web Key Set document and the client_secret inside the ReylingParty configuration (e.g. the one supplied in the properties files). If one exists, an ‘untrusted’ validation key is extracted from the JOSE header of the JWT. If the ‘untrusted’ key is used to verify the JWS, it must be verified by one of the ‘trusted’ keys. If an ‘untrusted’ key is not supplied, the ‘trusted’ keys will be used for validation instead.

More advanced customisation of signature validation would require a RelyingParty override with a new Security Configuration.


To enable ID Token encryption on the OP, the RP must register the encryption algorithm to use by setting the id_token_encrypted_response_alg and id_token_encrypted_response_encclient metadata/registration values on the OP (or any other way the OP supports its registration).

If the OP is configured to use a symmetric key encryption algorithm, it uses a key derived from the client_secret to either wrap a content encryption key (key wrapping) or directly as the content-encryption key (direct encryption). The RP can then use the client_secret to decrypt the ID Token.

To enable asymmetric public key encryption management modes, you must first create a suitable JSON Web Key credential (see the example below), reference it with the property idp.signing.oidc.rsa.enc.key, and register its public key components with the OP. For example:


{ "p": "value", "kty": "RSA|EC", "q": "value", "d": "value", "e": "AQAB", "use": "enc", "kid": "defaultRSAEnc", "qi": "value", "dp": "value", "dq": "value", "n": "modulus" }

More advanced customisation of ID Token decryption would require a RelyingParty override with a new Security Configuration.

UserInfo Token Decryption and Signature Validation

Typically, UserInfo response signing must be enabled on the OP before it is used. This involves setting the UserInfo signed response algorithm on the OP, for example, the userinfo_signed_response_alg client metadata/registration value. Once enabled, the OP will return the UserInfo claims inside a signed JWT. The same TrustEngine mechanism used to validate ID Tokens is used to validate the UserInfo claims JWT.

Similarly, UserInfo response encryption must also be enabled on the OP before use. This involves setting the UserInfo encrypted response algorithm and the UserInfo encrypted response encryption algorithm on the OP, for example, the userinfo_encrypted_response_alg and userinfo_encrypted_response_enc client metadata/registration value. The same ID Tokens encryption/decryption mechanisms as used to decrypt the UserInfo claims JWT.

How these settings are configured may differ per OpenID Provider

Provider Metadata Lookup

Metadata for the upstream OP is fetched dynamically by an HTTP metadata resolver based on the Issuer location derived from the Issuer Identifier. More specifically by default, appending the well-known path /.well-known/openid-configuration to a normalised Issuer Identifier. This should all work without requiring any further modification.

If you do need to modify its behaviour, the configuration for the default metadata resolver could be found in /conf/authn/oidc-rp-providermetadata-resolvers.xml. Note, the resolver configuration here differs from that for normal SAML Metadata resolvers. The maxCacheDuration defines how long the metadata remains valid before it expires and is re-fetched. Unlike SAML Metadata, the OIDC Provider metadata does not explicitly define cacheDuration or validUntil settings. An example config is given below:

<bean id="ProviderHTTPResolver" parent="shibboleth.authn.oidc.rp.OIDCProviderMetadataResolver">         <constructor-arg>             <bean parent="shibboleth.authn.oidc.rp.CacheBuilder">                 <constructor-arg> <bean p:cacheId="ProviderHTTPDynamicResolver" parent="shibboleth.authn.oidc.rp.BaseProviderDynamicCacheBuilderSpec" p:minCacheDuration="PT30M" p:maxCacheDuration="PT8H" p:cleanupTaskInterval="PT30M"/>                 </constructor-arg>             </bean>         </constructor-arg>   </bean>

If required, a well-known location composition strategy can be set for the resolver by defining a BiFunction bean named shibboleth.authn.oidc.rp.WellKnownLocationCompositionStrategy which accepts a Nimbus Issuer and a string well-known path, and returns the Issuer location.

End-User Claims Merging And Sanitization

To construct the final set of End-User claims to translate and filter, the system performs two important operations:

  1. Sanatizes the UserInfo and id_token claims.

  2. Merges the sanatized UserInfo claims with those in the id_token.

The default claim sanitization strategy removes any ‘validation’ claims, and leaves ‘identity', ‘authorization’, and ‘misc’ claims. This prevents exposure of validation claims to the attribute translation and filtering stages — although these are still available to various internal functions. See the table below to show which gets removed by default.

Claim Name


Claim Name



Authorized Party, already validated while accepting a token.


Nonce to prevent reply-attacks, already validated while accepting a token.


The authentication time


Authentication Context Class. These are translated into Principal objects by Subject Population


Authentication Method Reference. These are translated into Principal objects by Subject Population


Issuer, already validated while accepting a token.


Issued At, already validated while accepting a token.


Audience, already validated while accepting a token.


Expiry, already validated while accepting a token.

The default merging strategy combines claims in the UserInfo response with those from the id_token to produce a new claims set using the following logic:

  1. If one of UserInfo or id_token claims are null, the other is returned.

  2. If both input claims are null, an empty claims set is returned.

  3. Merges the id_token claims into the UserInfo claims, the value of a claim from the id_token
    is favoured over that from the UserInfo response if the claim names clash.

Both strategies can be customised by supplying beans named shibboleth.authn.oidc.rp.ClaimMergingStrategy and shibboleth.authn.oidc.rp.ClaimSanitizationStrategy. See the Reference section below.


There are some new audit fields (in review)






The outgoing authentication request’s response_type


The outgoing authentication request’s response_mode


The outgoing authentication request’s Authentication Context Class References


The outgoing authentication request’s redirect_uri


The authentication result status of ‘success’, or the error code if the response was indicative of an error


The authentication flow steps that have run by the time this audit statement has been written. By default, these are: AuthenticationRequest, AuthenticationResponse, TokenResponse, UserInfoPlainResponse | UserInfoJWTResponse













Statically-defined Issuer ID of upstream OP to use for authentication.




OAuth 2.0 Client Identifier valid at the Authorization Server.


String list


A list of allowed origins the RP can use when dynamically creating a redirect URI to use. Can be overridden to a fixed redirect URI using the property idp.authn.oidc.rp.client.redirectURL




The redirect URI to supply to the Authorization Server during an Authentication Request. Is where the Authentication Response is sent. Will override the dynamically computed redirect computed using the idp.authn.oidc.rp.client.redirecturl.allowedOrigins




OAuth 2.0 secret known only to the IdP and the Authorization Server (OP). Used to authenticate the RP to the Authorization Server and to potentially secure JSON Web Tokens.



30 minutes

The time duration for which an OpenID Provider’s key set document is cached.


Resource path


Resource containing a JWK private key for decryption, typically a file in the credentials directory. For example, for decryption id_tokens or UserInfo tokens.


Resource path


Resource containing private key for signing, typically a file in the credentials directory. For example, to sign the Request Object (if used) sent to the Authorization Server.




Whether to invoke OP-discovery prior to running flow. Default is false as there is currently no OP discovery mechanism to use.




Should the authentication request to the Authorization Server be passed inside a Request Object (by value).




If supported, should the Request Object be encrypted.




If supported, should the Request Object be signed. Defaults to true otherwise the advantage of using a Request Object is limited to certain caching functions.




Should the RP request claims from the UserInfo Endpoint.




The mechanism the OP uses to respond to an Authentication Request from the Authorization Endpoint. Only supports one-of; ‘query’ or ‘form_post’.


String list


Define which scopes to request authorization for. By default ‘openid’ is required and always supplied. A comma separated list of additional scopes can be request e.g. ` profile,email`


String list


Comma-delimited list of protocol-specific Principal strings associated with flow. The flow must support principals requested by the SP. By default, the usual password-centric are used. These can be overridden by this property. Remember that by default these are not added to the authentication result (see idp.authn.oidc.rp.addDefaultPrincipal), instead taking any AMRs or ACRs mapped from the upstream OP.




Whether to auto-attach the preceding set of Principal objects to each Subject produced by this flow.




The mechanism by which the client authenticates to the Authorization Server when using the Token endpoint. Supports client_secret_basic and client_secret_post.




If true and the ID Token was retrieved using TLS with server validation, JWS signature checking will be skipped




The clock skew allowed when verifying the auth_time.




The maximum authentication age of the auth_time claim if it is requested by the RP in the id_token. If the max_age parameter was requested, the value of MaxAuthenticationAge in the relying party config is used to verify the authentication time and this property becomes redundant. 




Whether to lowercase the incoming NameID value prior to applying any transforms




Whether to upcase the incoming NameID value prior to applying any transforms




Whether to trim leading and trailing whitespace from the username




Disable the inbuilt C14N flow, and fall back to system wide C14N flows




Allow a missing at_hash claim




The HTTP method used when sending an authentication request to the authorization server (OP). Supports GET or POST methods.




The HTTP method used when sending an UserInfo request to the UserInfo endpoint. Supports GET or POST methods.

The following beans if needed may be defined in oidc-rp-config.xml

Bean ID / Type



Bean ID / Type




Function<HttpResponse, T>


A function bean to create a Token Request to the OP. Must consider the authorization grant and client authentication.


Function<HttpResponse, T>


A function bean to decode the token response from the OP. The default decoder just converts the JSON response into a simple JSON map.

Vendor Integration Pitfalls


  • Issuer Identifier: If you are unable to determine the issuer to use for the idp.authn.oidc.rp.provider.proxyIssuer property, it can be taken from the OpenID Connect metadata document. The location of the metadata document can be found in the Endpoints tab on the App Registrations page.

  • Issued At (iat) claim: Microsoft(Azure AD) sets the Issued At (iat) claim 5 minutes before the time at which the JWT was actually issued. To the best of our understanding, this is the way they add clockSkew to deal with clock synchronization issues. The default allowable clockSkew for the ID Token is dictated by the idp.policy.clockSkew property: this will need to be set to a value > 5 minutes so IssuedAt validation does not fail.

    • For V1.0.0 of the RP, If you do not want to set the IdP wide clockSkew property to adjust the ‘iat’ claim validation for Azure, you can override the validation bean as shown below:

      • <bean id="IssuedAtClaimsValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.IssuedAtClaimsValidator" p:clockSkew="PT6M" p:messageLifetime="%{idp.policy.messageLifetime:PT1M}" p:requiredRule="false" />


  • Google does not support the auth_time claim in ID Token responses. This prevents the RP from proxying a forced authentication request as it expects to evaluate the auth_time claim on its return in the ID Token (i.e. the auth_time was after the authentication request was sent). The only information we can find on this subject is recorded in this thread.