Skip to content

feat(graphile): propagate jwt.claims.session_id to pgSettings#1014

Merged
pyramation merged 1 commit intomainfrom
feat/graphile-session-id-claim
Apr 19, 2026
Merged

feat(graphile): propagate jwt.claims.session_id to pgSettings#1014
pyramation merged 1 commit intomainfrom
feat/graphile-session-id-claim

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

Summary

Pairs with constructive-io/constructive-db#908, which adds session_id to the RETURNS TABLE of authenticate() and authenticate_strict(). Now that req.token.session_id is populated by the auth middleware (it falls out of result.rows[0] in <ref_snippet file="/home/ubuntu/repos/constructive/graphql/server/src/middleware/auth.ts" lines="118-138" />), surface it as jwt.claims.session_id on the request transaction so jwt_private.current_session_id() returns a real value inside PL/pgSQL.

Without this, every session-scoped DB procedure silently matched zero rows:

  • verify_password, verify_totpUPDATE sessions SET last_password_verified = now() WHERE id = NULL is a no-op, so the subsequent require_step_up check still fails.
  • sign_out, revoke_session, extend_token_expires, all webauthn_* flows — same pattern.

The most user-visible break was MFA step-up: completing a password challenge did nothing.

Changes

  • <ref_file file="/home/ubuntu/repos/constructive/graphql/server/src/middleware/types.ts" /> — add session_id?: string to ConstructiveAPIToken.
  • <ref_file file="/home/ubuntu/repos/constructive/graphql/server/src/middleware/graphile.ts" /> — set pgSettings['jwt.claims.session_id'] when present.

Guarded with an if (req.token.session_id) so this PR is safe to ship before the DB-side PR rolls out: if authenticate() still returns the old 4-column shape, req.token.session_id will be undefined and the GUC simply isn't set (same behavior as today). Once the DB-side ships, the GUC starts flowing automatically.

Review & Testing Checklist for Human

Risk: yellow — one-line change, but it's on the auth hot path.

  • Confirm the companion DB PR constructive-io/constructive-db#908 is deployed to any environment where you verify this change; otherwise req.token.session_id stays undefined and this PR is a no-op (safe, but not useful).
  • Sign in, then call SELECT current_setting('jwt.claims.session_id', true) via GraphQL/psql inside a request transaction and confirm it matches the session row for the current login.
  • Exercise an MFA step-up flow end-to-end (password challenge → privileged action) to confirm require_step_up now sees the elevation.

Notes

  • ConstructiveAPIToken already had [key: string]: unknown, so typing session_id?: string is additive and doesn't break any consumer.
  • No new config, no migration, no env var.

Link to Devin session: https://app.devin.ai/sessions/f0c49af3f7f24bf39e5ad0fd74f25c07
Requested by: @pyramation

Pairs with constructive-io/constructive-db#908, which adds session_id
to the RETURNS TABLE of authenticate() and authenticate_strict().
Now that req.token.session_id is populated by the auth middleware,
surface it as "jwt.claims.session_id" on the request transaction so
jwt_private.current_session_id() returns a real value.

Without this, every session-scoped DB procedure (sign_out,
revoke_session, extend_token_expires, verify_password, verify_totp,
require_step_up, webauthn_*) silently matches zero rows — the MFA
step-up window in particular never elevates because verify_password
updates sessions.last_password_verified WHERE id = NULL.

- types.ts: add session_id?: string to ConstructiveAPIToken
- graphile.ts: set pgSettings['jwt.claims.session_id'] when present
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@pyramation pyramation merged commit d4360ca into main Apr 19, 2026
51 checks passed
@pyramation pyramation deleted the feat/graphile-session-id-claim branch April 19, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant