Generating a JSON web token for a client assertion

When using authorization code flow or hybrid flow in OpenID Connect, the client application exchanges an authorization code for an access token. During this step, the client has to authenticate itself to the server.

About this task

One way to authenticate the client to use a client secret. The best practice is to keep the client secret out of source control.

For additional security, see Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants External link opens a new window or tab instead of a client secret.

With client assertion, the client uses an X.509 certificate to prove that the token request came from the client. The client certificate is installed on the web server. Generally, it is easier to restrict access to the certificate than to ensure that nobody inadvertently reveals a client secret.

A client assertion is produced by creating a JSON payload, and then signing it with a private key.

Procedure

To generate the JSON payload:

  1. Use the following URL to download the compressed file that contains the Decision Center API JAR files:
    https://<DC_URL>/decisioncenter/assets/decision-center-client-api.zip
    In the link, <DC_URL> is the endpoint to access Decision Center.
  2. Decompress decision-center-client-api.zip. It creates a directory, called decision-center-client-api.
  3. Provide the Java™ KeyStore (JKS) file that contains the private key that can be retrieved by using an alias name.
  4. Run a command line to generate the JSON.
    You use the following JAR files:
    • jrules-teamserver.jar
    • jose4j-0.9.5.jar
    • slf4j-api-1.7.25.jar
    These files are provided in decision-center-client-api.zip, which you decompressed in step 2. You can find the files in the directory decision-center-client-api/teamserver/lib by decision-center-client-api/teamserver/lib.
    Run the following command:
    Class name com.ibm.rules.oauth.ClientAssertionHelper 
       -clientId <CLIENT_ID> 
       -tokenEndpoint <TOKEN_URL_ENDPOINT> 
       -keyAliasName <KEYSTORE_ALIASNAME> 
       -keyStorePwd <KEYSTORE_PASSWORD> 
       -keyStoreLocation <KEYSTORE_LOCATION>
       -clientAssertionSigningAlgorithm <CLIENT_ASSERTION_SIGNING_ALGORITHM> (optional)
       -clientAssertionLifetime <CLIENT_ASSERTION_LIFETIME> (optional)
    The parameters are as follows:
    • CLIENT_ID : The client ID registered in your OpenID Provider (OP)
    • TOKEN_URL_ENDPOINT: The URL endpoint of your OP to request a token
    • KEYSTORE_ALIASNAME: The alias name of your keystore that contains the private key.
    • KEYSTORE_PASSWORD: The password to access to the keystore
    • KEYSTORE_LOCATION: The location of the keystore JKS file.
    • CLIENT_ASSERTION_SIGNING_ALGORITHM: Optional signing algorithm. The default value is RS256.
    • CLIENT_ASSERTION_LIFETIME: Optional token lifetime in minutes. The default value is five minutes.
    Example command:
    export DCLIB=decision-center-client-api/teamserver/lib 
    java -cp $DCLIB/jrules-teamserver.jar:$DCLIB/jose4j-0.9.6.jar:$DCLIB/slf4j-api-1.7.25.jar com.ibm.rules.oauth.ClientAssertionHelper -clientId ee3b4617-c283-4a37-bca0-d81569a911f2 -tokenEndpoint https://login.microsoftonline.com/90df2ccb-xxxx-xxx-xxx-cc8835f62f7f/oauth2/v2.0/token
    External link opens a new window or tab -keyAliasName privatekeyforazuread -keyStorePwd myKeystorepws -keyStoreLocation ./keystore.jks
    The JSON output from the command:
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1dCI6InUxeVVjVlpTNGtFQTEweUVrRjk3ZmNaWTBESSJ9.eyJpc3MiOiJlZTNiNDYxNy1jMjgzLTRhMzctYmNhMC1kODE1NjlhOTExZjIiLCJzdWIiOiJlZTNiNDYxNy1jMjgzLTRhMzctYmNhMC1kODE1NjlhOTExZjIiLCJhdWQiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTBkZjJjY2IteHh4eC14eHgteHh4LWNjODgzNWY2MmY3Zi9vYXV0aDIvdjIuMC90b2tlbiIsImV4cCI6MTY5MzU2MDkyNiwianRpIjoiT0NJOTV3OFRMWENQSldHYlNLQ3B5ZyIsImlhdCI6MTY5MzU2MDYyNn0.MHs27oY0f3Vd4yvtgdmNW9eYc_j_PmY6G3a1vPx8peQV4ZwUUoUm5eI95_FuJ_dTPlgfcGm-OQArbH8b5GIUOtytFJlDBQhsz_9sxY-_N93DW-J8Q-wS-oc8QIlOGQgn1DVHnS0DyEfp1iyZHnaWn4GDNJgDIV1kCMLin4UriyT4n5rRs0gHoXeKAA6WFx0-PW6UbydZD3gwZ8qDnFfYcvqLOIKZ-xBNPJ0J6vzkZwShW5a7dRHaJZClmzji1y4YAPpQHImXuKHerFpj0JaGSCwMtFNqVjFfpF0W2ic_KqmnMxNNvK3driTspQHKbT6xL7GXxEYlzXduCALMJ9zwgA
  5. You can validate the JSON after generating it.
    For example, the JWT debugger External link opens a new window or tab can decode the token. A JSON web token (JWT) is a credential that gives access to resources. Be careful where you place JWTs. The tokens are not recorded. Validation and debugging is done on the client side. In particular, check the x5t parameter in the header. It is the certificate thumbprint that you retrieve on the OP side when you register the public key.
  6. Use the JWT token to get the bearer access token.
    For example, for the client_credentials flow, you can run a curl command by using the OP token endpoint.
    The following example uses a scope parameter that is necessary with Azure AD. Generally, however, it is not necessary with other OPs.
    curl -k https://login.microsoftonline.com/xxxxxxx/oauth2/v2.0/token -d "client_id=xxxxxxxx&scope=xxxxxxx%2F.default&grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=xxxxx.xxxx"