Client Authentication

Clients, like users, can authenticate in various ways.

Clients may be public or confidential, depending on their usage. In general, only clients that are meant to be used by web applications are public. Mobile phone applications and backend servers typically use a confidential client.

Confidential clients must authenticate against the Token Profile to confirm their identity.

The following authentication methods are available:

Some of these methods must first be enabled on the Token Profile before they can be added to a client.

Clients may also have a secondary authentication method, in which case the OAuth client can authenticate using the secondary method as a fallback.

The following sections go through details about how each authentication method works.

Authentication Methods#

Client Secret#

Client authentication using Client Secret can be done either through the “Authorization” request header, or through form-encoded parameters.

When using the “Authorization” header, the Basic HTTP Authentication scheme is expected.

When submitting credentials by POST-ing them in the request body, the parameter names must be:

  • client_id.
  • client_secret.

Note that if both mechanisms are used, the “Authorization” header credentials take precedence and the credentials from the POST-body data are ignored.

Since version 10.0, the Identity Server performs URL-decoding of the userid and the password components of the Authorization header value to establish the client ID and secret. This aligns with OAuth 2.0, which states that clients should encode their ID/secret in this context.


To avoid blocking server upgrades in cases where client secrets contain encoding sequences (e.g. +) but clients are not URL-encoding them in the Authorization header, the se.curity:identity-server:authorize:allow-unencoded-client-secret-on-basic-auth system property can be set to true. In this case, the server also checks the client secret without decoding it, as a fallback.


Note that this property is meant to allow a transition period on edge-case scenarios and it will be removed in a future major release. Clients should be updated to URL-encode the ID and secret for the Authorization header value or use values without unsafe characters.

Client Assertion JWT#

A client can be configured to authenticate with a JWT (JSON Web Token) signed with an asymmetric key (a private RSA key, where the public key is stored in a keystore known to the Identity Server).

In the following example, an asymmetric key will be used for signing the JWT.

Server configuration#

Ensure that at least one signature-algorithm is selected for client-authentication in the configuration to allow for asymmetric algorithms like RS256 to be used for client authentication.

When allowing JWT’s to be used for client authentication, two options for configuration emerge under the node aptly named using-jwt. If enforce-unique-jti-values is set the jti (JWT ID) value of each JWT sent will be checked and authentication denied if the Identity Server has seen the same jti being used before.

This ensures that client assertion JWT’s must be used as one-off tokens. While a very good practice, as this might be quite cumbersome for the client this setting is disabled by default.

Setting the clock-skew allows for some difference in time between the signing client and the Identity Server. The default of 10 seconds should be enough for most cases, but adjust if needed.

Client configuration#

Using the asymmetric-key setting on our client, we can point to a public key (signature verification key) stored by the Identity Server.

The private key used for signing does not have to be available to anyone but the client. Note that the algorithm used must correspond with the one defined in the JWT header (see example below).

Example client assertion JWT

Both the sub (subject) and the iss (issuer) claim must correspond to the client ID of the authenticating client. The aud (audience) claim is the receiver of the token and should be that of a configured token endpoint in the Identity Server or the Identity Server issuer. The jti is the ID of the token and should preferably be unique (see Server configuration above for how to enforce this), but could be any value. Last, the exp (expires) claim defines when the token should no longer be considered valid (seconds since epoch).

JWT header

{
    "alg": "RS256",
    "typ": "JWT"
}

JWT body

{
    "sub": "client-one",
    "iss": "client-one",
    "aud": "https://curity.example.org/oauth/v2/token",
    "jti": "958af185-2bb8-4a08-be87-3f89138c0b6e",
    "exp": 1511801974
}

The JWT is now signed with a private key for which the Identity Server has the corresponding public key stored in its keystore and referenced by the client (which in the example above would be client-one).

The client assertion JWT is now ready to be used at an endpoint that would normally accept client credentials, such as the token, introspection or revocation endpoints.

An example request could look something like this:

POST /oauth/v2/token HTTP/1.1
Host: curity.example.org
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
client-assertion-type%3Ajwt-bearer&
client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6IjIyIn0.
eyJpc3Mi[...omitted for brevity...].
cC4hiUPo[...omitted for brevity...]

More information on client assertion JWT’s can be found in the OpenID Connect specification on Client Authentication as well as RFC-7253 (note however that the Identity Server does not implement the latter specification in its entirety).

Workload Identity Support

A client may also authenticate using workload identities.

When a platform where workloads run issues a client assertion JWT, it usually conforms to RFC-7253. The body of such a JWT could look similar to this:

{
  "aud": [
    "https://login.examplecluster.com/oauth/v2/oauth-anonymous"
  ],
  "exp": 1701463685,
  "iat": 1701456485,
  "iss": "https://kubernetes.default.svc.cluster.local",
  "nbf": 1701456485,
  "sub": "system:serviceaccount:applications:mywebworkload"
}

Note that:

  • it has no jti claim
  • the iss claim contains the platform issuer string (instead of client ID)
  • the sub claim contains the string identifying the workload identity

The JWT assertion signature should be verified with a key obtained from a JWKS URI, which is provided by the platform, such as https://kubernetes.default.svc.cluster.local/openid/v1/jwks.

When the Identity Server validates JWT assertions used for client authentication, by default it requires that the jti claim is present; and sub and iss claims have to both contain the client ID. To make platform-issued JWT assertions pass Identity Server validation, a client could have the jwks-uri client authentication configured with the uri pointing to the JWKS URI provided by the platform.

Additionally, the assertion-jwt-validation settings (a sibling to the jwks-uri configuration) has to be configured. These settings are comprised of:

  • issuer, which has to be set to the platform issuer string
  • jti-required, which has to be set to false in case the platform issues JWTs assertions with no jti claim.

The Identity Server will use the sub claim to identify the client which should be authenticated with the received assertion JWT. This claim will contain a string identifying the workload, which can be a string like spiffe://examplecluster.internal.com/ns/applications/sa/mywebworkload.

It can be undesirable to have clients with such complicated names, therefore the Identity Server provides an option to configure a mapping from the value in the sub claim to a client ID. The mapping configuration option is called client-id-mappings and it can be found in the client-authentication’s using-jwt container.

The following screenshot shows how you can map a sub claim value of spiffe://examplecluster.internal.com/ns/applications/sa/mywebworkload to a client ID my-client:

Configuring Client ID Mappings
Adding a Client ID mapping. (Admin UI version: 10.6)

This mapping will be used for all JWT assertions used for client authentication.

Asymmetric Cryptographic Key#

The client is expected to sign a JWT for authentication.

The Curity Identity Server must be configured with the public key that can be used to verify the JWT’s signature.

Allowed asymmetric signing algorithms for JWT’s are:

  • RS256
  • RS384
  • RS512
  • PS256
  • PS384
  • PS512
  • ES256
  • ES384
  • ES512
  • EdDSA

Symmetric Cryptographic Key#

Similar to the Asymmetric Cryptographic Key Authentication Method, but the client uses a symmetric key for signing its JWT or integrity-protect it.

Allowed symmetric signing algorithms for JWT’s are:

  • HS256
  • HS384
  • HS512

Mutual TLS#

Mutual TLS means that the client and server will establish a TLS connection where each party must present their certificate to the other.

Just like the client must trust the server certificate in “normal” TLS, in Mutual TLS, the Curity Identity Server must also trust the certificate presented by the client.

To configure Mutual TLS, one of the following trust options must be selected:

  • Client DN - DN of the client certificate.
  • Client DNS Name - dNSName SAN entry of the client certificate.
  • Client URI - SAN entry in the client certificate.
  • Client IP - IP address in the client certificate.
  • Client Email - rfc822Name SAN entry in the client certificate.
  • Trusted CA list - The CAs that must be the issuer of the client certificate.
  • Pinned Client Certificate - The client certificate that must be used to authenticate.
Configuring the Pinned Certificate Authentication Method
Configuring the Mutual TLS Authentication Method to use a pinned certificate. (Admin UI version: 10.6)

Detailed information about Mutual TLS and all of the above trust options can be found in the dedicated Mutual TLS page.

Mutual TLS by proxy#

This authentication method allows Mutual TLS to be terminated in a proxy instead of directly within the Curity Identity Server.

Notice that the following settings must be configured in the Token Profile before any client is allowed to use this method:

  • userid - User ID credential that the proxy uses to authenticate using HTTP Basic authentication through a Proxy-Authorization header.
  • password - Password credential that the proxy uses to authenticate using HTTP Basic authentication through a Proxy-Authorization header.
  • client-certificate-http-header - Name of the HTTP header that the proxy uses to include the PEM- or base64-encoded DER representation of the client certificate in the forwarded request.

Additionally, one of the trust options described in the Mutual TLS authentication method must be selected.

See also the Mutual TLS by Proxy page.

Credential Manager#

The Credential Manager is used to verify the client secret.

Configuring the Credential Manager Authentication Method
Configuring the Credential Manager Authentication Method. (Admin UI version: 10.6)

JWKS#

A JWKS providing keys that can be used to verify JWT assertions. The JSON String should be base64-encoded.

JWKS URI#

A key present in a JWKS referenced by an URI, accessed via an optional HTTP client ID

Secondary authentication#

It is also possible to define an optional secondary client authentication method, used only if the request failed client authentication using the primary method. This secondary method is useful for achieving high availability even during client credential rotations or authentication method upgrades.

Example:

Update client secret from S1 to S2:

  1. Configuration administrator changes secret from S1 to S2 on the primary method and creates a secondary method using the S1 secret. This ensures that both S1 and S2 will be usable simultaneously.

  2. Client stops using S1 and starts using S2.

  3. Configuration administrator removes the secondary method.

Example:

Update client from using secret S1 to use client assertions with key K1.

  1. Configuration administrator changes primary authentication from secret S1 to client assertion susing key K1. In the same configuration change, she also creates a secondary method using the S1 secret, allowing both methods to be used simultaneously.

  2. Client stops using S1 secret and starts using client assertions with key K1.

  3. Configuration administrator removes the secondary method.

When defining a secondary method it is also possible to define an associated expiry date, after which the secondary method will not be usable.

Was this helpful?