Skip to content

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: InsecureAlgorithmError

This 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 to clockToleranceSeconds past expiration
  • nbf (not before) — Accepts tokens up to clockToleranceSeconds before the not-before time
  • iat (issued at) — Rejects tokens issued more than clockToleranceSeconds in 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:

FeatureRequires clientCredentialsWhy
Token Validation (JWT)NoValidated locally using public keys
DPoP ValidationNoValidated locally using proof signature
Token IntrospectionYesThe authorization server authenticates the caller
Token RevocationYesThe 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 needed
const authrim = new AuthrimServer({
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
});
// For introspection/revocation — credentials required
const 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:settings rather than broad read / 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:

  1. Verify the JWT signature (the validator provides the parsed token)
  2. Check the jti has not been seen before
  3. 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 handler
app.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. requireHttps is true (default).
  • Clock synchronization — Your servers use NTP to keep clocks synchronized. Clock drift beyond clockToleranceSeconds causes false token rejections.
  • DNS resolution — The issuer hostname resolves correctly and is not vulnerable to DNS spoofing.

Configuration

  • Issuer URL is correct — Matches the iss claim in tokens exactly (including trailing slash behavior).
  • Audience value is correct — Matches the aud claim 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, and iat instead 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 jti values in a cache (e.g., Redis).
  • Back-Channel Logout is handled — If using back-channel logout, implement jti tracking 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 kid not 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:

ThreatAttack VectorSDK Defense
Token forgeryCrafted JWT with alg: noneRejects alg: none with InsecureAlgorithmError
Token forgeryJWT signed with wrong keySignature verification with JWKS kid matching
Token replayStolen Bearer tokenDPoP sender-constraining (application-level jti tracking)
Timing attackProbing issuer/audience valuesTiming-safe string comparisons
SSRFMalicious JWKS redirectCross-origin redirect blocking
DoSOversized JWT payload8 KB size limit
Thundering herdConcurrent JWKS refetchSingle-flight pattern
Key confusionPrivate key in DPoP proofPublic-key-only import
Expired tokenClock skew exploitationConfigurable clock tolerance with upper bound
MitMToken interception over HTTPHTTPS enforcement (configurable)
Privilege escalationMissing scope checksrequiredScopes 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