Overview
This tutorial shows you how to authenticate to the Issuing API using Java by generating signed JSON Web Tokens (JWTs).
In This Recipe
- Add Dependencies
- Create AccessTokenSigner
- Usage - GET Request
- 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