Repository navigation
fix(server-sdk): read and write the project-scoped auth cookies - #2277
Merged
Merged
Conversation
client-sdk-auth 1.3.4+ stores the session as crossmint-jwt-<projectId> and crossmint-refresh-token-<projectId>, but the server SDK only read and wrote the bare names, so getSession(request) saw no session and a custom refresh route stored cookies the client never read. - getSession(request), handleCustomRefresh and logout read the scoped names first and fall back to the legacy bare names, per cookie. - storeAuthMaterial writes the scoped names and expires the legacy ones. - New CrossmintAuth.getAuthCookieNames() for code with no request object (Next.js Server Components). - getScopedCookieName moves to common-sdk-auth; the client uses it. - README (source of the docs.crossmint.com server SDK page) and the nextjs-ssr example use getSession(request) / getAuthCookieNames() instead of bare names.
…eep Next.js middleware on response.cookies
🦋 Changeset detectedLatest commit: 52ba42b The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
[Medium impact] The PR appears safe to merge; no new blocking issue was found. Reviews (2) · Last reviewed commit: "fix(server-sdk): expire legacy auth cook..." · Reviewed by Greptile |
…er-key errors inside the example's error handling
Collaborator
Author
|
@greptileai review |
maxsch-xmint
approved these changes
Nov 5, 2026
… a CrossmintAuth method Callers with no request object read the project ID from the API key with the re-exported validateAPIKey.
albertoelias-crossmint
deleted the
albertoe/server-auth-scoped-cookies
branch
November 5, 2026 23:03
4 of 5 tasks
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.
fix(server-sdk): read and write project-scoped auth cookies
Problem
A developer signs a user in with
@crossmint/client-sdk-auth(1.3.4 or later) and callscrossmintAuth.getSession(request)in their server code. It throwsFailed to get sessionorNo auth material found, even though the user is signed in.The client now stores the session in cookies named after the project:
crossmint-jwt-<projectId>andcrossmint-refresh-token-<projectId>. The server SDK still looks forcrossmint-jwtandcrossmint-refresh-token, so it never finds them. The other direction breaks too: a custom refresh route that stores its cookies through the server SDK writes names the client never reads, so the refreshed session is lost.Today the only way out is to read the scoped cookies yourself and pass
{ jwt, refreshToken }togetSession, which the README does not tell you to do. In Next.js Server Components there is no request object, so you also have to know the scoped names.What this PR does
getSession(request),handleCustomRefreshandlogoutread the project-scoped cookies. The legacy bare names are used only when neither scoped cookie is present, and the two sets are never mixed (a legacy JWT is never paired with a scoped refresh token).storeAuthMaterialwrites the scoped names and expires the legacy ones.getAuthCookieNames()returns the scoped names, for code with no request object.getScopedCookieNamemoves to@crossmint/common-sdk-auth; the client uses it, so client and server cannot drift.nextjs-ssrexample usegetSession(request)andgetAuthCookieNames().flowchart LR subgraph Before C1[client writes crossmint-jwt-PROJECT] -.never read.-> S1[server reads crossmint-jwt] S1 --> E1[No auth material found] end subgraph After C2[client writes crossmint-jwt-PROJECT] --> S2[server reads scoped name, legacy only if no scoped cookie] S2 --> OK[session] endResult
getSession(request)with client 1.3.4+ cookiesFailed to get sessioncrossmintAuth.getAuthCookieNames()getSession(request)(one line)Unchanged: the
getSession({ jwt, refreshToken })form, JWT audience checks, cookie options, the legacy-only case (still readable).What to check when reviewing
packages/server/src/auth/utils/cookies.ts: source selection. If either scoped cookie is present both values come from the scoped names, otherwise from the legacy names. An empty scoped cookie counts as absent.packages/server/src/auth/CrossmintAuthServer.ts:projectIdis passed to every cookie read and write.apps/auth/nextjs-ssr: the middleware keepsresponse.cookies.setso Next.js hands refreshed cookies to Server Components in the same request.Set-Cookieheaders for the legacy names.CrossmintAuthServer.ts, its test andpackages/server/README.md; whichever merges second takes the other's change (the changes are in different methods and README sections). The open quorum PRs touch wallets code, not these files.Test plan
pnpm --filter @crossmint/server-sdk test:vitest: 75 passed.@crossmint/client-sdk-auth: 32 passed.tsc --noEmitonapps/auth/nextjs-ssr.CrossmintAuthServer.tsfails the getSession and logout scoped-cookie tests; revertingcookies.tsfails 10 of 15 cookie tests.nextjs-ssrexample and reload/and/direct.Checklist
storage.ts, not from this PR)Co-Authored-BylinesRollback
Revert the PR. Cookies written while it was live use the scoped names, which the client already reads; the legacy expiry headers only remove old bare-named cookies.
Closes WAL-13393
🤖 Generated with Claude Code