Signed Tokens
A lightweight JWT alternative: HMAC-SHA256 signed, purpose-bound, optionally expiring tokens. No algorithm-confusion attacks โ the algorithm is fixed, not user-controlled.
// Sign a structured payload
const token = await enc.sign(
{ userId: '123', role: 'admin' },
'auth:access',
{ ttlSeconds: 3600 }
);
// โ 'eyJhbGci....eyJ1c2VyS....ABC123...' (base64url, dot-separated)
// Verify โ never throws on invalid tokens (unless throwOnExpiry is set)
const result = await enc.verify<{ userId: string; role: string }>(token, 'auth:access');
if (result.valid) {
console.log(result.payload); // { userId: '123', role: 'admin' }
console.log(result.remainingTtl); // seconds until expiry
} else {
console.log(result.reason); // 'expired' | 'invalid_signature' | 'malformed'
}
Throw on expiry
await enc.verify(token, 'auth:access', { throwOnExpiry: true });
// โ throws EncryptixError { code: 'TOKEN_EXPIRED' }
sign<T>(payload: T, purpose: string, options?: SignTokenOptions): Promise<string>
verify<T>(token: string, purpose: string, options?: VerifyTokenOptions): Promise<VerifyTokenResult<T>>
VerifyTokenResult<T>:
type VerifyTokenResult<T> =
| { valid: true; payload: T; remainingTtl?: number }
| { valid: false; reason: 'expired' | 'invalid_signature' | 'malformed' };
๐ซ
Tokens are bound to their purpose. A token signed for auth:access will not verify under auth:refresh โ no separate audience field required.