As a transitional step, this site will temporarily be made Read-Only from July 8th until the new community launch. During this time, you can still search and read articles and discussions.

While the community is read-only, if you have questions or issues requiring TIBCO review/response, please access the new TIBCO Community and select "Ask A Question."

You will need to register or log in or register to engage in the new community.

TIBCO BusinessWorks™ Tutorial: Using JSON Web Tokens (JWT)

Last updated:
8:46am Jun 03, 2021

About this tutorial

Content and duration

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.

Here are some scenarios where JSON Web Tokens are useful:

  • Authentication: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.
  • Information Exchange: JSON Web Tokens are a good way of securely transmitting information between parties, because as they can be signed, for example using public/private key pairs, you can be sure that the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content has not been tampered with.

The tutorial, which should take you 15 to 20 minutes to complete, aims at illustrating how a JWT can be used for Authentication (and Authorisation) purposes when exposing a BusinessWorks REST Service. It also ships with Auth0's Java JWT library (version 3.2.0) packaged as a shared BusinessWorks module for reuse within your own BusinessWorks designs, or as a source of inspiration for you own packaging.

What you will use

  • TIBCO BusinessWorks™
    • Classic from version 6.3
    • Container Edition from version 2.3
    • Cloud Integration with Studio version 1.0.4 V23 2017-02-24 - which is the one used for the attached projects
  • Java 1.8
  • JSON Web Token
  • Auth0's Java JWT Library

Before you begin, prerequisites

We strongly encourage you to go through the basics of JWT and to have experimented the creation of your own JWTs before setting forth.

Moreover, we assume that you have some level of familiarity with one of the above listed versions of TIBCO BusinessWorks™, including:

  • A fully functional development and testing environment,
  • A reasonable command of the exposition of REST Services,
  • Ideally previous experience with BW mappings and JAVA activities.

Finally, you will need an API/REST testing tool for the third step of the tutorial. We can recommend several options:

  • cURL,
  • Postdot Technologie's Postman (used in the illustrations of this tutorial),
  • SmartBear's Ready! API.

Step 1: Producing a test JSON Web Token

In order to have an end-to-end scenario, we will mimick the production of the JWT by a login page. Instead, we will produce the JWT by hand and use it to get access to the server-side resource.

We shall use a nifty website that is practically the Swiss Army knife of JWTs, JWT Builder. Do fill in the first couple of sections as follows (note that Issued At is set to now and Expiration to in 1 year):

JWT Builder Settings

Then move to the fourth section, and enter TIBCOSoftware2017 as the Key (which is a type of shared secret between the producer and the consumer of the token). Different strengths of hash-based algorithms can be applied - and the JWT standard caters to cyphers based on RSA public/private keys instead. We shall keep the default HS256:

JWT Secret

This will produce a signed JWT as illustrated below, that you will want to copy into your clipboard or in a text editor.

JWT

Alternatively, use the following one (which is valid until 2018-05-24T01:51:16.628Z):

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3d3cudGliY28uY29tIiwiaWF0IjoxNDk1NTkwNjU1LCJleHAiOjE1MjcxMjY2NzYsImF1ZCI6Imp3dHNhbXBsZS50aWJjby5jb20iLCJzdWIiOiJlc2Nod2VpdEB0aWJjby5jb20iLCJHaXZlbk5hbWUiOiJFbW1hbnVlbCIsIlN1cm5hbWUiOiJTY2h3ZWl0emVyIiwiQWNjZXNzIjoiQWxsIn0.nXjY7placf8fRqFFX_2gDIo0UkwPa0q3aTZxfj0A-h4

Congratulations, you have generated your first JWT!


Step 2: Importing the attached archive

For the sake of speeding up our exploration, we have attached a TIBCO Business Studio archive to this page. Save it locally on your computer and let us import it into a fresh workspace:

Importing into Business Studio

Select the Existing Studio Projects into Workspace option:

Existing Studio Projects into Workspace

We will pick the projects from the archive file you just downloaded:

Select Archive File

Then please navigate to the location where you placed the file and select it:

Locate archive file

Finally, confirm the import for all contained projects:

Confirm Import

These should appear shortly in your Project Explorer.

Congratulations, you have successfully imported the sample projects and are ready to test it out. But make sure you wait the build process completion before moving to the next step.


Step 3: Testing

We have put together a reusable BusinessWorks process to validate a JSON Web Token sent as authentication to an exposed REST Service. Our sample exposes a simplistic resource on http://localhost:8080/test for GET operations, returning a single String value. Feel free to adjust the path or port as required in your environment, especially if 8080 is a busy port.

Find the details of the associated swagger below:

{
  "swagger" : "2.0",
  "info" : {
    "version" : "1.0",
    "title" : "Test Resource",
    "description" : "Test Resource"
  },
  "host" : "localhost:8080",
  "basePath" : "/",
  "schemes" : [ "http" ],
  "paths" : {
    "/test" : {
      "get" : {
        "description" : "",
        "operationId" : "get-test",
        "consumes" : [ "application/json" ],
        "produces" : [ "application/json" ],
        "parameters" : [ ],
        "responses" : {
          "200" : {
            "description" : "a string to be returned",
            "schema" : {
              "type" : "string"
            }
          }
        }
      }
    }
  },
  "definitions" : { }
}

The service implementation is equally simplistic, as illustrated below:

  • Validate the JSON Web Token against the current date and specific issuer, audience, and subject values which must be a perfect match with those of the token,
  • Log the validation status as well as the private claims,
  • Return OK if validated, KO otherwise.

Process Implementation

As you know (or may have learned when reviewing JWT), the tokens are usually send as an HTTP Authorization header of the Bearer type.

Run the JWT.Test application locally, and let us perform a few invokations (all illustrations with Postman).

No authorisation token

We first perform the GET operation on http://localhost:8080/test with only an Accept header:

Accept: application/json,text/html;q=0.9,application/xhtml+xml;q=0.8,*/*;q=0.7

Test without authentication header

As you can see, the authentication fails.

Correct authorisation token

Let us reperform the test, but this time we shall add the correct Authorization header (feel free to replace with your own token details):

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3d3cudGliY28uY29tIiwiaWF0IjoxNDk1NTkwNjU1LCJleHAiOjE1MjcxMjY2NzYsImF1ZCI6Imp3dHNhbXBsZS50aWJjby5jb20iLCJzdWIiOiJlc2Nod2VpdEB0aWJjby5jb20iLCJHaXZlbk5hbWUiOiJFbW1hbnVlbCIsIlN1cm5hbWUiOiJTY2h3ZWl0emVyIiwiQWNjZXNzIjoiQWxsIn0.nXjY7placf8fRqFFX_2gDIo0UkwPa0q3aTZxfj0A-h4

Test with correct token

This time, the token is validated.

Notice the content of the log. It confirms the validation status, and lists the private claims of the token as a comma-separated list of KeyValues:

15:15:23.641 INFO  [bwEngThread:In-Memory Process Worker-2] c.t.b.p.g.Log.JWT.Test.module.Log - Validation true. AccessAll, GivenNameEmmanuel, SurnameSchweitzer

The token subject or any of its private claims could potentially be used to make decisions when it comes to authorisation.

Tampered-with authorisation token

Replace a few characters of the token, or add them: the token will be refused. You can also try to build a token with a different key, or with characteristics that do not exactly match our expectations: the token will be refused as well.

Tampered authorisation token

Congratulations, you have tested the basic principles of JWT in BusinessWorks!


Step 4: Review the JWT.Validate shared module

Note that this module is by no means the ultimate implementation, and should only be considered as an illustration. Feel free to suggest or share improvements!

JWT.Validate.module is a wrapper around auth0's java-jwt library. It consists in a reusable sub-process, a Java class to perform the bulk of the validation, and all the required Java libraries (java-jwt, jackson-core, jackson-annotations, jackson-databind, and commons-codec).

jwt.module.ValidateJWT sub-process

The sub-process is simply a JavaInvoke operation followed by a transformation of its results into XML usable by the sub-process consumer:

jwt.module.ValidateJWT

Its input signature is a follows:

<xsd:element name="Request">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element maxOccurs="1" minOccurs="1" name="token" type="xsd:string"/>
      <xsd:element maxOccurs="1" minOccurs="1" name="secret" type="xsd:string"/>
      <xsd:element maxOccurs="1" minOccurs="1" name="issuer" type="xsd:string"/>
      <xsd:element maxOccurs="1" minOccurs="1" name="audience" type="xsd:string"/>
      <xsd:element maxOccurs="1" minOccurs="1" name="subject" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

and its output is as follows:

<xsd:element name="Response">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element maxOccurs="1" minOccurs="1" name="validated" type="xsd:boolean"/>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="claims" type="tns:Claim"/
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

<xsd:complexType name="Claim">
  <xsd:sequence>
    <xsd:element maxOccurs="1" minOccurs="1" name="key" type="xsd:string"/>
    <xsd:element maxOccurs="1" minOccurs="0" name="value" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

Other approaches could be considered, e.g. having the InvokeJava operation return the decoded token as a JSON string and leverage BusinessWorks JSON operations.

jwt.tibco.com.Validator class

The Validator class is a Java Bean easily consumed by BusinessWorks. It leverages java-jwt to decode the token, verify that it has not been tampered with using the secret/key, and perform validation checks (issuer, audience, subject, and dates). It then extracts the non-public claims, which are stored as jwt.tibco.com.Claim entries.

package jwt.tibco.com;

import java.util.Date;
import java.util.Vector;
import java.util.Map;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;


public class Validator {	
	private static String JWT_Type = "JWT";
	
	protected boolean validated;
	protected Object[] claims;
	
	public Validator() {
		setValidated(false);
		setClaims(null);
	}
	
	public void validate(String token, String secret, String issuer, String audience, String subject) {
		DecodedJWT jwt = null;
		setValidated(false);
		
		if (token == null || secret == null || issuer == null || audience == null || subject == null)
			return;
		
		try {
			jwt = JWT.require(Algorithm.HMAC256(secret.getBytes())).build().verify(token);
		} catch (JWTVerificationException e) {
			return;
		}
		
		if (jwt == null || jwt.getType() == null || !jwt.getType().contentEquals(JWT_Type))
			return;
		
		if (!jwt.getIssuer().contentEquals(issuer) ||
			!jwt.getAudience().contains(audience) ||
			!jwt.getSubject().contentEquals(subject))
			return;
		
		Date now = new Date();
		
		if ((jwt.getNotBefore() != null && jwt.getNotBefore().after(now)) ||
			(jwt.getExpiresAt() != null && jwt.getExpiresAt().before(now)))
			return;
		
		setValidated(true);

		Map<String, Claim> claimsMap = jwt.getClaims();
		Vector<jwt.tibco.com.Claim> claimsVector = new Vector<jwt.tibco.com.Claim>();
		
		if (claimsMap != null) {
			for (Map.Entry<String, Claim> entry : claimsMap.entrySet()) {
				String key = entry.getKey();
				if (key != null && !key.matches("aud|sub|iss|exp|iat")) {					
					claimsVector.add(new jwt.tibco.com.Claim(key, entry.getValue().asString()));
				}
			}		
		}

		setClaims(claimsVector.isEmpty() ? null : claimsVector.toArray());
	}

	public boolean isValidated() { return validated; }
	public void setValidated(boolean val) { validated = val; }

	public Object[] getClaims() { return claims; }
	public void setClaims(Object[] val) { claims = (val == null ? new Object[0] : val); }
}

jwt.tibco.com.Claim class

The Claim class is a very simple JavaBean to hold Claims.

package jwt.tibco.com;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Claim implements Serializable {
	private static final long serialVersionUID = 7960567494553263091L;
	
	private String key;
	private String value;
	
	public Claim() { setKey(""); setValue(""); }
	public Claim(String key, String value) { setKey(key); setValue(value); }

	public String getKey() { return this.key; }
	public void setKey(String key) { this.key = key; }
	
	public String getValue() { return this.value; }
	public void setValue(String value) { this.value = value; }

	private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException {
		//always perform the default de-serialization first
		aInputStream.defaultReadObject();
	}

	private void writeObject(ObjectOutputStream aOutputStream) throws IOException {
		//perform the default serialization for all non-transient, non-static fields
		aOutputStream.defaultWriteObject();
	}
}

Using the module

Using the module is just a matter of referencing it your module's dependencies and calling the JWT.Validate.module.jwt.module.ValidateJWT subprocess and passing the appropriate input parameters:

Using the module

Then, make use of the output parameters:

Output parameters


Conclusion

You have now explored the basics of JWTs and how they can be applied to your BusinessWorks REST Services, both for authentication and authorisation, once their consumers have identified through separate means and have obtained the JSON Web Token proving their credentials.

Sit back and relax! And feel free to suggest and share improvements.


Contributors: Emmanuel Schweitzer

Attachments

AttachmentSize
Package icon bw-jwt-validate-20170524.zip1.66 MB

Feedback (1)

Hi Emmanuel,

Thanks for the explanation. I am trying to create JWT and facing issues with keyprovider and algorithm. Do you have a sample java class which can be used as reference?

Thanks

Venkata Nimmakayala

US Bank

clastibcoteam 12:56pm May. 25, 2021