All JWTs (access, MFA setup, MFA challenge, SSO completion) were signed
with the same secret and the access-token strategy checked only signature
and expiry. The MFA challenge token returned after the password step
therefore worked as a full access token: a password alone was enough to
use the API, skipping the second factor.
Every token now carries a pinned issuer, algorithm (HS256) and a
per-purpose audience; the strategy accepts only the access audience and
rejects any payload carrying a helper-token purpose. Existing access
tokens (no audience) stop working; clients renew them via the refresh
cookie.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>