Client authentication

Note that client authentication can be used both in the context of end-user authentication (for example in combination with Authorization Code Flow), and as a system-only authentication using Client Credentials only.

The type of client authentication method available will depend on the Security Domains , context and application.

As described in the OIDC specification, clients can be Confidential Clients, capable of keeping secrets or Public Clients not capable of holding secrets (or some other factor deeming client secrets unnecessary).

Client identifier

In any case, a Client Id (Client Identifier) is required. This means that, regardless of Confidential or Public clients, a Client Id must be registered with (and possibly issued by) Buypass OpenID Provider before use.

The Client Id will be registered within a Security Domain and will also need to specify and handle scopes and claims relevant for that domain.

Tokens will not be issued to unregistered clients.

Client authentication methods

In general, Buypass only support Confidential Clients. The exception is clients using the Implicit Flow. All other supported flows and grants require Confidential Clients.

OIDC define several client authentication methods for Confidential ClientsClient Authentication.

client_secret_basic / client_secret_post

These authentication methods are only supported in Security Domains where the security risk of client impersonation is low or in closed domains where the additional security is considered unnessesary.

private_key_jwt

Buypass uses private_key_jwt as a default client authentication mechanism for open Security Domains  and high level IDs like the BuypassID Domain.  

In short this means that in addition to the Client Id, a public key must be registered with (and possibly issued by) Buypass. The corresponding private key must be used by the client to sign a JSON Web Token (JWT) sent as part of the client authentication request. This is typically done using a Buypass Merchant certificate or a more general Enterprise certificate, depending on the application.

Client request JWT claims

The following minimum claims must be defined in the client request JWT:

ClaimRequiredDescriptionExample value
issyes

Issuer. 

Should be set to the Client Id (Client Identifier) of the OIDC/OAuth2 client

oidc-client
subyes

Subject.

Should be set to the Client Id (Client Identifier) of the OIDC/OAuth2 client

oidc-client
audyes

Audience.

Should be set to the URL of the OpenID Provider/OAuth2 Authorization Server issuer URL.

https://auth.buypass.no/auth/realms/SECURITYDOMAIN

jtiyes

JWT ID.

A unique identifier for the token, which can be used to prevent reuse of the token.

These tokens MUST only be used once.

Se also: JWT ID Claim

461d5788-2a18-4e63-9e35-7097e02b0227
expyes

Expiration time on or after which the JWT MUST NOT be accepted for processing.

See also: Expiration Time Claim

Date format should be in "NumericDate", ref JWT terminology.

1510831578
iatyes

Time at which the JWT was issued.

See also: Issued At Claim

Date format should be in "NumericDate", ref JWT terminology.

1510831518

Example

Example below using a small NPM cmdline tool for generating the JWT: jwtgen. Using the curl tool, the JWT is then sent as authentication data in the post request directly to the token endpoint.

Example using jwtgen to generate JWT and curl to post the request
SD="SECURITYDOMAIN"
ISSUER_URL="https://auth.buypass.no/auth/realms/${SD}";
TOKEN_URL="${ISSUER_URL}/protocol/openid-connect/token";
CLIENT_ID="oidc-client";

# Assuming private key and certificate is available in the keystore named:
# ${CLIENT_ID}-keystore.p12

# Export the certificate
openssl pkcs12 -in ${CLIENT_ID}-keystore.p12 -nokeys -out ${CLIENT_ID}-jwt-cert.pem
# Export the private key (unencrypted)
openssl pkcs12 -in ${CLIENT_ID}-keystore.p12 -nodes -nocerts -out ${CLIENT_ID}-jwt-key.pem

JTI=`uuidgen`
JSON="{
    \"iss\": \"${CLIENT_ID}\",
	\"sub\": \"${CLIENT_ID}\",
    \"aud\": \"${ISSUER_URL}\",    
    \"jti\": \"${JTI}\"
}"

# Generate signed JWT (including exp and iat claims)
CLIENT_JWT=`jwtgen -a RS256 -e 3600 -p ${CLIENT_ID}-jwt-key.pem --claims "${JSON}"`

# Post client authorization request using curl
curl -i -w "\n" \
-H "Content-Type: application/x-www-form-urlencoded" \
-X POST "${TOKEN_URL}" \
-d "grant_type=client_credentials"\
"&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer"\
"&client_assertion=${CLIENT_JWT}"

Two-Way TLS client authentication

In addition to supporting the standard OIDC client authentication methods, Buypass also support two-way TLS or Mutual TLS authentication (mTLS), https://tools.ietf.org/html/rfc5246#section-7.4.6.

Note that this authentication method is only available for selected clients and authentication scenarios for B2B setups (for example in the EnterpriseID Domain). 

The two-way TLS authentication protocol is standardised and done as a part of the low level TLS socket connection and transparent to the HTTP and OIDC/OAuth protocols. The protocol uses certificates and the Client Id must somehow be communicated in the certificate. This is one of the reasons that the applications of Two-way TLS is service/application limited, as there need to be a correlation between the certificate metadata and the OIDC client.

Example

Using the curl tool, the two-way TLS authentication is done using the supplied certificate (and client key). The further client authentication is then further implicit as  the request is done over the established TLS connection, directly to the token endpoint. 

Note the parameter "?_tlsclientauth=1" added to the TOKEN_URL. The parameter is used to trigger two-way TLS only if requested, if multiple authentication methods are available.

Example using jwtgen to generate JWT and curl to post the request
SD="SECURITYDOMAIN"
ISSUER_URL="https://auth.buypass.no/auth/realms/${SD}";
# Note: Parameter to trigger MTLS inly when requested
TOKEN_URL="${ISSUER_URL}/protocol/openid-connect/token?_tlsclientauth=1";
CLIENT_ID="oidc-client";

# Assuming private key and certificate is available in the keystore named:
# ${CLIENT_ID}-keystore.p12

# Export the certificate
openssl pkcs12 -in ${CLIENT_ID}-keystore.p12 -nokeys -out ${CLIENT_ID}-cert.pem
# Export the private key (unencrypted)
openssl pkcs12 -in ${CLIENT_ID}-keystore.p12 -nodes -nocerts -out ${CLIENT_ID}-key.pem

# Post client authorization request using curl
curl -v -i -w "\n" \
--cert ${CLIENT_ID}-cert.pem \
--key ${CLIENT_ID}-key.pem \
-H "Content-Type: application/x-www-form-urlencoded" \
-X POST "${TOKEN_URL}" \
-d "grant_type=client_credentials"\
"&client_id=${CLIENT_ID}"