You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The remaining findings of the 2026-09-25 review of auth/jwt, auth/credential, auth/apikey and auth/field. No behaviour changes; each is a guide that says the wrong thing or a control nothing pins.
docs/secure-login.md section 5 still replaces the refresh hash unconditionally and claims the second presentation of a replayed token "finds no matching hash". Two requests carrying the same token that read the row before either writes both rotate and both get a pair; docs: fix the recipes that lose credentials #427 fixed the same block in docs/jwt.md only.
The auth/field package doc still says an index hit proves the plaintext, the claim docs: fix the recipes that lose credentials #427 removed from docs/field.md, and shows a read path that decrypts without re-checking.
docs/configuration.md describes the credential binding as purpose || 0x00 || subject || 0x00 || token, the construction the code itself calls the bug it replaced with length prefixes; docs/errors.md has no row for jwt.ErrTokenOversized or jwt.ErrNotInitialised.
docs/key-management.md says the refresh secret gives "cryptographic separation", which is true of auth/field only: apikey.Hash, jwt.HashRefreshToken and totp.HashRecoveryCode key HMAC with the raw secret and produce one digest for one string.
Controls that could be deleted with the suite green: WithExpirationRequired and WithIssuedAt on both verifiers (the no-exp test's fixture used jti as its jti, which fix(jwt): make issuance and verification agree #443's shape check refuses first, so the test stayed green for the wrong reason); the zero-value guard in jwt.VerifyRefreshTokenHash (its test used a hash no key produces) and in apikey.Hash (no test); the dash, variant and hex checks of isUUIDv7; ParseID's lowercase-hex rule and prefix check (the uppercase fuzz seed uppercases the prefix too, so it never reaches the hex rule); the refresh-token issuance cap from fix(jwt): make issuance and verification agree #443; the leeway on the refresh path; the empty-audience check in validateConfig, unreachable through New.
Both jwt fuzz targets have no oracle: FuzzVerifyAccessToken discards the result and FuzzIsUUIDv7 checks nothing, although its seed set already holds the variant-c input the variant mutant accepts.
No known-answer test pins any stored format: the HKDF labels, the credential field order, the apikey hash input and the refresh-hash digest can all change with the suite green, and every stored ciphertext or hash then stops matching after an upgrade.
The remaining findings of the 2026-09-25 review of
auth/jwt,auth/credential,auth/apikeyandauth/field. No behaviour changes; each is a guide that says the wrong thing or a control nothing pins.docs/secure-login.mdsection 5 still replaces the refresh hash unconditionally and claims the second presentation of a replayed token "finds no matching hash". Two requests carrying the same token that read the row before either writes both rotate and both get a pair; docs: fix the recipes that lose credentials #427 fixed the same block indocs/jwt.mdonly.auth/fieldpackage doc still says an index hit proves the plaintext, the claim docs: fix the recipes that lose credentials #427 removed fromdocs/field.md, and shows a read path that decrypts without re-checking.docs/configuration.mddescribes the credential binding aspurpose || 0x00 || subject || 0x00 || token, the construction the code itself calls the bug it replaced with length prefixes;docs/errors.mdhas no row forjwt.ErrTokenOversizedorjwt.ErrNotInitialised.docs/key-management.mdsays the refresh secret gives "cryptographic separation", which is true ofauth/fieldonly:apikey.Hash,jwt.HashRefreshTokenandtotp.HashRecoveryCodekey HMAC with the raw secret and produce one digest for one string.WithExpirationRequiredandWithIssuedAton both verifiers (the no-exp test's fixture usedjtias its jti, which fix(jwt): make issuance and verification agree #443's shape check refuses first, so the test stayed green for the wrong reason); the zero-value guard injwt.VerifyRefreshTokenHash(its test used a hash no key produces) and inapikey.Hash(no test); the dash, variant and hex checks ofisUUIDv7;ParseID's lowercase-hex rule and prefix check (the uppercase fuzz seed uppercases the prefix too, so it never reaches the hex rule); the refresh-token issuance cap from fix(jwt): make issuance and verification agree #443; the leeway on the refresh path; the empty-audience check invalidateConfig, unreachable throughNew.FuzzVerifyAccessTokendiscards the result andFuzzIsUUIDv7checks nothing, although its seed set already holds the variant-cinput the variant mutant accepts.