Token Model
QNSP uses a two-token model: access tokens and refresh tokens.
Token Model
QNSP uses a two-token model: access tokens and refresh tokens.
Token Audiences
From packages/shared-kernel/src/constants.ts:
export const TOKEN_AUDIENCES = {
PLATFORM: "platform",
INTERNAL_SERVICE: "internal-service",
EXTERNAL_API: "external-api",
} as const;
| Audience | Use Case |
|---|---|
platform |
General platform access (default) |
internal-service |
Service-to-service communication |
external-api |
External API integrations |
Access Tokens (JWT)
Access tokens are issued as PQC-signed JWTs for API authentication.
In this repo, auth-service uses a JWT key manager and signs tokens by default.
JWT Claims
From packages/shared-kernel/src/auth.ts:
// JWT payload structure
interface JwtPayload {
jti: string; // Token ID (UUID)
sub: string; // Subject ID (user/service UUID)
iat: number; // Issued at (Unix timestamp)
exp: number; // Expiration (Unix timestamp)
aud: TokenAudience; // Audience
iss?: string; // Issuer (optional)
tenant_id?: string; // Tenant ID (optional)
roles?: string[]; // Roles (optional)
}
Token Lifetime
From apps/auth-service/src/config/env.ts:
| Setting | Default | Description |
|---|---|---|
ACCESS_TOKEN_TTL_SECONDS |
900 (15 min) | Access token lifetime |
REFRESH_TOKEN_TTL_SECONDS |
2,592,000 (30 days) | Refresh token lifetime |
DEFAULT_TOKEN_TTL_SECONDS |
900 (15 min) | Fallback from constants.ts |
JWT Signing Algorithms
From packages/shared-kernel/src/jwt.ts:
JWT signing uses a signature algorithm (default dilithium-2).
The JWT alg header is derived from the configured PQC algorithm.
Refresh Tokens
Opaque tokens for obtaining new access tokens.
Format
From packages/shared-kernel/src/auth.ts:
const REFRESH_TOKEN_SECRET_BYTES = 48;
const REFRESH_TOKEN_DELIMITER = ".";
// Format: <tokenId>.<base64url-secret>
// Example: 550e8400-e29b-41d4-a716-446655440000.dGhpcyBpcyBhIHNlY3JldA...
Rotation
Refresh tokens rotate on use:
- Client presents refresh token
- Server validates and issues new access + refresh tokens
- Old refresh token is revoked
Revocation
POST /auth/token/revoke
Content-Type: application/json
{"refreshToken": "<token>"}
Or by token ID:
POST /auth/token/revoke
Content-Type: application/json
{"tokenId": "<uuid>"}