Choosing data-plane auth: API key vs JWT vs mTLS
When to use API keys, JWT tokens, or mutual TLS for your RestWard APIs, with rotation guidance and configuration details.
RestWard supports three authentication methods for your generated APIs. Each method suits different use cases, security requirements, and operational patterns. This guide helps you choose the right method for your scenario and explains how to configure and rotate credentials for each.
Authentication methods overview
| Method | Best for | Credential format | How it works | Rotation complexity |
|---|---|---|---|---|
| API Key | Server-to-server, internal services, simple integrations | rw_... string (32-byte random) |
Sent in X-API-Key header; matched against stored hash |
Single click in dashboard |
| JWT | User-delegated access, tokens from your IdP (Entra ID, Auth0, etc.) | Bearer token (JWT) | Sent in Authorization: Bearer header; validated against JWKS or shared key |
Automatic via JWKS endpoint; manual for shared keys |
| mTLS | High-assurance machine identity, zero-trust environments | X.509 client certificate | Sent via TLS client cert (or X-Forwarded-Client-Cert header from proxy); validated against CA or fingerprint |
CA/fingerprint rollover in dashboard |
Key insight: All three methods can coexist on the same API. Enable the ones your consumers need in Auth & Keys for your organization. A request is authenticated by the first enabled method that presents a valid credential.
API Key authentication
API keys are the simplest authentication method. They are ideal for server-to-server communication, internal services, CI/CD pipelines, and any scenario where you control both the producer and consumer of the API.
Who it suits
- Internal microservices communicating with each other
- CI/CD pipelines that need programmatic access
- Partner integrations where you issue and manage keys centrally
- Simple mobile/desktop apps where embedding a key is acceptable
- Machine-to-machine scenarios without user context
Dashboard configuration
- Go to Auth & Keys in your organization
- Ensure API Key method is enabled (toggle on if needed)
- Click New API Key
- Enter a Key Name (e.g., "Production Mobile App", "CI Pipeline")
- Select the API this key can access
- Choose the Role: Read Only, Read & Write, or Admin
- Optionally set Allowed IP addresses (one per line, supports CIDR)
- Optionally set Rate Limit Per Minute (defaults to 60, clamped to plan ceiling)
- Click Create Key
- Copy the key immediately — it displays only once in plaintext
The key appears in your API Keys table as Active. You can view its usage statistics, last used time, and manage it from there.
Rotation
Rotating an API key generates a new key string while keeping the same name, API assignment, role, and IP allowlist. The old key is revoked immediately in the platform. Running APIs stop accepting it on their next key reload, which happens within 30 seconds (configurable via EndpointConfig:RefreshSeconds).
To rotate a key:
- In the API Keys table, find the active key
- Click Rotate key (refresh icon)
- The new key is shown once in a success banner at the top of the page
- Copy it and update your consumer's configuration
- Dismiss the banner
What happens to the old key: It is immediately revoked in the database. The old key string no longer authenticates once running APIs reload their keys (within ~30 seconds). The new key inherits the old key's name, API assignment, role, and IP allowlist. The rate limit is re-clamped to the current plan ceiling at rotation time, so a key rotated after a plan downgrade comes back with the new, lower limit rather than keeping the old, higher value.
Per-method rate limits and IP allowlists
- Rate limit: Each API key has its own
RateLimitPerMinutevalue (default: 60). This is clamped to your plan'sMaxKeyRateLimitPerMinuteceiling. - IP allowlist: Each key can have its own allowed IP ranges. A request from an address not in the list receives
403 Forbiddenwith the messageIP address not allowed.
See API keys & tenant API auth for detailed key management.
JWT authentication
JWT (JSON Web Token) authentication validates bearer tokens issued by your identity provider. This is ideal when your API consumers already have tokens from your organization's IdP, or when you want to delegate authentication to a trusted third party.
Who it suits
- User-delegated access: Your users obtain tokens from your IdP (e.g., Entra ID) and use them to call your API
- Service-to-service with existing token infrastructure
- Multi-tenant SaaS where each tenant brings their own IdP
- Short-lived credentials with automatic expiration
Dashboard configuration
- Go to Auth & Keys in your organization
- Ensure JWT Bearer method is enabled
- Click Configure on the JWT Bearer card
- Enter the Issuer (required) — the expected
issclaim in tokens (e.g.,https://login.microsoftonline.com/your-tenant-id/v2.0) - Optionally enter Audience — when set, tokens must contain this value in their
audclaim - Choose validation approach:
- JWKS URI (recommended): Enter the OpenID Connect discovery endpoint or direct JWKS endpoint. Keys are fetched and cached automatically.
- Signing Key: Enter a shared symmetric key for HMAC-signed tokens (HS256, HS384, HS512)
- Optionally set Role Claim — the claim name whose value maps to an API role (Admin, ReadWrite, ReadOnly)
- Optionally set Default Scope — the role granted when no role claim is present or matched
- Optionally set Rate Limit Per Minute for JWT callers (defaults to 60)
- Optionally set Allowed IP addresses for all JWT tokens
- Click Save
Token requirements
- Tokens must have exactly three dot-separated parts (header.payload.signature)
- Maximum token length: 16,384 characters
- For JWKS validation: tokens must specify an
alg(algorithm) that matches the key type - For symmetric validation: tokens must use an HS* algorithm (HS256, HS384, HS512)
- The
issclaim must match the configured issuer exactly (ordinal comparison) - If audience is configured, the token's
audmust contain that value
Rotation
With JWKS endpoint (asymmetric):
JWT signing keys are automatically rotated when the IdP publishes new keys to its JWKS endpoint. RestWard:
- Caches the JWKS configuration per issuer endpoint (static
ConcurrentDictionaryinJwtAuthenticator) - Uses
ConfigurationManager<OpenIdConnectConfiguration>from Microsoft.IdentityModel which auto-refreshes keys - When a token arrives with an unknown
kid(key ID), requests a refresh (at most once per minute per issuer) - Accepts tokens signed with any key in the current JWKS set
JWKS refresh behavior: An unknown
kidtriggers a single refresh attempt. If the refresh fails or thekidis still not found, the token is rejected with reasonunknown_kid. If the JWKS endpoint is completely unavailable, authentication returns503 Service Unavailable(not counted against rate limits).
With shared signing key (symmetric):
You must manually update the Signing Key in the dashboard when you rotate your shared secret. There is no automatic rotation — the old key continues to work until you replace it, at which point tokens signed with the old key are immediately rejected.
Best practice: Use asymmetric JWKS validation whenever possible. It enables automatic key rotation and is more secure (no shared secrets to manage).
Per-method rate limits and IP allowlists
- Rate limit: JWT callers share a configured
RateLimitPerMinute(default: 60). This applies per token subject. - IP allowlist: All JWT tokens for this method can be restricted to specific IP ranges. A request from an address not in the list receives
403 Forbidden.
mTLS authentication
Mutual TLS (mTLS) authentication validates client certificates presented during the TLS handshake. This provides the highest level of assurance that the caller is who they claim to be, as it relies on cryptographic proof of identity at the transport layer.
Who it suits
- High-security environments requiring certificate-based authentication
- Zero-trust architectures where every request must prove identity
- Machine-to-machine in regulated industries (finance, healthcare)
- Internal services in a PKI-managed infrastructure
Dashboard configuration
- Go to Auth & Keys in your organization
- Ensure Mutual TLS method is enabled
- Click Configure on the Mutual TLS card
- Configure at least one acceptance criterion:
- Trusted CA PEM: The CA certificate (in PEM format) that issued the client certificates. All certificates that chain to this CA are accepted.
- Allowed Fingerprints: SHA-256 thumbprints of specific client certificates. Enter one per line.
- Allowed Subjects: Distinguished Names or Common Names from the certificate's subject. Requires a Trusted CA — subjects are only checked on certificates that chain to the configured CA.
- Optionally set Default Scope — the role granted to authenticated clients
- Optionally set Rate Limit Per Minute for mTLS callers (defaults to 60)
- Optionally set Allowed IP addresses for all mTLS connections
- Click Save
Validation rule: You must configure at least one criterion. If you use Allowed Subjects, you must also provide a Trusted CA. A configuration with subjects but no CA is refused on save.
How it works
RestWard's mTLS implementation handles two deployment topologies:
Proxy-terminated TLS (current production):
On the demo and production deployments, Caddy terminates TLS for the API hostnames under *.run.restward.tech and reverse-proxies to Kestrel on a loopback port. In this topology:
- Caddy is configured to request client certificates (
client_auth mode request) - Caddy forwards the client certificate to the backend in the
X-Forwarded-Client-Certheader - The header value is a single-line base64-DER encoding (multi-line PEM won't work in HTTP headers)
MtlsAuthenticatorreads this header first
See deploy/hetzner/conf.d/restward-app.caddy for the Caddy configuration.
Direct Kestrel TLS (future):
For direct Kestrel deployments where Kestrel performs the TLS handshake, the authenticator falls back to reading HttpContext.Connection.ClientCertificate.
Certificate validation
A presented certificate is accepted when:
- It is within its validity window (not before
NotBefore, not afterNotAfter) - AND it matches at least one configured criterion:
- Its SHA-256 thumbprint is in the Allowed Fingerprints list, OR
- It chains to the configured Trusted CA AND (if Allowed Subjects are configured) its subject DN/CN/SAN is in the list
Subject matching: A subject match alone is never sufficient. Subjects are only checked when the certificate chains to the configured CA. This prevents spoofing via self-signed certificates with arbitrary subjects.
Rotation
CA rollover:
To rotate your CA certificate:
- Generate a new CA certificate
- Issue new client certificates from the new CA
- In the dashboard, add the new CA PEM to the Trusted CA PEM field (you can temporarily have both old and new)
- Deploy the new client certificates to your consumers
- Once all consumers are using the new CA, remove the old CA PEM
Grace period: During the transition, both old and new CA certificates are accepted. This allows for gradual rollout without downtime.
Fingerprint rollover:
To rotate client certificates identified by fingerprint:
- Generate new client certificates
- Add the new SHA-256 thumbprints to the Allowed Fingerprints list
- Deploy the new certificates to your consumers
- Remove the old fingerprints once all consumers have updated
Thumbprint format: SHA-256 hash of the certificate's DER encoding, represented as a lowercase hexadecimal string (no
0xprefix, no separators).
Subject rollover:
If you use Allowed Subjects with a CA:
- Update the Allowed Subjects list to include new subject DNs
- Deploy new client certificates with the new subjects
- Remove old subjects once all consumers have updated
Important: Subject-based validation always requires a Trusted CA. The subject is only checked after the certificate chain is verified.
Per-method rate limits and IP allowlists
- Rate limit: mTLS callers share a configured
RateLimitPerMinute(default: 60). This applies per client certificate. - IP allowlist: All mTLS connections for this method can be restricted to specific IP ranges. A request from an address not in the list receives
403 Forbidden.
Decision table
Use this table to quickly determine which authentication method fits your scenario:
| Scenario | API Key | JWT | mTLS | Notes |
|---|---|---|---|---|
| Internal service-to-service | ✅ Best | ⚠️ Good | ⚠️ Good | API keys simplest; mTLS for highest assurance |
| User-delegated access (your IdP) | ❌ No | ✅ Best | ❌ No | JWT carries user identity from IdP |
| Partner integration (you issue keys) | ✅ Best | ⚠️ Possible | ⚠️ Possible | API keys simplest to manage |
| High-security zero-trust | ⚠️ Possible | ⚠️ Possible | ✅ Best | mTLS provides transport-level identity |
| Short-lived credentials | ❌ No | ✅ Best | ⚠️ Possible | JWT tokens have built-in expiration |
| Automatic rotation | ❌ Manual | ✅ JWKS | ⚠️ Manual | JWKS enables automatic key rotation |
| No infrastructure changes | ✅ Best | ✅ Best | ❌ Requires TLS config | mTLS needs certificate deployment |
| Fine-grained IP restrictions | ✅ Per key | ✅ Per method | ✅ Per method | API keys support per-key IP lists |
| Rate limiting | ✅ Per key | ✅ Per subject | ✅ Per cert | All methods support rate limits |
| Existing token infrastructure | ❌ No | ✅ Best | ❌ No | JWT integrates with your IdP |
| PKI-managed environment | ⚠️ Possible | ⚠️ Possible | ✅ Best | mTLS leverages existing PKI |
Troubleshooting
401 Unauthorized vs 403 Forbidden
Understanding the difference helps you diagnose authentication issues:
| Status | Meaning | Common causes |
|---|---|---|
| 401 Unauthorized | Authentication failed — no valid credential presented | Expired key/token/certificate; revoked key; wrong issuer; invalid signature; malformed credential; key used for wrong API |
| 403 Forbidden | Authentication succeeded but access denied | IP address not in allowlist; insufficient role/permissions for the operation |
API Key specific:
401: Key not found, key revoked, or key hash mismatch403: IP address not in the key's allowed IP ranges; key used for a different API (wrong API configuration)
JWT specific:
401: Token malformed, wrong issuer, invalid signature, unknown kid (with JWKS), token expired503: JWKS endpoint could not be fetched (reason:jwks_unavailable)403: IP address not in the method's allowed IP ranges
mTLS specific:
401: No client certificate presented, certificate outside validity window, certificate doesn't match any criterion403: IP address not in the method's allowed IP ranges
Common issues and solutions
"API key not working after rotation"
- The old key is immediately invalid. Ensure you've updated your consumer with the new key.
- Check that the new key was copied correctly (no truncation, no extra spaces).
"JWT tokens rejected with unknown_kid"
- The token was signed with a key not in the current JWKS set.
- This triggers a JWKS refresh (once per minute per issuer).
- Verify your IdP has published the new signing keys to its JWKS endpoint.
- Check that the token's
kidheader matches a key in the JWKS.
"JWT tokens rejected with wrong_issuer"
- The token's
issclaim doesn't match the configured issuer exactly (ordinal comparison). - Verify the issuer URL in your dashboard matches the
issclaim in your tokens exactly.
"mTLS certificate rejected"
- Certificate is outside its validity window: check
NotBeforeandNotAfter. - Certificate doesn't chain to the configured CA: verify the CA PEM is correct.
- Certificate fingerprint doesn't match: recompute the SHA-256 thumbprint of the DER encoding.
- Subject doesn't match: ensure the certificate's subject is in the Allowed Subjects list AND it chains to the CA.
"IP address not allowed" (403)
- The client's IP address is not in the allowlist for the key or method.
- Remember: the address compared is what the platform's reverse proxy appends to
X-Forwarded-For, not the direct connection address. - For consumers behind NAT/proxy, this is the gateway's public address.
- Clear the allowlist field to remove the restriction entirely.
"Rate limit exceeded" (429)
- You've exceeded the configured rate limit for the key, token subject, or certificate.
- Check the
X-RateLimit-Scopeheader to see which limit was hit. - Wait for the
Retry-Afterperiod before retrying. - Consider increasing the rate limit or implementing client-side backoff.
Verification checklist
Before deploying, verify your authentication configuration:
- The authentication method is enabled in Auth & Keys
- For JWT: Issuer is configured correctly; JWKS endpoint is accessible (test with
curl) - For mTLS: At least one acceptance criterion is configured; CA PEM is valid
- For API keys: Keys are created and assigned to the correct API
- IP allowlists (if used) include the actual client addresses (consider NAT/proxy)
- Rate limits are set appropriately for each method
- You've tested authentication with a real request (not just dashboard configuration)
See also
- API keys & tenant API auth — Detailed reference for API key management
- Rate limiting — How rate limits work and how to handle 429 responses
- Building & publishing APIs — Endpoint configuration and authentication setup
- Examples: Authentication — Code examples for all authentication methods