Access to the Issuing API is authenticated using an API access key combined with cryptographically signed API requests.
Overview
To authenticate your implementation against the Issuing API, you must complete three steps:
Generate an RSA key pair - Create a public/private RSA key pair in PEM format (minimum 2048 bits)
Register your public key - Email your public key and IP whitelist address to your implementation manager. In return, you’ll receive an Access Key (UUID). In the future, this can be done via the UTGL Developer Portal.
Sign your requests - Use your access key and private key to generate signed JWT tokens for each API request
Authentication Flow
The following diagram illustrates the complete authentication flow from initial setup to making authenticated API requests:
Step 1: Generate RSA Key Pair
Generate a public/private RSA key pair using OpenSSL or your preferred tool.
Security Warning: Ensure your private key is stored in a secure, encrypted location and never expose it to anyone.Gaining access to your access key + private key essentially grants full access to your account.
openssl req -new -newkey rsa:4096 -nodes \
-keyout utgl-access.private -out utgl-access.csr
Step 2: Create Bearer Token
Each API request requires a Bearer token in the Authorization header. The token is a signed JWT that includes request-specific claims.
Process Overview
Create the JWT header and payload - Include required claims (URI, method, body hash, etc.)
Sign the JWT - Use your RSA private key with the RS256 algorithm
Add to request header - Include the signed token as Authorization: Bearer <token>
The Issuing API verifies the JWT signature against the provided claims and validates the URI, method, and request body against the claims.
JWT Creation Process
If token verification fails, the API returns HTTP 401 Unauthorized with error code INVALID_SIGNATURE.
JWT Token Specification
The JWT token must be created according to the following specification.
The JWT header must contain:
Field Value Description algRS256Signature algorithm typJWTToken type
Payload (Claims)
The JWT payload must include the following claims:
Claim Required Description Example subYes Your Access Key (UUID) 899a7a89-bb6b-4d43-a702-c6aa45dd89cfiatYes Issued at time (Unix timestamp in seconds) 1668849961expYes Expiration time (Unix timestamp in seconds). Must be less than iat + 30 seconds 1668849991bodyConditional Hex-encoded SHA-256 hash of the raw HTTP request body. Optional for GET requests (empty body) 93a23971a914e5eacbf0a8d25154cda309c3c1c72fbb9914d47c60f3cb681588uriYes The URI part of the request, including query parameters /v1/transactions?filter=123methodYes The HTTP method of the request GET, POST, PUT, DELETE
Signing
The JWT must be signed using your RSA Private Key with the RS256 algorithm.
Implementation Examples: See our language-specific guides for complete implementation examples:
Example: GET Request
The following example demonstrates how to create a JWT for a GET request to /ping.
Test Credentials
6e33a078-99ed-4aa1-8e67-b0e19e9475fd
JWT Components
Header
Claims
Signature
Complete Bearer Token
{
"alg" : "RS256" ,
"typ" : "JWT"
}
Example: POST Request
The following example demonstrates how to create a JWT for a POST request with a request body.
Request Details
Endpoint: POST /ping
Request Body: {"hello":"world"}
Access ID: ed63e5a1-3e8e-4b63-96b5-b711f91bc2dd
JWT Components
Header
Request Body
Claims
Signature
Complete Bearer Token
{
"alg" : "RS256" ,
"typ" : "JWT"
}
Important: The body claim contains the hex-encoded SHA-256 hash of the raw request body. For POST requests, you must include this hash. The exact string representation of the body must match between signing and sending.
Common Issues & Troubleshooting
Token Expiration
JWT tokens expire after 30 seconds. Generate a fresh token for each API request.
Body Hash Mismatch
Ensure the request body used for signing exactly matches the body sent in the HTTP request. Common issues:
Trailing whitespace differences
JSON formatting differences (spaces, newlines)
Character encoding mismatches
Invalid Signature Errors
If you receive INVALID_SIGNATURE errors:
Verify your private key is correct and properly formatted
Ensure you’re using RS256 algorithm
Check that all required claims are present
Verify the uri includes query parameters if present
Confirm the body hash matches the actual request body (for POST requests)
Next Steps