feat(graphql-server): Cookie Lifecycle & CSRF Enforcement#1041
Open
theothersideofgod wants to merge 12 commits into
Open
feat(graphql-server): Cookie Lifecycle & CSRF Enforcement#1041theothersideofgod wants to merge 12 commits into
theothersideofgod wants to merge 12 commits into
Conversation
7263419 to
8b29938
Compare
- Add AuthSettings interface for cookie configuration - Add cookie.ts with session/device cookie helpers: - buildCookieOptions() - builds Express cookie options from settings - setSessionCookie() / clearSessionCookie() - setDeviceTokenCookie() / clearDeviceTokenCookie() - Support rememberMe for extended session duration - Parse PostgreSQL interval format for durations Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Intercept auth mutation responses (signIn, signUp, signOut, etc.) - Set constructive_session cookie on successful authentication - Clear session cookie on signOut/revokeSession - Set constructive_device_token cookie for device tracking - Support rememberMe from mutation input variables Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add sessions_module query to get auth_settings table location - Add queryAuthSettings() to fetch settings from tenant DB - Update toApiStructure() to include authSettings - Load auth settings in parallel with RLS module Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cookie-parser and @constructive-io/csrf dependencies - Add CSRF middleware with double-submit cookie pattern - Skip CSRF check for Bearer token authentication - Add auth-cookie middleware to intercept responses - Add CSRF error codes to SAFE_ERROR_CODES allowlist Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cookie.test.ts with 9 tests for cookie helpers - Add auth-cookie.test.ts with 13 tests for middleware - Test session cookie set/clear on auth mutations - Test device token cookie handling - Test rememberMe duration extension Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Test Bearer token authentication skips CSRF - Test GET/HEAD/OPTIONS requests skip CSRF - Test anonymous requests (no session cookie) skip CSRF - Test cookie-authenticated requests require valid CSRF token - Test CSRF token validation (missing, invalid, valid) - Test CSRF token from header and body Refs: constructive-io/constructive-planning#749 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The captcha middleware references this property, so it needs to be included in the AuthSettings type definition. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…v plugin - Replace Express middleware with grafserv processRequest plugin - Fix cookie handling for grafserv streaming responses (buffer parsing) - Handle multiple Set-Cookie headers correctly (array format) - Preserve CSRF cookies when setting session cookies - Fix rememberMe cookie duration logic - Remove old middleware and tests (will add plugin tests separately) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Test preset structure and plugin metadata - Test session cookie on auth mutations (signIn, signUp, etc.) - Test cookie clearing on sign out mutations - Test device token cookie handling - Test CSRF cookie preservation - Test buffer and JSON response handling - Test mutation detection regex patterns Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8b29938 to
3b626b1
Compare
pyramation
reviewed
May 10, 2026
| 'IMMUTABLE_PROPS', | ||
| 'IMMUTABLE_PEOPLESTAMPS', | ||
| 'IMMUTABLE_TIMESTAMPS', | ||
| 'CONST_TYPE_FIELDS_IMMUTABLE', |
pyramation
reviewed
May 10, 2026
| }; | ||
|
|
||
| if (req.token.session_id) { | ||
| pgSettings['jwt.claims.session_id'] = req.token.session_id; |
Contributor
There was a problem hiding this comment.
is this done somewhere else now?
pyramation
reviewed
May 10, 2026
| json: overrides.body || {}, | ||
| }), | ||
| requestContext: { | ||
| expressv4: { |
Contributor
There was a problem hiding this comment.
hey @theothersideofgod I think we may want to look at v5 and see if there's any reason not to upgrade now
…data Restores accidentally deleted code that propagates credential metadata (session_id, access_level, kind) to PostgreSQL via jwt.claims settings. Also restores read_only transaction enforcement for read-only credentials. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Restores accidentally deleted error codes including: - Auth aliases (NOT_AUTHENTICATED, USER_NOT_AUTHENTICATED) - Auth method toggles (SSO_SIGN_IN_DISABLED, etc.) - Rate limiting (TOO_MANY_REQUESTS) - MFA/TOTP codes - Session/API key codes - Entity immutability codes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Restores accidentally deleted captcha middleware that validates reCAPTCHA tokens on sign-up and password-reset operations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.
Summary
Implements server-side cookie management for authentication flows, addressing #749.
constructive_sessioncookie on successful auth mutations (signIn, signUp, SSO, MFA, etc.)Why grafserv Plugin Instead of Express Middleware?
Initially attempted to implement this using Express middleware, but encountered architectural limitations:
Express middleware approach (doesn't work):
The problem: PostGraphile v5 (grafserv) uses streaming responses. The response is serialized to a buffer internally by grafserv and written directly to the stream — it never passes through
res.json(). Express middleware cannot intercept this.grafserv plugin approach (correct solution):
This allows us to modify headers before grafserv sends the response, correctly setting cookies at the right layer.
Key Changes
New Files
graphql/server/src/plugins/auth-cookie-plugin.ts- grafserv plugin for cookie lifecyclegraphql/server/src/plugins/__tests__/auth-cookie-plugin.test.ts- 25 unit testsModified Files
graphql/server/src/middleware/graphile.ts- Wire AuthCookiePreset into PostGraphilegraphql/server/src/middleware/cookie.ts- Fix rememberMe duration logicgraphql/server/src/server.ts- Remove old Express middlewareRemoved Files
graphql/server/src/middleware/auth-cookie.ts- Old Express middleware (didn't work with grafserv streaming)graphql/server/src/middleware/__tests__/auth-cookie.test.ts- Old testsCookie Behavior
constructive_sessioncookie (+constructive_device_tokenif returned)Cookie Attributes
HttpOnly: true(XSS protection)SameSite: Lax(CSRF protection)Path: /MaxAge: 1 hour default, 30 days withrememberMe: trueTest Plan
Related
Closes #749
🤖 Generated with Claude Code