X

Best Practices from Oracle Development's A‑Team

  • August 22, 2020

Create a JWT Token in Java for Oracle IDCS

Introduction

An Oracle OIC customer wants to pass a username to OIC integration instances when triggering them via a REST call. But the customer does not want to use a password for security reasons. One way to implement this use case is to set a username in a self (the customer) generated and signed JWT token, use that JWT token to obtain an access code from IDCS and finally use the access code to trigger OIC instances.

There are a few steps that need to take place in order to achieve our goal. In my search for a solution, I found a few blogs that were very helpful in providing information on how to accomplish some of these necessary steps. But in terms of creating a JWT token that is acceptable to IDCS, I have yet found any documentation that provides a working set of instructions (Please see the footnote). After some trial-and-error effort, I managed to create my own JWT token that worked with IDCS. I would like to share my findings with other developers in this blog. I will start by briefly describing all the required artifacts and configurations.

IDCS Configuration: Create and Configure a Confidential Application

The blog Trigger OIC Integration Using OAuth by Greg Mally provides a detailed guide on these steps. It also has good information on using Postman for testing, which we will do for our own testing.

For our use case, we will set the grant types to Client Credentials and JWT Assertion only as in the following image.

From this step, you will record three values: client ID, client secret, and scope value.

Preparation for Using JWT

Please follow the blog Authentication and User Propagation for API Calls by Olaf Heimburger to complete the following tasks:

1. Create a key pair in a key store, export the public certificate in a file, and record the alias for your public key.

2. Import the public certificate into the confidential application created in the previous step. This is for signature verification.

3. Import the public certificate into the Partner Setting to set up a trust relationship.

 

Create a JWT Token

Download the JWT Library

At jwt.io, you can find many JWT libraries for different programming languages. I use jjwt (Java JWT: JSON Web Token for Java and Android) in this exercise. For us non-Maven user, we need to manually download the required libraries:

jackson-annotations-2.11.2.jar

jackson-core-2.11.2.jar

jackson-databind-2.11.2.jar

jjwt-api-0.11.2.jar

jjwt-impl-0.11.2.jar

jjwt-jackson-0.11.2.jar

jjwt-orgjson-0.11.2.jar

Construct a JWT Token

The following code snippets show how to set up a JWT token programmatically.

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import java.io.File;
import java.security.Key;
import java.security.KeyStore;
import java.util.Date;
import java.util.UUID;
...

            // Read the private key from the key store
            KeyStore ks = KeyStore.getInstance(new File(keyStoreFileName), keyStorePassword.toCharArray());
            Key key = ks.getKey(alias, keyStorePassword.toCharArray());
            
            JwtBuilder jwtBuilder = Jwts.builder();
            
            // Set up the header first
            jwtBuilder.setHeaderParam("alg", "RS256");
            jwtBuilder.setHeaderParam("typ", "JWT");
            jwtBuilder.setHeaderParam("kid", "key-alias"); // This property must be specified. If missing, you will get "Invalid User Assertion"
            
            jwtBuilder.claim("sub", "username"); // subject = username
            jwtBuilder.claim("prn", "username"); // principle = username
            
            // The following combination works
//            jwtBuilder.claim("aud", "https://identity.oraclecloud.com/"); // audience = a fixed value to this value for IDCS
//            jwtBuilder.claim("iss", "https://identity.oraclecloud.com/"); // Issuer = fixed 
            
            // The following combination works
            jwtBuilder.claim("aud", "https://identity.oraclecloud.com/"); // audience = a fixed value to this value for IDCS
            jwtBuilder.claim("iss", "c54859b3b7054cxxxxea864cb211a21c"); // Issuer = fixed to IDCS app client id 

            UUID uuid = UUID.randomUUID();
            
            Date date = new Date();
            long iatSeconds = date.getTime() / 1000;
            long expSeconds = iatSeconds + 1 * 60 * 60; // set the JWT expiration to 1 hour. Can be longer
            
            jwtBuilder.claim("iat", iatSeconds);
            jwtBuilder.claim("exp", expSeconds);
            jwtBuilder.claim("jti", uuid.toString());

            // Sign the token with the private key
            String jwt = jwtBuilder.signWith(key).compact();

 

Here is the JWT token we build in the Java code above in JSON format (header.payload):

{ "alg": "RS256", "typ": "JWT", "kid": "key-alias"} . {"sub": "username", "prn": "username", "aud": "...", "iss": "...", "iat": 1234, "exp": 1256, "jti": "uuid..."}

Test JWT Token in Postman

Follow the images below to set up Postman to use the JWT token to retrieve an access code from IDCS:

If everything works, you should get an access code back.

Troubleshooting Tip

In case you run into errors, you can get some information from IDCS by turning on Diagnostics as shown in the image below:

 

Now you can do your test and download the log file like the following:

I found the following error in my downloaded csv file when I did not set the "kid" attribute in the JWT header.

Footnote

1. After I published this blog, I was made aware of another blog Creating a JWT Token for an Assertion Grant Type Flow by Olaf Heimburger. In that blog, he provides more detailed information on JWT token creation. 

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha