OpenID Client PKI Authentication using JWT
- The OpenID client should have a valid JWT-Bearer credential.
- The root certificate of the client credential should be trusted by the ActivID AS server.
- The token request should have a JWT assertion signed with client’s private key.
The root certificate should be imported into the ActivID AS server trust store.
When creating PKI credential, the PKI certificate to be imported should contain certificate chains (PEM or P7b) to be validated until the root certificate.
The first certificate in the chain must be the end-user certificate.
The certificate path and revocation status are now checked when importing the certificate and at authentication (CRL check can be deactivated by the ActivID AS server’s configuration file. This certificate chain will also be persisted in the database to allow certificate path validation at authentication.
The following are not checked:
Certificate name (CN)
SubjectAltNames (SAN)
Key usage (verification is performed only using the public key of the certificate)
-
Create an OpenID client with a valid JWT-bearer credential:
-
Log on to the ActivID Management Console as an ActivID Administrator (for example, ftadmin).
-
Click Register User and then proceed through the wizard to create a user with a JWT-bearer credential.
-
In the client’s details page, select the Wallet tab and verify that the authenticator is configured correctly.
-
In the Configuration tab, under Environment, select Adapters and click Add (see Create an OpenID adapter – with same name as the "OpenID administrator":).
-
Create an OpenID adapter with corresponding parameters.
-
In the Configuration tab, under Environment, select Authentication Policies and select the policy configured for the OpenID client authenticator (in this example, JWT Bearer auth).
-
Select the Assignments tab and verify that OpenID client can authenticate via the configured channel.
-
Select the Constrains tab and verify that OpenID client can authenticate with the registered credential.
-
-
Send a token request to the token endpoint with a JWT assertion signed with the client’s private key.
The client that has registered a public key, signs a JWT using the corresponding private key. The client authenticates in accordance with the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants.
The client’s token request must contain the following parameters:
-
grant_type – the value must be client_credentials.
-
client_assertion_type – the value must be urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
-
client_assertion - a signed JWT which contains the required claims set.
The JWT must contain the following Claim Values:
Required:
-
iss – (Issuer) must contain the client_id of the OpenID Client.
-
sub – (Subject) must contain the client_id of the OpenID Client.
-
aud – (Audience claim) the value that identifies the Authorization Server as an intended audience.
The Authorization Server must verify that it is an intended audience for the token. The Audience must be the URL of the Authorization Server's token endpoint.
-
jti – (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 during the validity of a JWT token for a given domain/tenant.
- exp – expiration time on, or after, which the ID Token must NOT be accepted for processing.
Optional:
-
iat – time at which the JWT was issued.
Note:The JWT can contain other Claims.
Any Claims used that are not understood must be ignored.
The authentication token must be sent as the value of the client_assertion parameter.
-
Sample Use Case 1 – Request Only Access Token
Request
POST https://[base-server-url]/{tenant}/authn/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiO….VsNg
Payload in JWT
{
"sub": "client4",
"aud": "https://server.example.com:8445/idp/domain/authn/token",
"nbf": 1535449276,
"iss": "client4",
"exp": 1535452876,
"iat": 1535449276,
"jti": "4FlhWa8t6kM5X22IjVlPz82W1XLjkA8bcTmLxiZxWFQ"
}
Response
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"access_token": "m8kwNgAAAWV/6xXHSgt6JvaPeZzsab1sPabzWP6a",
"context": {"LEVEL_OF_ASSURANCE": "2"},
"token_type": "Bearer",
"expires_in": 86400
}
Sample Use Case 2 – Request Access Token and ID Token
Request
POST https://[base-server-url]/{tenant}/authn/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
scope=openid%20profile&grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJjbGllbnQ0IiwiYXVkIjoiaHR0cH….7vg
Payload in JWT
{
"at_hash": "wcvmNj4esm3….",
"sub": "client4",
"aud": "https://server.example.com:8445/idp/domain/authn/token",
"nbf": 1535451511,
"iss": "client4",
"exp": 1535455111,
"iat": 1535451511,
"jti": "_cj5S7EMVo9NaOkCtwjE5s7fo6kJYRti8rQSrMGp5mY"
}
Response
HTTP/1.1 200 OK
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"access_token": "m8kwNgAAAWWACyZxQDXh2Ndlm1+yB7fhutLmhRA+",
"id_token": "eyJraWQiOiIxNTM0NDI5MTA0Njg1IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJjbGllbnQ0Iiw….SchA",
"context": {"LEVEL_OF_ASSURANCE": "2"},
"token_type": "Bearer",
"expires_in": 86400
}
Payload in JWT of ID Token
{
"sub": "client4",
"aud": "client4",
"acr": "2",
"iss": "https://server.example.com:8445/idp/domain/authn/token",
"preferred_username": "client4",
"exp": 1535537939,
"iat": 1535451539
}
Error Responses
Error 1 - Audience does not match
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"error_description":"Invalid request: This authorization server is not the intended audience:Audience must be the token endpoint URL",
"error":"invalid_request"
}
Error 2 – Challenge does not match
HTTP/1.1 403 Forbidden
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"error_description": "Access denied by resource owner or authorization server: Given challenge does not match the last issued challenge:Authentication Failed",
"error": "access_denied"
}
Error 3 – JWT has expired
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"error_description":"Invalid request: JWT has expired:JWT has expired (Mon Aug 27 17:07:13 CEST 2018)",
"error":"invalid_request"
}
Error 4 – Duplicated JTI
HTTP/1.1 403 Forbidden
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
{
"error_description":"Access denied by resource owner or authorization server: Duplicated JTI:Authentication Failed",
"error":"access_denied"
}