OpenID Connect

The Curity Security Token Server supports OpenID Connect. This is enabled by enabling openid configuration for the token profile that should support it. This enables the use of ID Tokens which represents user-authentications. When this mode is enabled, clients can also get more information about a user via the user info endpoint. Metadata can also be exposed when this option is enabled.

../_images/oidc-disable.png

Fig. 148 Disabled OpenID Connect as shown in the GUI

OpenID Connect is disabled by default, but can be enabled for any OAuth profile. To do so using the admin GUI, go to OAuth ‣ $PROFILE_NAME ‣ General and then enable the Open ID Connect option as shown in Fig. 149

../_images/oidc-enabled.png

Fig. 149 Enabling OpenID Connect in the admin GUI

When OpenID Connect is enabled, the following options can also be configured:

id-token-ttl
Path :/profiles/profile{id, type}/settings/authorization-server/openid-connect/id-token-ttl

The amount of time that an ID token should be valid for

passthrough-unscoped-claims
Path :/profiles/profile{id, type}/settings/authorization-server/openid-connect/passthrough-unscoped-claims

When false, all non-standard attributes returned from the account data source will be removed unless there is a corresponding scope that the end user has authorized. Setting this value to true will cause such attributes to be included in the user info endpoint’s response.

Metadata

Aside from these settings, it is also possible to configure that OpenID Connect metadata should be exposed. This is disabled by default, but can be enabled by toggling the associating setting in the GUI or setting in the CLI. In order for OpenID Connect metadata to be exposed, certain conditions have to be met. The configuration will not validate if these conditions are not met. These include:

  • The OAuth profile must have one and only one anonymous endpoint
  • An authorize endpoint must be defined
  • A token endpoint must be defined if the profile supports the client-credentials, code, resource-owner-password-credentials, or token-exchange capabilities
  • If there are more then one of any of the following kinds of endpoints, then which one should be exposed in the metadata must be configured: oauth-authorize, oauth-token, oauth-userinfo, oauth-assisted-token, oauth-revoke, oauth-introspect.

If all of these conditions are met, then the metadata can be obtained by requesting the subroute /.well-known/openid-configuration under the anonymous endpoint. For example, if the anonymous endpoint is configured to be ~, then this would be at /~/.well-known/openid-configuration on the host that is serving the OAuth profile’s anonymous endpoint. If this endpoint were hosted on a service that used the HTTPS protocol, had a hostname of localhost and was listening on port 8443, then the metadata would be accessible at https://localhost:8443/~/.well-known/openid-configuration.

The metadata in this response is mostly defined by the OpenID Connect and OAuth metadata standards where applicable. The included metadata and its meaning is described in the following table:

OpenID Connect Metadata

OpenID Connect metadata fields that are returned depending on various configuration

Object Properties:
 
  • issuer (string) – The issuer ID. This will be the URL of the anonymous endpoint unless issuer-override has been set to some non-URL value.
  • introspection_endpoint (url) – If there is only one introspection endpoint defined in the profile, then the URL of this endpoint. If there are multiple, the URL of the one that is configured to be exposed. If no introspection endpoint is defined in the profile, this value will not be included in the response.
  • authorization_endpoint (url) – If there is only one authorization endpoint defined in the profile, then the URL of this endpoint. If there are multiple, the URL of the one that is configured to be exposed.
  • token_endpoint (url) – If there is only one token endpoint defined in the profile, then the URL of this endpoint. If there are multiple, the URL of the one that is configured to be exposed. If there is no token endpoint defined in the profile and the profile does not support the client-credentials, code, resource-owner-password-credentials, nor the token-exchange capabilities, then this value will be not be included in the response.
  • jwks_uri (url) – The URL of the JSON Web Key Set (JWKS). This will be the URL of the OAuth profile’s anonymous endpoint with jwks appended.
  • revocation_endpoint (url) – If there is only one revocation endpoint defined in the profile, then the URL of this endpoint. If there are multiple, the URL of the one that is configured to be exposed. If there is no revocation endpoint defined in the profile, then this value will be not be included in the response.
  • assisted_token_endpoint (url) – If there is only one assisted endpoint defined in the profile, then the URL of this endpoint. If there are multiple, the URL of the one that is configured to be exposed. If there is no assisted token endpoint defined in the profile and the profile does not support the assisted-token capabilities, then this value will be not be included in the response.
  • scopes_supported (string[]) – The scopes that the OAuth profile supports which always includes openid.
  • response_types_supported (string[]) –

    The response types that the OAuth profile supports. The elements of the array will be as summarized in the following table:

    Capability Enabled in the OAuth Profile JSON Array Values
    code
    • code
    • code id_token
    • code id_token token
    • id_token
    implicit
    • id_token
    • id_token token
    • token
    code and implicit
    • code token
    • code token id_token
    client-credentials token
    resource-owner-password-credentials token
  • response_modes_supported (string[]) – The response modes that the OAuth profile supports. If the code capability is enabled, the array will include query, and if the implicit capability is enabled, the array will also include fragment. If both of these capabilities are supported in the profile, this array will contain both of the associated values.
  • grant_types_supported (string[]) –

    The grant types or “flows” that are supported by the OAuth profile. The elements of the array will be as summarized in the following table:

    Capability Enabled in the OAuth Profile JSON Array Values
    code
    • authorization_code
    • refresh_token
    implicit
    • implicit
    resource-owner-password-credentials
    • password
    • refresh_token
    client-credentials client_credentials
    token-exchange https://curity.se/grant/accesstoken
    assisted-token https://curity.se/grant/assisted-token
  • acr_values_supported (string[]) – The ACRs of all authenticators in the authentication profile associated with the profile.
  • subject_types_supported (string[]) – An array containing the string value pairwise, and when pairwise subject identifiers are not required, will also contain the string value public.
  • id_token_signing_alg_values_supported (string[]) – A singleton array containing the string RS256.
  • token_endpoint_auth_methods_supported (string[]) – An array containing the strings client_secret_post and client_secret_basic which represents the authentication methods supported by the token endpoint.
  • revocation_endpoint_auth_methods_supported (string[]) – An array containing the strings client_secret_post and client_secret_basic which represents the authentication methods supported by the revocation endpoint.
  • claim_types_supported (string[]) – An array containing the single string value normal, meaning that only normal claims, as opposed to distributed claims, are supported. Distributed claims can be supported using token issuance procedures, but the Curity Security Token Server does not advertise support for this in the metadata.
  • ui_locales_supported (string[]) – An array containing the BCP47 formatted names of the locals installed in the the Curity Identity Server. If a new locale is added to the $IDSVR_HOME/usr/share/messages/overrides directory, this new locale will be added to the published metadata.
  • claims_locales_supported (string[]) – The same as ui_locales_supported. Claims may be localized into other languages using token issuance procedures, but these are not included in the metadata.
  • code_challenge_methods_supported (string[]) – If the code capability is configured for the OAuth profile, then the array will contain the elements S256 and plain; otherwise, this property will be excluded from the metadata. These values are defined by Proof Key for Code Exchange by OAuth Public Clients (PKCE).
  • service_documentation (url) – The URL where developers can find the documentation describing how to integrate with the service. This URL is the one set by the developer-documentation-url configuration setting.
  • registration_endpoint (url) – The URL where dynamic clients can submit their registration information to obtain a new client ID and secret. If dynamic client registration is not enabled for the profile, this value will not be included in the response.
  • registration_endpoint_auth_methods_supported (string[]) – The authentication methods that are supported by the dynamic client registration endpoint. The value will always be a singleton array containing the value Bearer, meaning a bearer access token that represents the user or client’s authorization of the caller. If dynamic client registration is not enabled for the profile, this value will not be included in the response.
  • op_policy_uri (url) – The policy URL where developers of dynamically registered clients can obtain the policy by which registration is governed.
  • op_tos_uri (url) – The URL of the terms of service that dynamic clients can show to users, so they are aware of the conditions under which they may use the OAuth server.
  • end_session_endpoint (url) – the URL that the RP can redirect the user to to request Logout
  • check_session_endpoint (url) – the URL that the RP can load in an IFrame to check the user’s SSO status with the OP, see Session Endpoint
  • frontchannel_logout_supported (boolean) – indicates whether front channel logout notification is supported
  • frontchannel_logout_session_supported (boolean) – indicates whether front channel logout notification from Curity can include the logged out sid as parameter to the logout uri
  • backchannel_logout_supported (boolean) – indicates whether back channel logout notification is supported
  • backchannel_logout_session_supported (boolean) – indicates whether back channel logout notification from Curity can include the logged out sid as claim in the Logout Token

An example of the OpenID Connect metadata is shown in Listing 205.

Listing 205 Example OpenID Connect metadata
{
  "introspection_endpoint": "https://localhost:8443/introspection",
  "scopes_supported": [
    "read",
    "admin_read",
    "openid",
    "profile",
    "admin_write",
    "write",
    "email"
  ],
  "issuer": "https://spruce:8443/dev/oauth/anonymous",
  "acr_values_supported": [
    "urn:se:curity:authentication:google:google1",
    "urn:se:curity:authentication:sms:sms2fa",
    "urn:se:curity:authentication:sms:sms1",
    "urn:se:curity:authentication:html-form:html2fa",
    "loa1"
  ],
  "authorization_endpoint": "https://localhost:8443/dev/oauth/authorize",
  "introspection_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "service_documentation": "https://localhost/developer-documentation-url",
  "claim_types_supported": [
    "normal"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "response_modes_supported": [
    "fragment",
    "query"
  ],
  "token_endpoint": "https://localhost:8443/dev/oauth/token",
  "response_types_supported": [
    "code",
    "id_token",
    "token"
  ],
  "revocation_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "grant_types_supported": [
    "refresh_token",
    "implicit",
    "client_credentials",
    "password",
    "https://curity.se/grant/accesstoken",
    "authorization_code",
    "https://curity.se/grant/assisted-token"
  ],
  "ui_locales_supported": [
    "sv",
    "en"
  ],
  "revocation_endpoint": "https://localhost:8443/revoke",
  "userinfo_endpoint": "https://localhost:8443/dev/oauth/userinfo",
  "code_challenge_methods_supported": [
    "S256",
    "plain"
  ],
  "jwks_uri": "https://localhost:8443/dev/oauth/anonymous/jwks",
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "S256"
  ],
  "assisted_token_endpoint": "https://localhost:8443/assisted-token",
  "claims_locales_supported": [
    "sv",
    "en"
  ]
}

The “claims” request parameter

There are two ways to request profile data to be included in the ID-token or the response of the user info endpoint, which are by requesting scopes and by requesting individual claims through the claims request parameter. As specified by OpenID Connect, the claims parameter is a JSON document which has the option to request each claim individually, as opposed to the claim sets that are specified by the OpenID scopes.

Given that OpenID Connect is enabled on the profile, claims request parameter support is enabled by default. When more fine grained control over the requested claims is needed, it is possible to do so from the different token procedures for each flow that issues an ID token or returns a user info response. By default, the claims parameter is stored with the delegation, and as such it can be found like this:

  • In the oauth-authorize-implicit and oauth-token-authorization-code procedures: context.getDefaultDelegationData().requestedClaims
  • In the openid-userinfo procedure : context.presentedToken.getDelegationData().data.requestedClaims.

The parameter is the string with the JSON document. To use it, you need to parse it still. An example of how to process the parsed claims request parameter is included in the oidc/claims-parameter directory of the examples. Note that this string comes from an unverified and possible unsafe source (i.e. user input), and parsing it incorrectly could introduce a security vulnerability.

The claims request parameter is used to establish which claims from the profile data must be included in an ID token or in the user info response. If the authenticated account data contains non-standard attributes, there is no enforcement on whether these claims can be exposed. To allow these claims to be exposed, make sure to enable the Pass Through Unscoped Claims configuration option of the OpenID Connect settings on the Token Profile.

There is access control applied on the claims that can be requested by clients. This access control is based on the allowed scopes for the client, in particular the OpenID Connect scopes (profile, email, phone and address). These scopes represent a set of claims, and by these scopes to be requested by a client, this also allows the claims that they represent to be requested through the claims parameter. However, claims that are not OpenID Connect claims are always released when the Pass Through Unscoped Claims setting is enabled (see above).

For example, in case the client does not allow the profile claim to be requested, yet there is a request for the picture claim, this request will be rejected because it is not an OpenID Claim that is represented by an allowed OpenID Connect scope. If instead the request is for the big-picture (which is not an OpenID Connect claim), and Pass Through Unscoped Claims is enabled, then that account attribute would be released if it were available.

Note that requesting the acr claim with a specific value will result in requiring authentication to be performed with that particular acr.

Issuing pseudonymous subject identifiers

By default, when a user authenticates, the authenticated subject is passed along unmodified in tokens issued to the client. In environments where different clients should not be able to share properties that are bound to a subject amongst each other, it is possible to issue pseudonymous subject identifiers. These pseudonyms will be the same for one user to a client, but will be different for that same user to a different client. The intent is that different clients will not be able to link their databases with each other and create a bigger user profile than the user might expect.

The OpenID Connect specification describes a way to express how to issue pseudonymous subject identifiers. Pseudonyms are called Pairwise Pseudonymous Identifiers (PPIDs) because they are based on the pair of Subject Identifier and Sector Identifier. If a sector identifier is not explicitly set, it is derived for each client, based on its registered redirect URI’s: if all the redirect URI’s share the same host component, then this shared host component is used as the sector identifier. If there is no redirect URI or if there are multiple redirect URIs with different host components, then it is required to configure a sector identifier for the client explicitly.

Example A client does not configure a value for sector identifier, but it has registered redirect URI https://www.example.com/cb. In case a pairwise pseudonym is calculated, this is done by taking the host component (www.example.com) of this redirect URI and feeding it into the algorithm. When a user has authenticated as teddie, then the pseudonym to be issued is calculated like:

pseudonymize("teddie", "www.example.com")

In case the client has multiple redirect URIs registered, e.g. https://www.example.com/cb and https://another.example.com/cb, it is required for the client to also register a Sector Identifier. Say the Sector Identifier is registered as Sector Zort, then the pseudonym to be issued is calculated like:

pseudonymize("teddie", "Sector Zort")

Note

Mobile Connect requires a sector identifier to be a URL even for statically registered clients. To conform to this profile, an administrator should use a URL instead of some other value. Be aware that the configuration is not validated for such a case.

Client settings

A client will always be issued a non-pseudonym, unless it is enabled to issue Pairwise Pseudonyms for that client. Once enabled, no more unprocessed subject identifiers will be issued.

Different clients will be issued different pseudonyms for the same user, unless multiple clients share the same Sector Identifier, as explained in the previous paragraph. If this is desired, you can explicitly set the Sector Identifier that is used to calculate a pseudonym for the subject.

Caution

Be careful when changing a Sector Identifier on an existing client, as the result will be that all users will be assigned a new subject identifier; the client will not be able to find out which new subject identifier referred to which old subject identifier.

Profile settings

There is a setting on the profile that indicates whether it is required to issue pairwise pseudonyms to clients. This setting is particularly useful in case a profile is setup for Dynamic Client Registration: when the profile requires pairwise pseudonyms, a new non-templatized client must be registered with a subject_type=pairwise parameter, or it will be rejected upon registration.

To calculate the issued pseudonym, the same logic applies to configured clients as well as dynamically registered clients: by default the explicitly configured Sector Identifier value will be used in the pair of Subject Identifier and Subject Identifier. In case there is no configured sector identifier, the hostname of the configured redirect URI or URI’s will be used. If that fails because none or there are more than one different host names found in the redirect URI’s, an error will occur.

Sector Identifier for Dynamic Client Registration

When doing Dynamic Client Registration, a client can not just say which Sector Identifier it wants to use. The reason for that is to protect users from clients that want to join a sector, and thereby getting issued with the same pairwise pseudonyms as every other client in that sector, without anyone checking that! Instead, a mechanism is in place that will verify whether a sector identifier can be accepted, which is based on the sector_identifier_uri parameter.

Curity supports this approach, and will fetch the document from the location that is referred to in the sector_identifier_uri location. It will verify the document as specified in the OpenID Connect Dynamic Client Registration specification.

You can use the sector-identifier-lookup-http-client configuration option of Dynamic Client Registration settings to change the HTTP client that must be used to look up the sector_identifier_uri document.

When the request is accepted, the hostname component of the sector_identifier_uri will be used as Sector Identifier. For example, if a client registers with the parameters subject_type=pairwise and sector_identifier_uri=https://my.example.com/sector-info, pairwise pseudonyms are calculated as pseudonymize("teddie", "my.example.com")

Templatized Dynamic Client Registration

As Registration Based on a Template Client registers a client based on only a reference to the client template, it could lead to all registered clients using the same Sector Identifier, which effectively reduces a pairwise pseudonym into a regular pseudonym. In this case however, Curity will use the client’s ID of a dynamically registered template client as the sector identifier. Note that this is only the case when the client template is configured to issue pairwise pseudonyms.

Example A dynamically registered client based on a client template was issued the id 192-riw-1uc. In this case, the pairwise pseudonym for user teddie is calculated like this:

pseudonymize("teddie", "192-riw-1uc")