Repository navigation
fix(auth): refuse revoked sessions on every request - #65
Open
christian-at-sevenlab wants to merge 1 commit into
Open
christian-at-sevenlab wants to merge 1 commit into
christian-at-sevenlab wants to merge 1 commit into
Conversation
Logout, revoking a device and deleting a user only remove the `sessions` row; the sealed cookie stayed valid. nuxt-auth-utils calls the `fetch` hook in server/plugins/session.ts only from GET /api/_auth/session, never from getUserSession or requireUserSession, so every API route kept accepting a revoked cookie. The docs claimed the plugin validated the row on every request. server/middleware/02.session-revocation.ts now checks, on each request that carries a session cookie, that the row exists, belongs to the user and has not expired. If not, it strips h3's per-request session cache in place and deletes the cookie. clearUserSession does not work here: the next getUserSession re-reads the still-valid request cookie. Without that cache it fails closed with a 401. The auth e2e suite now asserts that a logged-out cookie and a session revoked from another device both get a 401.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Adds
server/middleware/02.session-revocation.tsto thenuxt4:authtemplate. On every request that carries a session cookie, it checks that thesessionsrow exists, belongs to the user and has not expired. If any check fails, the session is cleared for that request and the cookie is deleted.Why
Logging out, revoking a device and deleting a user all remove only the
sessionsrow. The sealed cookie itself stays valid. nuxt-auth-utils calls thefetchhook inserver/plugins/session.tsonly fromGET /api/_auth/session. It never calls it fromgetUserSessionorrequireUserSession. As a result, every API route still accepted a revoked cookie. The generated AGENTS.md/README said the plugin "validates the row on every request", which was not true.This was found and fixed first in a downstream project, then ported here.
Type of change
AI assistance
Agent, service and model, if you know it: Claude Code, Opus 5.5
How much of this is agent-written?
Feature versions
version(nuxt4:auth1.10.1,nuxt4:vitest1.0.7)collectDocsorcollectEnvcontribution, and also bumped the feature that writes the target file (nuxt4:docs1.0.25)Testing
The e2e auth suite (
test/e2e/api/auth.test.ts) now checks that both a logged-out cookie and a session revoked from another device get a 401 on/api/auth/sessions. These tests need a running app, and I have not run them against a fresh scaffold yet. The same middleware, with an extra check for deactivated users, runs in the downstream project, where these cases pass.pnpm tscpassespnpm testpasses (see the WSL-only failure above)Checklist
docs/,README.md)packages/*/templates/**are LF (.gitattributesenforces it; the copy path never translates line endings)Anything else
clearUserSessiondoes not work here: the nextgetUserSessionin the same request re-reads the still-valid request cookie. The middleware therefore strips h3's per-request cache (event.context.sessions[name]) in place. If that cache is missing, it fails closed with a 401.