Use a supervised JWKS-backed strategy when tokens come from an external identity provider, and keep the signing keys in memory with concurrent reads through ETS. If you verify locally, pin the algorithm and validate exp, nbf, iss, and aud explicitly. The safest pattern is to treat signature checking, key rotation, and claim validation as separate controls, not one combined step.
Where JWT verification and key management should be separated
JWT verification fails when teams let one step do too much. Signature validation answers whether the token was issued by a trusted signer, while claim validation answers whether it should be accepted in this request context. Key rotation and key lookup are separate again, because the verifier needs a dependable way to find current public keys without turning runtime checks into a brittle manual process.
For Elixir services, the practical model is to keep verification state narrow: cache JWKS material for fast reads, refresh it on a schedule or on cache miss, and make the verifier depend on explicit inputs rather than hidden assumptions. That keeps the code easier to reason about when issuers rotate keys, when multiple environments exist, or when tokens from different issuers share the same application boundary.
A helpful reference point is NIST SP 800-57 Key Management, because JWT signing keys are still cryptographic keys with lifecycle obligations. Treating verification as part of key lifecycle discipline, not just parsing, prevents teams from confusing cached trust material with durable trust.
How to build the verifier so it stays safe under rotation
The safest Elixir pattern is usually a supervised process that owns JWKS fetching and cache refresh, with in-memory reads through ETS for verification throughput. That design gives you predictable concurrency and avoids reloading keys on every request, while still letting the application recover cleanly if the upstream JWKS endpoint is temporarily unavailable.
Local verification should be strict rather than convenient. Pin the expected algorithm, reject algorithm confusion, and validate exp, nbf, iss, and aud explicitly for every token. If the issuer changes, the audience changes, or the token is not time-valid, the token should fail even if the signature is otherwise correct.
When the application depends on a hosted identity provider, a JWKS-backed verifier is often the most maintainable option because it cleanly separates trust establishment from request handling. If the system uses its own signing keys, the verifier should still consume keys from a managed source and avoid embedding long-lived secrets in code or configuration.
For implementation discipline, OWASP ASVS is useful because it treats authentication, session handling, and authorization checks as distinct verification concerns. JWT handling is most reliable when teams apply the same separation of duties in code that ASVS expects in the control model.
What breaks most often in JWT handling
The common failure is not cryptography, it is control coupling. Teams trust a signature and then skip claim checks, accept whatever algorithm the token declares, or keep using an outdated key set after rotation. Another frequent problem is treating cached keys as if they were permanent, which creates a hidden dependency on stale trust material.
Key management gaps also appear when rotation is planned but not operationalized. If old keys remain accepted too long, or if there is no clear path to retire a compromised key, the verification layer can continue to validate tokens that should no longer be trusted. That is why the verifier needs both a refresh path and an explicit revocation or rekeying response.
The same pattern shows up in identity-related incidents where exposed or never-retired signing keys let attackers mint trusted tokens. NHIMG’s Microsoft Storm-0558 key breach 2023 and Coupang Signing Key Breach both illustrate why token verification must be coupled to disciplined signing-key retirement and offboarding.
For broader token hygiene, Token and Session Security Guide is relevant because JWTs behave like bearer credentials when they are accepted without adequate claim and lifetime checks. The useful rule is simple: a valid signature is necessary, but it is never sufficient on its own.
Risk and Threat Considerations
JWT verification gaps turn into trust failures, not just coding bugs. If keys are cached badly, rotated slowly, or accepted without issuer and audience checks, an attacker who obtains a signing key or forges one through a compromised trust path can continue to issue tokens that your service accepts.
Failure mechanism: The verifier treats signature validity as proof of full legitimacy, while stale JWKS data, weak algorithm handling, or incomplete claim checks leave a path for forged, replayed, or mis-scoped tokens to pass.
Impact: Attackers can impersonate users or services, move laterally across APIs, and preserve access beyond the intended key lifetime, especially when rotation and revocation are not operationally connected to verification.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST SP 800-57 and OWASP ASVS set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST SP 800-57 | NIST SP 800-57 Part 1 — Key Management | JWT signing keys require lifecycle and rotation discipline to keep verification trustworthy. |
| Recommendation — Manage JWT signing keys as lifecycle-bound cryptographic keys with clear rotation and retirement procedures. | ||
| OWASP ASVS | V6 — Authentication | JWT verification depends on strict token validation, issuer trust, and algorithm handling. |
| V8 — Authorization | JWT claims such as audience and scope affect whether a token should be accepted for a request. | |
| V9 — Self-contained Tokens | JWTs are self-contained tokens whose integrity and claims must be verified independently. | |
| Recommendation — Enforce strict token validation, algorithm pinning, and issuer checks in authentication code. Validate token audience and scope before allowing access to protected actions. Verify token integrity, lifetime, and claim consistency before trusting self-contained tokens. | ||
Practitioner Guidance
What to prioritise: Make the verifier depend on a single, tested trust source for public keys, then isolate signature checks from claim checks so either failure mode is visible in logs and tests. If the service accepts multiple issuers, model each issuer explicitly rather than sharing one permissive validation path.
What to verify: Confirm that the JWKS refresh path survives network failure, that ETS reads never block request handling, and that expired or not-yet-valid tokens fail even when the signature is correct. Also verify that rotation does not silently extend trust in retired keys.
What good looks like: A token can only pass when the key is current, the algorithm is expected, the issuer and audience match, and the token is time-valid. In practice, that means the verifier is resilient under normal rotation and safely strict under compromise.
Practitioner takeaway: The goal is not merely to decode JWTs, it is to make trust state explicit, refreshable, and bounded so key rotation can happen without weakening verification.
Related resources from NHI Mgmt Group
- How should security teams implement self-service API key management without creating governance gaps?
- How should security teams implement SCIM provisioning for secrets management without creating lifecycle gaps?
- How should organisations implement identity security across authentication, authorization, verification, and compliance without creating gaps between teams?
- How should security teams implement selective disclosure in identity verification flows without creating new trust gaps?
Deepen Your Knowledge
Reviewed and updated by the NHIMG editorial team on September 30, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org