Skip to content

JWT Tokens

JWT (JSON Web Tokens) provide time-bound authentication for browser-based applications and server-to-server communication. Tokens are obtained via the login endpoint and refreshed as needed.

Obtaining a Token

Via Email/Password Login

POST to /api/v1/auth/login with email and password:

Terminal window
curl -X POST https://api.truthvouch.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"grantType": "password",
"email": "user@company.com",
"password": "SecurePassword123!"
}'

Response:

{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "rt_1234567890abcdef",
"expiresIn": 3600,
"tokenType": "Bearer"
}

Token Structure

Each JWT contains the following claims:

{
"sub": "user-uuid",
"email": "user@company.com",
"client_id": "org-uuid",
"role": "admin",
"subscription_tier": "professional",
"iat": 1678886400,
"exp": 1678890000
}

Claims:

  • sub — Unique user ID (use for audit trails)
  • email — User email address
  • client_id — Organization / account ID (all API requests filtered by this)
  • role — User role: admin, developer, viewer
  • subscription_tier — Plan level: sandbox, professional, enterprise
  • iat — Issued at (Unix timestamp)
  • exp — Expires at (Unix timestamp)

Using JWT Tokens

Setting Authorization Header

Include the access token in the Authorization header:

Terminal window
curl -X GET https://api.truthvouch.com/api/v1/governance/alerts \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

In Python SDK

from truthvouch import TruthVouchClient
client = TruthVouchClient(
gateway_url="https://gateway.truthvouch.com",
jwt_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
)

In TypeScript SDK

import TruthVouch from '@truthvouch/sdk';
const tv = new TruthVouch({
jwtToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
});

In Browser (JavaScript)

const response = await fetch('https://api.truthvouch.com/api/v1/governance/alerts', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + accessToken
}
});
const data = await response.json();

Token Lifetime

  • Access Token: 1 hour (3600 seconds)
  • Refresh Token: 30 days (2,592,000 seconds)

After an access token expires, use the refresh token to obtain a new one without re-authenticating.

Refreshing Tokens

When your access token is about to expire (check the exp claim), refresh it using the refresh token:

Terminal window
curl -X POST https://api.truthvouch.com/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"grantType": "refresh_token",
"refreshToken": "rt_1234567890abcdef"
}'

Response:

{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "rt_9876543210fedcba",
"expiresIn": 3600,
"tokenType": "Bearer"
}

Refresh Token Rotation

For security, the refresh token is rotated on each refresh. Always use the new refresh token from the response.

Handling Token Expiration

Check Before Expiry

Decode the JWT to check the exp claim (Unix timestamp):

import json
import base64
from datetime import datetime
def is_token_expired(token):
parts = token.split('.')
payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
expires_at = payload['exp']
return datetime.utcnow().timestamp() > expires_at
# Refresh if less than 5 minutes remaining
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
if is_token_expired(token):
# Call refresh endpoint

Handle 401 Responses

If a request returns 401 Unauthorized:

  1. The token has expired or been revoked
  2. Use the refresh token to obtain a new access token
  3. Retry the original request
  4. If refresh also fails, re-authenticate (ask user to login)

Security Best Practices

1. Store Tokens Securely

In Browser:

  • Use httpOnly cookies (server sets via Set-Cookie header)
  • Never store in localStorage (vulnerable to XSS)

In Server/App:

  • Store in memory or secure session storage
  • Never log tokens
  • Never commit tokens to source control

2. Use HTTPS Only

Always communicate over HTTPS to prevent token interception.

3. Never Share Tokens

  • Tokens are user-specific
  • Do not embed tokens in URLs
  • Do not share via email or chat

4. Rotate Refresh Tokens

Always use the new refresh token from the response. Old refresh tokens should be discarded.

5. Handle Expiration Gracefully

Refresh tokens before they expire to avoid interrupting user workflows.

6. Validate Token Claims

When receiving a token from a client, verify:

  • Signature is valid (use your public key)
  • exp claim is in the future
  • client_id matches your expected organization ID

Common Errors

”Invalid credentials”

Email or password is incorrect.

Fix: Verify credentials and try again.

”401 Unauthorized”

Access token is missing, invalid, or expired.

Fix:

  1. Check that the token is in the Authorization: Bearer header
  2. Check the token hasn’t expired (decode and check exp claim)
  3. If expired, refresh using the refresh token
  4. If refresh fails, re-authenticate

”403 Forbidden”

Token is valid but the user doesn’t have permission for this operation.

Fix: Check the user’s role and subscription tier in the token claims.

”Refresh token expired”

Refresh tokens are only valid for 30 days.

Fix: Re-authenticate by calling /api/v1/auth/login again.


Next Steps