Skip to main content

Overview

This tutorial shows you how to authenticate to the Issuing API using Java by generating signed JSON Web Tokens (JWTs).

In This Recipe

  1. Add Dependencies
  2. Create AccessTokenSigner
  3. Usage - GET Request
  4. Usage - POST Request

Prerequisites

  • Java 8 or higher
  • Your Issuing API credentials (Access Key and RSA key pair)
  • Maven or Gradle for dependency management

Step 1: Add Dependencies

Add these dependencies to your pom.xml:
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>

Step 2: Create AccessTokenSigner

Create a utility class to handle JWT signing with SHA256 body hashing:
package com.example;

import java.time.Instant;
import java.util.Date;
import java.util.Base64;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.digest.DigestUtils;

public class AccessTokenSigner {
  public static String signJWT(
      String privateKey, 
      String accessKey, 
      String uri, 
      String method, 
      String requestBody) throws Exception {
    
    // Private key should be Base64-encoded with no headers/footers/newlines
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(
        Base64.getDecoder().decode(privateKey)
    );
    PrivateKey privKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
    
    Instant now = Instant.now();
    Date issuedAt = Date.from(now);
    Date expiration = Date.from(now.plusSeconds(30)); // 30 second expiration
    
    // Hash request body with SHA256
    String hashedBody = DigestUtils.sha256Hex(requestBody);
    
    String jws = Jwts.builder()
        .setHeaderParam("typ", "JWT")
        .setSubject(accessKey)
        .setExpiration(expiration)
        .setIssuedAt(issuedAt)
        .claim("uri", uri)
        .claim("method", method)
        .claim("body", hashedBody)
        .signWith(privKey, SignatureAlgorithm.RS256)
        .compact();
    
    return jws;
  }
}

Important Notes:

  • Request body is hashed with SHA256 before signing
  • 30 second expiration for security
  • Private key format: Base64-encoded PKCS8, no PEM headers/footers
  • Empty body: Use empty string "" for GET requests

Step 3: Usage - GET Request

Make a simple GET request to test connectivity:
import com.nimbusds.jose.JOSEException;

public class ExampleAPI {
    public static void main(String[] args) {
        String privateKey = "<RSA private key>"; // Replace with actual private key
        String accessKey = "<access key>"; // Replace with actual access key
        String uri = "/v1/ping";
        String method = "GET";
        String requestBody = "";
        try {
            String jwt = AccessTokenSigner.signJWT(privateKey, accessKey, uri, method, requestBody);
            // Use the JWT in the Authorization header of the HTTP request
            String authorizationHeader = "Bearer " + jwt;
            // Make the HTTP request to the API endpoint
            // ...
        } catch (JOSEException e) {
            // Handle JOSEException
        }
    }
}
This example shows JWT generation only. Use your preferred HTTP client (Apache HttpClient, OkHttp, Spring RestTemplate, etc.) to make the actual API request with the authorizationHeader.

Step 4: Usage - POST Request

Make a POST request with a request body:
import com.nimbusds.jose.JOSEException;

public class ExampleAPI {
    public static void main(String[] args) {
        String privateKey = "<RSA private key>"; // Replace with actual private key
        String accessKey = "<access key>"; // Replace with actual access key
        String uri = "/v1/ping";
        String method = "POST";
        String requestBody = "{'message': 'Hello, world!'}"; // Replace with actual request body

        try {
            String jwt = AccessTokenSigner.signJWT(privateKey, accessKey, uri, method, requestBody);
            // Use the JWT in the Authorization header of the HTTP request
            String authorizationHeader = "Bearer " + jwt;
            // Make the HTTP request to the API endpoint
            // ...
        } catch (JOSEException e) {
            // Handle JOSEException
        }
    }
}

Common Pitfalls

Body Hashing is Critical! The AccessTokenSigner automatically hashes the request body with SHA256 before including it in the JWT claims. Make sure you pass the exact same request body to both signJWT() and your HTTP client.
Token Expiration: JWT tokens expire after 30 seconds. Generate a fresh token for each API request to avoid authentication errors.

Next Steps