feat: Tier 0 server auth - cookie lifecycle, CSRF, device tokens (backwards-compatible)#1007
Open
pyramation wants to merge 1 commit intomainfrom
Open
feat: Tier 0 server auth - cookie lifecycle, CSRF, device tokens (backwards-compatible)#1007pyramation wants to merge 1 commit intomainfrom
pyramation wants to merge 1 commit intomainfrom
Conversation
…kwards-compatible) - Cookie lifecycle via grafserv processRequest plugin (no monkey-patching) - CookiePlugin intercepts auth mutation responses to set/clear HttpOnly session cookies - Extracts accessToken and deviceId from GraphQL response payloads - Gated by enable_cookie_auth flag (complete no-op when disabled) - CSRF double-submit-cookie protection - Sets CSRF token cookie on every response (when cookie auth enabled) - Validates X-CSRF-Token header on POST for cookie-authenticated requests - Bearer-authenticated requests are exempt (not vulnerable to CSRF) - Gated by enable_cookie_auth + require_csrf_for_auth flags - Feature flags in AuthSettings (all default to false) - enableCookieAuth: enables cookie-based session management - requireCsrfForAuth: enables CSRF validation for cookie-authenticated mutations - tokenSource tracking on Express Request - auth.ts now sets req.tokenSource to 'bearer', 'cookie', or 'none' - CSRF middleware uses this to exempt bearer-authenticated requests - All features gated behind app_auth_settings flags that default to OFF - Server works identically to today when features are disabled - Zero middleware overhead when disabled (early return on flag check)
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
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.
Summary
Adds cookie-based session management and CSRF protection to the GraphQL server, fully gated behind per-tenant
app_auth_settingsflags that default to OFF. When disabled, the server behaves identically to today.Cookie lifecycle (
cookie-plugin.ts): A grafservprocessRequestplugin that intercepts GraphQL responses for auth mutations (signIn, signUp, signOut, etc.) and injectsSet-Cookieheaders to set/clear HttpOnly session cookies and device token cookies. Uses the official grafserv middleware hook — no monkey-patching ofres.writeHead/res.end.CSRF protection (
csrf.ts): Double-submit-cookie pattern. Sets a non-HttpOnly CSRF token cookie; validatesX-CSRF-Tokenheader on POST requests from cookie-authenticated clients. Bearer-authenticated requests are exempt.Feature flags added to
AuthSettings/api.ts:enable_cookie_auth— gates cookie lifecycle + CSRFrequire_csrf_for_auth— allows tenants to opt out of CSRF if neededtokenSourcetracking:auth.tsnow setsreq.tokenSourceto'bearer' | 'cookie' | 'none'so downstream middleware (CSRF) knows whether the request is CSRF-vulnerable.Review & Testing Checklist for Human
api.tsnow SELECTsenable_cookie_authandrequire_csrf_for_authfromapp_auth_settings. Verify the corresponding columns exist (or will be added) in constructive-db before deploying — the server will fail at runtime if they're missing.cookie-plugin.ts:276):result.headersis cast fromRecord<string, string>toRecord<string, string | string[]>to support multiple Set-Cookie values. Verify grafserv's Node adapter passes headers straight towriteHeadwithout intermediate validation that would reject arrays.extractAccessToken/extractDeviceId): Assumes{ data: { operationName: { result?: { accessToken } } } }shape. Verify this matches PostGraphile's actual output for all 10 sign-in mutations listed inAUTH_MUTATIONS_SIGN_IN.protectmiddleware returnsstatus(200)with GraphQL-shaped errors inline, whileerrorHandlerreturnsstatus(403). Confirm this is the intended pattern (the errorHandler appears to only catch errors thrown by other middleware, not from protect itself).Suggested test plan: Enable
enable_cookie_authon a test tenant, run a signIn mutation, and verify theSet-Cookieheader appears in the response with the correct accessToken. Then verify signOut clears the cookie. For CSRF, verify that a cookie-authenticated POST withoutX-CSRF-Tokenreturns the expected error, and that bearer-authenticated POSTs are unaffected.Notes
node:crypto, cookie serialization is hand-rolled to avoid pulling incookie-parseras a server dependency.parseCookieValuehelper in csrf.ts usessplit('=')[1]which would truncate values containing=. This is safe for hex CSRF tokens but would need revisiting if reused for other cookie types.Link to Devin session: https://app.devin.ai/sessions/12acfda2a5434d2686c63515cfeb2610
Requested by: @pyramation