Skip to main content
Version: ADONIS 15/ADOIT 16/ADOGRC 12

JSON Web Token Authentication

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. Authentiation using JWT helps prevent unauthorized usage of the API and replay and other abuse of requests.

For prerequisites to use JWT Authentication, see the REST API section in the administration manual.

Requests will always have to authenticate. Read more about Authenticated Connection here.

Procedure

  1. When issuing a REST request, the client creates a JWT which is submitted as part of the request in the Authorization header (as Bearer token).
  2. The server verifies the token based on the proper content structure, correct signature and the token expiration time.
  3. When the JWT passes these checks, the JWT will be validated based on the ADOxx JWT REST configurations.
  4. Once the JWT token is accepted by the JWT REST configuration, it will use the claim defined in the relevant configuration's user mapping as username. The REST request will be executed in the context of this user.

Try it out

JWT can be configured and generally activated in the Admin Page, enabled for the REST API in the Administration Toolkit and then a token can be generated based on the configured mechanisms.

A possible JWT configuration in the Admin Page can be seen below. In this example, only JWTs where the claim 'iss' has the value 'http://issuer.boc-group.com' are accepted. For the signature validation, the HS256 algorithm is used and a secret is configured. If an incoming JWT passes the validations, the user name will be taken from the JWT's claim 'sub'.

The shared secret for the signature validation can be generated programmatically (see further below), or on pages like Security Key Generator (Choose e.g. 256bit or higher and activate the option Hex).

Claims Validation Example
{
"claims_validation": {
"iss": {
"type": "string",
"value": "http://issuer-boc-group.com"
}
},
"index": -1,
"name": "My Test JWT",
"signature_validation": {
"HMAC_shared_secret": "6251655468576D5A7134743777217A25432A462D4A614E635266556A586E3272"
},
"user_mapping": {
"claim": "sub"
}
}

A JWT that matches this configuration can be generated programmatically (see further below), or on pages like JWT.IO.

String sIssuer = "http://issuer.boc-group.com";
String sSubject = "username";
String sSecret = "6251655468576D5A7134743777217A25432A462D4A614E635266556A586E3272";
long nTTL = 180000; // 30 Minutes time to live

Programmatic Generation of an HMAC Secret

The following snippet shows how an HMAC Secret can be generated using Java. For this, the library jjwt.jar (https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt/) is used.

Click to view the code!

Source Code

  public static String generateHMACSecret ()
{
// Generating a safe HS256 Secret key
SecretKey aKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
return Encoders.BASE64.encode(aKey.getEncoded());
}

Programmatic Generation of a JWT

The following snippet shows how a JWT using the HS256 algorithm can be generated. For this, the libraries jjwt.jar (https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt) and Jackson (https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind) are used.

Click to view the code!

Source Code

public class JWTUtil
{
public static String createJWTWithClaims (String sSecret, String sUserName, String sForename, String sSurname, String sIssuer, long nTTL)
{
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm aSignatureAlgorithm = SignatureAlgorithm.HS256;

long nNow = System.currentTimeMillis();

// Sign our JWT with the secret
byte[] aAPIKeySecretBytes = DatatypeConverter.parseBase64Binary (sSecret);
Key aSigningKey = new SecretKeySpec (aAPIKeySecretBytes, aSignatureAlgorithm.getJcaName());

long nExp = nNow + nTTL;

Map<String, Object> aClaims = new HashMap<String, Object>();
aClaims.put ("name", sForename+ " " + sSurname);
JwtBuilder aBuilder = Jwts.builder ()
.setClaims (aClaims)
.setIssuedAt (new Date (nNow))
.setSubject (sUserName)
.setIssuer (sIssuer)
.setExpiration(new Date (nExp))
.signWith (aSigningKey, aSignatureAlgorithm);


//Builds the JWT and serializes it to a compact, URL-safe string
return aBuilder.compact();
}

public static String createJWTWithPayload (String sSecret, String sUserName, String sForename, String sSurname, String sIssuer, long nTTL)
{
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm aSignatureAlgorithm = SignatureAlgorithm.HS256;

long nNow = System.currentTimeMillis();

//We will sign our JWT with our ApiKey secret
byte[] aAPIKeySecretBytes = DatatypeConverter.parseBase64Binary (sSecret);
Key aSigningKey = new SecretKeySpec (aAPIKeySecretBytes, aSignatureAlgorithm.getJcaName());

long nExp = nNow + nTTL;

ObjectNode aPayload = new ObjectMapper().createObjectNode();
aPayload.put ("sub", sUserName);
aPayload.put ("name", sForename+" " + sSurname);
// iat (Issued At Time) and exp has to be passed as seconds in the payload
aPayload.put ("iat", nNow/1000);
aPayload.put ("exp", nExp/1000);
aPayload.put ("iss", sIssuer);

//Let's set the JWT Claims
JwtBuilder aBuilder = Jwts.builder()
.setPayload(aPayload.toString())
.signWith (aSigningKey, aSignatureAlgorithm);


//Builds the JWT and serializes it to a compact, URL-safe string
return aBuilder.compact();
}
}

The following snippet shows how the JWTUtil can be used to create a JWT based on data that would match the JWT configuration from further above and how this JWT can then be added to a REST request:

String sPath = "https://<SERVER_NAME>:<PORT>/<PRODUCT><VERSION>/rest/myEndpoint";

String sUsername = "username";

String sForename = "forename";

String sSurname = "surname";

String sIssuer = "http://issuer.boc-group.com";

String sSecret = "6251655468576D5A7134743777217A25432A462D4A614E635266556A586E3272";

long nTTL = 180000; // 30 Minutes time to live

HttpGet aMethod = new HttpGet (sPath);

String sJWT = JWTUtil.createJWTWithClaims (sSecret, sUsername, sForename, sSurname, sIssuer, nTTL);

aMethod.addHeader ("Authorization", "Bearer " + sJWT);