Security Considerations
Why Token Validation Matters
A resource server’s primary security responsibility is ensuring that every incoming request carries a valid, non-tampered access token issued by a trusted authorization server. Failures in token validation can lead to:
- Unauthorized access — Attackers accessing protected resources without valid credentials
- Privilege escalation — Tokens with forged scopes granting elevated permissions
- Token replay — Stolen tokens reused from a different context
- Data exfiltration — Compromised tokens used to extract sensitive data
@authrim/server is designed with defense-in-depth principles. Every validation step is implemented to be resistant against known attack vectors.
Built-in Security Features
The SDK includes the following security measures by default. These protections are always active and cannot be accidentally disabled.
1. Timing-Safe Comparisons
All security-critical string comparisons use constant-time algorithms to prevent timing side-channel attacks:
- Issuer (
iss) validation — Prevents attackers from probing which issuers are trusted - Audience (
aud) validation — Prevents probing of accepted audience values - DPoP thumbprint binding — Prevents inferring expected thumbprint values
Timing-safe comparison ensures that the time taken to compare two strings does not reveal how many characters match, eliminating information leakage.
2. Rejects alg: none
The SDK rejects any JWT with alg: none in the header, throwing an InsecureAlgorithmError. The “none” algorithm means the token is unsigned — accepting it would allow anyone to forge tokens.
// The SDK automatically rejects this — no configuration needed// Header: { "alg": "none", "typ": "JWT" }// Result: InsecureAlgorithmErrorThis protection cannot be disabled. There is no configuration option to allow unsigned tokens.
3. HTTPS Enforcement
By default, requireHttps: true ensures all external URLs use HTTPS:
- Issuer URL
- JWKS endpoint
- Introspection endpoint
- Revocation endpoint
HTTP URLs are rejected at configuration time, before any network request is made.
4. SSRF Protection (JWKS Redirect Blocking)
When fetching JWKS, the SDK blocks cross-origin redirects. This prevents Server-Side Request Forgery (SSRF) attacks where a malicious authorization server redirects the JWKS fetch to an internal network resource.
If the JWKS endpoint returns a redirect to a different origin, the SDK throws an error rather than following the redirect.
5. JWT Size Limit (8 KB)
The SDK rejects JWTs larger than 8 KB to prevent denial-of-service attacks. Oversized tokens could be used to:
- Exhaust memory during Base64 decoding
- Cause excessive CPU usage during signature verification
- Slow down request processing
Legitimate access tokens are typically well under 2 KB.
6. Single-Flight JWKS Fetch
When multiple requests arrive simultaneously and trigger a JWKS refresh, the SDK coalesces them into a single network request. This “single-flight” or “thundering herd” prevention:
- Avoids overwhelming the authorization server with parallel JWKS requests
- Ensures consistent key state across concurrent validations
- Reduces latency for all waiting requests
7. Public-Key-Only JWK Import
When processing DPoP proofs, the SDK imports only public key parameters from the JWK in the proof header. Any private key parameters (d, p, q, dp, dq, qi) are rejected.
This prevents:
- Attackers embedding private keys in proofs to trick the server
- Accidental private key leakage through logging or error messages
8. Clock Tolerance for exp / nbf / iat
The clockToleranceSeconds setting (default: 60 seconds) provides a buffer for clock skew between the authorization server and your resource server. The SDK applies this tolerance to:
exp(expiration) — Accepts tokens up toclockToleranceSecondspast expirationnbf(not before) — Accepts tokens up toclockToleranceSecondsbefore the not-before timeiat(issued at) — Rejects tokens issued more thanclockToleranceSecondsin the future
9. Request Body Consumption Protection
Framework middleware adapters handle request body parsing carefully to avoid consuming the body before your application reads it. Token extraction from the Authorization header is header-only and does not interfere with body processing.
10. No Private Key Leakage in DPoP
The SDK never requires or processes private keys for DPoP validation. Resource servers only need the public key from the DPoP proof header to verify the proof signature and compute the JWK Thumbprint.
Do NOT Checklist
Client Design Guidance
When to Create a Confidential Client
Some features of @authrim/server require clientCredentials (a client ID and secret). You need a confidential client when:
| Feature | Requires clientCredentials | Why |
|---|---|---|
| Token Validation (JWT) | No | Validated locally using public keys |
| DPoP Validation | No | Validated locally using proof signature |
| Token Introspection | Yes | The authorization server authenticates the caller |
| Token Revocation | Yes | The authorization server authenticates the caller |
If you only validate JWT access tokens, you do not need client credentials. Register a confidential client only when you need introspection or revocation.
// For JWT validation only — no credentials neededconst authrim = new AuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
// For introspection/revocation — credentials requiredconst authrim = new AuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com', introspectionEndpoint: 'https://auth.example.com/oauth/introspect', revocationEndpoint: 'https://auth.example.com/oauth/revoke', clientCredentials: { clientId: 'my-resource-server', clientSecret: 'resource-server-secret', },});Audience and Scope Design Patterns
Design your audience and scope values carefully:
- One audience per API — Use a unique audience URI for each API service (e.g.,
https://api.example.com,https://billing.example.com) - Scope granularity — Use scopes like
read:users,write:orders,admin:settingsrather than broadread/write - Least privilege — Client applications should request only the scopes they need
Token Lifetime Recommendations
Application Responsibilities
The SDK handles most security concerns automatically, but some responsibilities remain with your application:
DPoP jti Replay Protection
The SDK validates DPoP proof structure, signature, and binding — but it does not track jti values for replay detection. This is because replay protection requires server-side state (a cache of recently seen jti values), which varies by deployment.
Back-Channel Logout jti Verification
Similarly, BackChannelLogoutValidator validates logout token structure and claims but does not track jti values. Your application must:
- Verify the JWT signature (the validator provides the parsed token)
- Check the
jtihas not been seen before - Invalidate the corresponding user session
Error Response Formatting
The SDK throws typed errors (e.g., TokenExpiredError, InvalidSignatureError) but does not format HTTP error responses. Your application or middleware adapter handles this:
// Example: Express error handlerapp.use((err, req, res, next) => { if (err.name === 'TokenExpiredError') { return res.status(401).json({ error: 'token_expired' }); } if (err.name === 'InsufficientScopeError') { return res.status(403).json({ error: 'insufficient_scope' }); } next(err);});Production Checklist
Before deploying to production, verify the following:
Infrastructure
- HTTPS is enabled — All endpoints (API, issuer, JWKS) use HTTPS.
requireHttpsistrue(default). - Clock synchronization — Your servers use NTP to keep clocks synchronized. Clock drift beyond
clockToleranceSecondscauses false token rejections. - DNS resolution — The issuer hostname resolves correctly and is not vulnerable to DNS spoofing.
Configuration
- Issuer URL is correct — Matches the
issclaim in tokens exactly (including trailing slash behavior). - Audience value is correct — Matches the
audclaim in tokens. - Clock tolerance is reasonable — Default 60 seconds. Do not exceed 300 seconds.
- JWKS cache TTL is appropriate — Default 1 hour (
jwksRefreshIntervalMs: 3600000). Adjust based on your key rotation frequency.
Application Code
- Tokens are never logged — Log
sub,jti,scope, andiatinstead of the raw token string. - Error responses do not leak internal details — Return generic error codes to clients, log details server-side.
- Scopes are enforced per endpoint — Every protected endpoint specifies required scopes.
- DPoP jti replay protection is implemented — If using DPoP, track
jtivalues in a cache (e.g., Redis). - Back-Channel Logout is handled — If using back-channel logout, implement
jtitracking and session invalidation.
Key Rotation
- Key rotation strategy is defined — The authorization server rotates signing keys periodically.
- JWKS cache handles rotation — The SDK auto-retries on
kidnot found, but verify this works in your environment. - Old keys are removed — After a grace period, old keys should be removed from the JWKS to prevent use of compromised keys.
Monitoring
- Token validation failures are logged — Monitor for spikes that may indicate attacks.
- JWKS fetch failures are alerted — If the SDK cannot fetch keys, all token validations will fail.
- Clock drift is monitored — Alert if NTP synchronization fails.
Threat Model Summary
The following table maps common attacks to the SDK’s built-in defenses:
| Threat | Attack Vector | SDK Defense |
|---|---|---|
| Token forgery | Crafted JWT with alg: none | Rejects alg: none with InsecureAlgorithmError |
| Token forgery | JWT signed with wrong key | Signature verification with JWKS kid matching |
| Token replay | Stolen Bearer token | DPoP sender-constraining (application-level jti tracking) |
| Timing attack | Probing issuer/audience values | Timing-safe string comparisons |
| SSRF | Malicious JWKS redirect | Cross-origin redirect blocking |
| DoS | Oversized JWT payload | 8 KB size limit |
| Thundering herd | Concurrent JWKS refetch | Single-flight pattern |
| Key confusion | Private key in DPoP proof | Public-key-only import |
| Expired token | Clock skew exploitation | Configurable clock tolerance with upper bound |
| MitM | Token interception over HTTP | HTTPS enforcement (configurable) |
| Privilege escalation | Missing scope checks | requiredScopes validation on every endpoint |
Understanding this threat model helps you evaluate whether additional application-level security measures are needed for your specific deployment.
Next Steps
- Token Validation — Detailed validation API and claims processing
- DPoP Validation — Sender-constrained token verification with replay protection
- JWKS Management — Key caching, rotation, and custom providers
- Introspection & Revocation — Query and revoke tokens at the authorization server