The JWT implementation provides comprehensive functionality for creating, signing, verifying, and decoding JSON Web Tokens (JWT) in NetLinx applications. JSON Web Tokens are an open, industry-standard method for representing claims securely between two parties.
This library implements:
- RFC 7519 - JSON Web Token (JWT)
- RFC 7515 - JSON Web Signature (JWS)
Key features:
- Create JWT tokens with custom headers and payloads
- Sign tokens using HMAC algorithms (HS256, HS384, HS512)
- Verify token signatures
- Decode and extract token components
- Time-based validation (exp, nbf, iat claims)
- Comprehensive error handling
Dependencies:
- NAVFoundation.Core
- NAVFoundation.Encoding.Base64Url
- NAVFoundation.Cryptography.Hmac
- NAVFoundation.StringUtils
The library uses domain-specific buffer size constants that can be configured at compile time:
NAV_JWT_MAX_TOKEN_LENGTH(default: 4096 bytes) - Maximum length for complete JWT token stringsNAV_JWT_MAX_COMPONENT_LENGTH(default: 2048 bytes) - Maximum length for individual token components (header, payload, signature)NAV_JWT_MAX_JSON_LENGTH(default: 2048 bytes) - Maximum length for decoded JSON header/payload strings
These can be overridden before including the library:
#DEFINE NAV_JWT_MAX_TOKEN_LENGTH 8192
#include 'NAVFoundation.Jwt.axi'JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure.
A JWT consists of three parts separated by dots (.):
header.payload.signature
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U
-
Header - Contains metadata about the token (algorithm, type)
{ "alg": "HS256", "typ": "JWT" } -
Payload - Contains the claims (data)
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 } -
Signature - Ensures the token hasn't been tampered with
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
JWT is commonly used for:
- API Authentication - Stateless authentication for REST APIs
- Single Sign-On (SSO) - Cross-domain authentication
- Information Exchange - Securely transmitting information between parties
- Authorization - Granting access to resources
- Session Management - Alternative to server-side sessions
- Third-party Integration - Authentication with external services (OAuth, OpenID Connect)
- Control System Integration - Secure communication between AMX systems and cloud services
define_function char NAVJwtCreate(char headerJson[], char payloadJson[], char secret[], char token[])Description: Creates a complete JWT token from header and payload JSON strings.
Parameters:
headerJson- Header JSON string (or empty string for default HS256 header)payloadJson- Payload JSON string containing claimssecret- Secret key for HMAC signingtoken- Output: Complete JWT token string (header.payload.signature)
Returns: true if successful, false otherwise
Example:
stack_var char token[NAV_JWT_MAX_TOKEN_LENGTH]
stack_var char payload[500]
payload = '{"sub":"user123","name":"John Doe","iat":1516239022}'
if (NAVJwtCreate('', payload, 'mySecretKey', token)) {
// Token created successfully
}
// Use empty string for headerJson to get default HS256 headerdefine_function char NAVJwtVerify(char token[], char secret[])Description: Verifies the signature of a JWT token.
Parameters:
token- Complete JWT token stringsecret- Secret key used for signing
Returns: true if valid, false otherwise
Example:
if (NAVJwtVerify(token, 'mySecretKey')) {
send_string 0, "'Token is valid'"
} else {
send_string 0, "'Token verification failed'"
}define_function char NAVJwtDecode(char token[], _NAVJwtToken jwtToken)Description: Decodes a JWT token into a _NAVJwtToken structure with all components.
Parameters:
token- Complete JWT token stringjwtToken- Output structure containing decoded components
Returns: true if successful, false otherwise (errorCode field set in struct)
Example:
stack_var _NAVJwtToken jwtToken
if (NAVJwtDecode(token, jwtToken)) {
send_string 0, "'Header: ', jwtToken.headerJson"
send_string 0, "'Payload: ', jwtToken.payloadJson"
send_string 0, "'Algorithm: ', jwtToken.headerParsed.alg"
} else {
send_string 0, "'Decode failed: ', NAVJwtGetErrorMessage(jwtToken.errorCode)"
}define_function char NAVJwtVerifyAndDecode(char token[], char secret[], _NAVJwtToken jwtToken)Description: Verifies and decodes a JWT token in one operation.
Parameters:
token- Complete JWT token stringsecret- Secret key used for signingjwtToken- Output structure containing decoded components
Returns: true if valid, false otherwise (errorCode field set in struct)
Example:
stack_var _NAVJwtToken jwtToken
if (NAVJwtVerifyAndDecode(token, 'mySecretKey', jwtToken)) {
send_string 0, "'Valid token from: ', jwtToken.payloadJson"
} else {
send_string 0, "'Error: ', NAVJwtGetErrorMessage(jwtToken.errorCode)"
}define_function char NAVJwtGetHeader(char token[], char header[])Description: Extracts and decodes the header from a JWT token.
Parameters:
token- Complete JWT token stringheader- Output: Decoded header JSON string
Returns: true if successful, false otherwise
define_function char NAVJwtGetPayload(char token[], char payload[])Description: Extracts and decodes the payload from a JWT token.
Parameters:
token- Complete JWT token stringpayload- Output: Decoded payload JSON string
Returns: true if successful, false otherwise
define_function char NAVJwtGetSignature(char token[], char signature[])Description: Extracts the signature component from a JWT token (Base64Url encoded).
Parameters:
token- Complete JWT token stringsignature- Output: Base64Url encoded signature
Returns: true if successful, false otherwise
define_function char[NAV_JWT_MAX_JSON_LENGTH] NAVJwtCreateHeader(char algorithm[], char tokenType[])Description: Creates a standard JWT header JSON string.
Parameters:
algorithm- Signing algorithm (useNAV_JWT_ALG_HS256,NAV_JWT_ALG_HS384, orNAV_JWT_ALG_HS512)tokenType- Token type (default:NAV_JWT_TYP_JWT)
Returns: JSON string representing the JWT header
Example:
stack_var char header[NAV_JWT_MAX_JSON_LENGTH]
header = NAVJwtCreateHeader(NAV_JWT_ALG_HS256, NAV_JWT_TYP_JWT)
// Returns: {"alg":"HS256","typ":"JWT"}define_function char NAVJwtSign(char encodedHeader[], char encodedPayload[],
char secret[], char algorithm[], char token[])Description: Signs existing Base64Url encoded header and payload components.
Parameters:
encodedHeader- Base64Url encoded headerencodedPayload- Base64Url encoded payloadsecret- Secret key for signingalgorithm- Algorithm to usetoken- Output: Complete JWT token string
Returns: true if successful, false otherwise
define_function char NAVJwtValidateTime(char payloadJson[], slong currentTime, integer clockSkew)Description: Validates time-based claims (exp, nbf, iat) in a JWT token.
Parameters:
payloadJson- Decoded payload JSON stringcurrentTime- Current Unix timestamp (signed long)clockSkew- Allowed clock skew in seconds
Returns: true if valid, false if expired or not yet valid
define_function char[128] NAVJwtGetErrorMessage(sinteger errorCode)Description: Returns a human-readable error message for a JWT error code.
Parameters:
errorCode- JWT error code
Returns: Error message string
#include 'NAVFoundation.Jwt.axi'
define_function char CreateAccessToken(char userId[], char token[]) {
stack_var char payload[500]
stack_var slong currentTime
// Get current Unix timestamp (you'll need a time function)
currentTime = 1516239022 // Example timestamp
// Create payload with standard claims
payload = "'{',
'"sub":"', userId, '",',
'"iat":', itoa(currentTime),
'}'"
// Create token with default HS256 header
return NAVJwtCreate('', payload, 'your-256-bit-secret', token)
}#include 'NAVFoundation.Jwt.axi'
define_function char CreateExpiringToken(char userId[], integer expiresInSeconds, char token[]) {
stack_var char payload[500]
stack_var slong currentTime
stack_var slong expirationTime
currentTime = 1516239022 // Current timestamp
expirationTime = currentTime + expiresInSeconds
// Create payload with exp claim
payload = "'{',
'"sub":"', userId, '",',
'"iat":', itoa(currentTime), ',',
'"exp":', itoa(expirationTime),
'}'"
return NAVJwtCreate('', payload, 'your-256-bit-secret', token)
}#include 'NAVFoundation.Jwt.axi'
define_function integer AuthenticateRequest(char token[]) {
stack_var _NAVJwtToken jwtToken
// Verify and decode the token
if (!NAVJwtVerifyAndDecode(token, 'your-256-bit-secret', jwtToken)) {
send_string 0, "'Authentication failed: ', NAVJwtGetErrorMessage(jwtToken.errorCode)"
return false
}
send_string 0, "'Authenticated. Payload: ', jwtToken.payloadJson"
return true
}#include 'NAVFoundation.Jwt.axi'
define_function ProcessToken(char token[]) {
stack_var char headerJson[NAV_JWT_MAX_JSON_LENGTH]
stack_var char payloadJson[NAV_JWT_MAX_JSON_LENGTH]
// Extract and decode components without verification
// (useful for debugging or when signature verification is handled elsewhere)
if (NAVJwtGetHeader(token, headerJson)) {
send_string 0, "'Header: ', headerJson"
}
if (NAVJwtGetPayload(token, payloadJson)) {
send_string 0, "'Payload: ', payloadJson"
}
// Now you can parse the JSON to extract specific claims
// (Using your JSON parsing library)
}#include 'NAVFoundation.Jwt.axi'
define_function char CreateTokenWithHS512(char token[]) {
stack_var char header[NAV_JWT_MAX_JSON_LENGTH]
stack_var char payload[500]
// Create custom header with HS512 algorithm
header = NAVJwtCreateHeader(NAV_JWT_ALG_HS512, NAV_JWT_TYP_JWT)
payload = '{"sub":"user123","role":"admin"}'
// Create token with custom header
return NAVJwtCreate(header, payload, 'your-512-bit-secret', token)
}#include 'NAVFoundation.Jwt.axi'
#include 'NAVFoundation.HttpUtils.axi'
define_variable
char gApiSecret[] = 'your-api-secret-key'
char gAuthToken[NAV_JWT_MAX_TOKEN_LENGTH]
define_function char GenerateApiToken(char token[]) {
stack_var char header[NAV_JWT_MAX_JSON_LENGTH]
stack_var char payload[1000]
stack_var slong currentTime
stack_var slong expirationTime
// Current time (Get from your time function)
currentTime = 1516239022
expirationTime = currentTime + 3600 // Expires in 1 hour
// Create payload with API claims
payload = "'{',
'"iss":"AMX Control System",',
'"sub":"api_access",',
'"iat":', itoa(currentTime), ',',
'"exp":', itoa(expirationTime), ',',
'"scope":"device.control"',
'}'"
// Use HS256 for API tokens
header = NAVJwtCreateHeader(NAV_JWT_ALG_HS256, NAV_JWT_TYP_JWT)
return NAVJwtCreate(header, payload, gApiSecret, token)
}
define_function MakeAuthenticatedApiRequest(char endpoint[]) {
stack_var char authHeader[NAV_JWT_MAX_TOKEN_LENGTH + 20]
// Generate token if needed
if (!length_array(gAuthToken)) {
if (!GenerateApiToken(gAuthToken)) {
send_string 0, "'Failed to generate token'"
return
}
}
// Verify token is still valid
if (!NAVJwtVerify(gAuthToken, gApiSecret)) {
send_string 0, "'Token expired, generating new token'"
if (!GenerateApiToken(gAuthToken)) {
send_string 0, "'Failed to generate token'"
return
}
}
// Create Authorization header
authHeader = "'Bearer ', gAuthToken"
// Make HTTP request with JWT token
// NAVHttpGet(endpoint, authHeader, ...)
send_string 0, "'Making API request with token'"
}
define_function integer VerifyIncomingToken(char token[]) {
stack_var _NAVJwtToken jwtToken
stack_var slong currentTime
// Verify signature
if (!NAVJwtVerifyAndDecode(token, gApiSecret, jwtToken)) {
send_string 0, "'Token verification failed: ', NAVJwtGetErrorMessage(jwtToken.errorCode)"
return false
}
// Validate time claims
currentTime = 1516239022 // Get current time
if (!NAVJwtValidateTime(jwtToken.payloadJson, currentTime, 30)) {
send_string 0, "'Token time validation failed'"
return false
}
send_string 0, "'Token is valid and not expired'"
return true
}#include 'NAVFoundation.Jwt.axi'
define_function integer ValidateTokenTiming(char token[], char secret[]) {
stack_var _NAVJwtToken jwtToken
stack_var slong currentTime
stack_var integer clockSkew
// Decode the token
if (!NAVJwtVerifyAndDecode(token, secret, jwtToken)) {
return false
}
// Get current Unix timestamp
currentTime = 1516239022 // Replace with actual time function
// Allow 30 seconds of clock skew
clockSkew = 30
// Validate exp and nbf claims
if (!NAVJwtValidateTime(jwtToken.payloadJson, currentTime, clockSkew)) {
send_string 0, "'Token time validation failed'"
return false
}
send_string 0, "'Token timing is valid'"
return true
}| Constant | Value | Description |
|---|---|---|
NAV_JWT_ALG_HS256 |
"HS256" |
HMAC using SHA-256 |
NAV_JWT_ALG_HS384 |
"HS384" |
HMAC using SHA-384 |
NAV_JWT_ALG_HS512 |
"HS512" |
HMAC using SHA-512 |
NAV_JWT_ALG_NONE |
"none" |
No signature (use caution!) |
| Constant | Value | Description |
|---|---|---|
NAV_JWT_SUCCESS |
0 |
Operation successful |
NAV_JWT_ERROR_INVALID_FORMAT |
-1 |
Token structure invalid (not 3 parts) |
NAV_JWT_ERROR_INVALID_HEADER |
-2 |
Header JSON is invalid |
NAV_JWT_ERROR_INVALID_PAYLOAD |
-3 |
Payload JSON is invalid |
NAV_JWT_ERROR_INVALID_SIGNATURE |
-4 |
Signature verification failed |
NAV_JWT_ERROR_UNSUPPORTED_ALG |
-5 |
Algorithm not supported |
NAV_JWT_ERROR_MISSING_ALG |
-6 |
Algorithm not specified in header |
NAV_JWT_ERROR_EMPTY_TOKEN |
-7 |
Token string is empty |
NAV_JWT_ERROR_EMPTY_SECRET |
-8 |
Secret key is empty |
NAV_JWT_ERROR_DECODE_FAILED |
-9 |
Base64Url decode failed |
NAV_JWT_ERROR_EXPIRED |
-10 |
Token has expired (exp claim) |
NAV_JWT_ERROR_NOT_YET_VALID |
-11 |
Token not yet valid (nbf claim) |
NAV_JWT_ERROR_INVALID_TIME |
-12 |
Time validation failed |
Note: Functions return simple boolean (char) values for success/failure. Detailed error codes are stored in the errorCode field of the _NAVJwtToken structure and can be retrieved using NAVJwtGetErrorMessage() for human-readable error messages.
| Constant | Value | Description |
|---|---|---|
NAV_JWT_CLAIM_ISS |
"iss" |
Issuer |
NAV_JWT_CLAIM_SUB |
"sub" |
Subject |
NAV_JWT_CLAIM_AUD |
"aud" |
Audience |
NAV_JWT_CLAIM_EXP |
"exp" |
Expiration Time |
NAV_JWT_CLAIM_NBF |
"nbf" |
Not Before |
NAV_JWT_CLAIM_IAT |
"iat" |
Issued At |
NAV_JWT_CLAIM_JTI |
"jti" |
JWT ID |
- Never hardcode secrets in production code
- Use strong, random secrets (at least 256 bits for HS256)
- Rotate keys regularly for enhanced security
- Store secrets securely, not in version control
- Prefer HS256 for most applications (good balance of security and performance)
- Use HS512 when maximum security is required
- Never use "none" algorithm in production
- Ensure algorithm in header matches expected algorithm (prevent algorithm confusion attacks)
- Always set expiration (
expclaim) for tokens - Use short expiration times for sensitive operations (minutes to hours)
- Implement token refresh mechanism for long-lived sessions
- Consider clock skew (typically 30-60 seconds) during validation
- Always verify signatures before trusting token content
- Verify before extracting or using claims
- Handle verification failures appropriately (log, reject, alert)
- Validate time claims (exp, nbf) in addition to signature
- Transmit tokens over HTTPS only
- Store tokens securely on client side (avoid localStorage for sensitive apps)
- Include tokens in Authorization header:
Authorization: Bearer <token> - Consider token size - large payloads increase bandwidth
- None Algorithm Attack - Reject tokens with
"alg":"none" - Algorithm Confusion - Verify algorithm matches expectations
- Token Replay - Use
jti(JWT ID) claim and maintain a blacklist - Insufficient Secret Length - Use secrets at least as long as hash output
- Missing Expiration - Always include
expclaim
- JWT components are Base64Url encoded (not standard Base64) per RFC 7515
- Padding is omitted from Base64Url encoding per RFC 7519
- Header and payload are JSON objects
- Signature is computed over:
base64url(header) + "." + base64url(payload) - Current implementation supports HMAC algorithms only (symmetric signing)
- Whitespace in JSON header/payload is preserved
- Claims are case-sensitive
- RSA and ECDSA algorithms (RS256, ES256, etc.) are not currently supported
- JSON Web Encryption (JWE) is not implemented
- No built-in token blacklisting or revocation
- Time functions must be provided by application (Unix timestamps)
- Maximum token size limited by configurable constants (default:
NAV_JWT_MAX_TOKEN_LENGTH= 4096 bytes)
- NAVFoundation.Encoding.Base64Url - URL-safe Base64 encoding (required)
- NAVFoundation.Cryptography.Hmac - HMAC signatures (required)
- NAVFoundation.Json - JSON parsing for advanced claim extraction
- NAVFoundation.HttpUtils - HTTP client for API requests with JWT
- RFC 7519 - JSON Web Token (JWT)
- RFC 7515 - JSON Web Signature (JWS)
- RFC 7518 - JSON Web Algorithms (JWA)
- RFC 4648 - Base64url Encoding
- JWT.io - Online JWT debugger and documentation
Test files for the JWT implementation can be found in the __tests__ directory. The test suite covers:
- Token creation with various algorithms
- Signature verification (valid and invalid)
- Token decoding and component extraction
- Time-based validation
- Error handling for malformed tokens
- Round-trip encoding/decoding
- Edge cases and boundary conditions
Run tests using the NAVFoundation test framework.