JWT Authentication Guide in JAVA

Written By mvishwakarma (Administrator)

Updated at September 10th, 2025

1. Overview

This document provides a detailed explanation of how to generate a Client Access Token for authenticating Annex Cloud public API calls.
The token is a JSON Web Token (JWT) signed using the HMAC-SHA256 algorithm to ensure:

  • Data integrity – the request cannot be altered without detection.
  • Authentication – confirming the request comes from a trusted client.

This guide covers:

  • JWT structure and components
  • How to generate the HMAC value for both POST/PATCH and GET requests
  • Step-by-step Java implementation example
  • Required HTTP headers when calling Annex Cloud APIs
 Library used

<dependency>

      <groupId>io.jsonwebtoken</groupId>

      <artifactId>jjwt</artifactId>

      <version>0.9.1</version>

    </dependency>

 

<dependency>

      <groupId>org.json</groupId>

      <artifactId>json</artifactId>

      <version>20230227</version>

    </dependency>

<dependency>

      <groupId>javax.xml.bind</groupId>

      <artifactId>jaxb-api</artifactId>

      <version>2.3.1</version>

    </dependency>

2. Understanding JWT

A JWT consists of three parts, each Base64URL-encoded and separated by a period (.):

<base64url-encoded header>.<base64url-encoded payload>.<base64url-encoded signature> 

2.1. JWT Components

a. Header

Defines the type of token and the signing algorithm used.

{ 
  "alg": "HS256", 
  "typ": "JWT" 
} 
  • alg: Signing algorithm (HS256 = HMAC with SHA-256)
  • typ: Token type (JWT)

b. Payload

Contains claims and authentication-related data.

Mandatory claims:

  • sub – Client identifier (shared during integration)
  • exp – Expiration time (in Unix timestamp seconds; ensures the token is valid only for a set duration)
  • site_id – Your Annex Cloud site ID
  • hmac – Base64-encoded HMAC-SHA256 signature of either:
    • The request JSON payload (POST/PATCH requests), or
    • The query parameter value (GET requests)

Example Payload:

{ 
  "sub": "socialannextestsite", 
  "exp": 1568674228, 
  "site_id": "yoursiteid", 
  "hmac": "generated_hmac_here" 
} 

c. Signature

The JWT signature is created as follows:

HMACSHA256( base64url(header) + "." + base64url(payload), shared_secret ) 

Where:

  • base64url(header) - Base64URL-encoded JSON header
  • base64url(payload) - Base64URL-encoded JSON payload
  • shared_secret - Your Annex Cloud shared secret key

3. HMAC Generation Rules

For POST / PATCH Requests

  1. Take the exact JSON payload you will send in the API request.
  2. Base64-encode the payload (standard Base64, not Base64URL).
  3. Generate the HMAC using SHA-256 with your shared secret key.
  4. Base64-encode the HMAC output.
  5. Insert this Base64-encoded HMAC into the hmac field in the JWT payload.

For GET Requests

  1. Take the query parameter value you will send.
  2. Convert it to JSON format (enclose it in quotes).
  3. Base64-encode this JSON string.
  4. Generate the HMAC using SHA-256 with your shared secret key.
  5. Base64-encode the HMAC output.
  6. Insert this Base64-encoded HMAC into the hmac field in the JWT payload.

Important: The payload or parameter used to generate the HMAC must exactly match what is sent in the API request. Even a single space difference will cause authentication failure.

4. Java Implementation Example

package org.annexcloud.utility; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.util.Base64; 
import java.util.HashMap; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.concurrent.TimeUnit; 
import javax.crypto.Mac; 
import javax.crypto.spec.SecretKeySpec; 
import com.google.gson.Gson; 
import io.jsonwebtoken.Jwts; 
import io.jsonwebtoken.SignatureAlgorithm; 
public class CreateToken { 
    private static final String SECRET_KEY = "secretKey"; 
    private static final String SITE_ID = "siteId"; 
    private static final String HMAC_ALGORITHM = "HmacSHA256"; 
    public static String getToken(String payload, HashMap<String, String> envDetails) { 
        try { 
            // Generate HMAC 
            byte[] hmac = generateHMAC(payload, envDetails.get(SECRET_KEY)); 
            // Prepare JWT claims 
            Map<String, Object> tokenParams = setTokenParams(hmac, envDetails); 
            String jsonTokenObj = new Gson().toJson(tokenParams, LinkedHashMap.class); 
            // Sign JWT 
            String annexKey = Base64.getEncoder().encodeToString(envDetails.get(SECRET_KEY).getBytes()); 
            return "Bearer " + Jwts.builder() 
                    .setPayload(jsonTokenObj) 
                    .signWith(SignatureAlgorithm.HS256, annexKey) 
                    .compact(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
            return null; 
        } 
    } 
    private static byte[] generateHMAC(String payload, String secretKey) 
            throws NoSuchAlgorithmException, InvalidKeyException { 
        byte[] encodedPayload = Base64.getEncoder().encode(payload.getBytes()); 
        Mac sha256_HMAC = Mac.getInstance(HMAC_ALGORITHM); 
        SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(), HMAC_ALGORITHM); 
        sha256_HMAC.init(secret_key); 
        return Base64.getEncoder().encode(sha256_HMAC.doFinal(encodedPayload)); 
    } 
    private static Map<String, Object> setTokenParams(byte[] hMacEncodedBytes, HashMap<String, String> envDetails) { 
        Map<String, Object> tokenParams = new LinkedHashMap<>(); 
        tokenParams.put("sub", "socialannextestsite"); 
        tokenParams.put("exp", String.valueOf(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(3600))); 
        tokenParams.put("site_id", envDetails.get(SITE_ID)); 
        tokenParams.put("hmac", new String(hMacEncodedBytes)); 
        return tokenParams; 
    } 
} 

5. Required HTTP Headers for API Calls

When sending requests to Annex Cloud APIs, you must include the following headers:

Header Name

 

Value

 

Description

 

Authorization

Bearer <JWT_access_token>

The JWT generated using the above process

X-AnnexCloud-Site

<site_id>

Your Annex Cloud site ID

Content-Type

application/json

Request body format

Example
POST /api/3.0/points HTTP/1.1 
Authorization: Bearer eyJhbGciOiJIUzI1NiIs... 
X-AnnexCloud-Site: yoursiteid 
Content-Type: application/json