feat(oauth): OAuth identity sign-in with cross-origin token exchange#1141
feat(oauth): OAuth identity sign-in with cross-origin token exchange#1141theothersideofgod wants to merge 12 commits into
Conversation
- Add emailVerified field to OAuthProfile - Add emailVerified mapping to providers - Track email verification for GitHub
Implement OAuth routes that wire the @constructive-io/oauth package to the database's sign_in_identity/sign_up_identity private functions. Routes: - GET /auth/providers - list configured providers - GET /auth/:provider - initiate OAuth flow - GET /auth/:provider/callback - handle OAuth callback Features: - Signed state with HMAC for CSRF protection and redirect_uri storage - Shadow attack defense: reject unverified emails for auto-signup - MFA flow: redirect to /auth/mfa when mfa_required=true - Session and device token cookie setting Refs: #750 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- OAuth middleware unit tests - Multi-tenant isolation tests
- Read OAuth provider config from identity_providers table - Resolve encrypted_secrets schema from metaschema - Use encrypted_secrets.get() to decrypt client secret
Instead of using a static baseUrl config, dynamically derive it from
req.protocol and req.get('host'). This ensures each tenant's OAuth
callback URL matches their subdomain.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /error route to prevent conflict with /:provider
- Use next('router') to skip entire router for /error
- Correct parameter order for sign_up_identity call
- Make cookie and token modes mutually exclusive - Set JWT context for correct session user-agent/origin - Use dedicated db client for sign_in_identity JWT context - Use session-level set_config for JWT context
OAUTH_SECRET is now required for server to start. No fallback, no warning - just fail fast if not configured. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Code Review — OAuth Identity Sign-InNice work on the overall architecture here. The secrets handling (encrypted_secrets module for client secrets, HMAC-SHA256 state signing with timing-safe comparison), the database integration (identity provider allowlist guard, proper JWT context on dedicated db client), and the cross-origin vs same-origin token flow are all well-designed. PR #1117 (Cookie lifecycle & CSRF) has been reviewed and is good to merge. This PR (#1141) needs the following fixes before we can merge it. Once addressed, please rebase onto Must Fix1. Test env var mismatch — callback tests don't actually validate callback logic
// Test sets:
process.env.OAUTH_STATE_SECRET = 'test-secret-key-for-testing';
// But the code reads (oauth.ts line 34):
const secret = process.env.OAUTH_SECRET;Wrong env var name. Fix: Change 2. Dead code — standalone
|
Change OAUTH_STATE_SECRET to OAUTH_SECRET to match the production code. This fixes 10 failing tests that were incorrectly hitting INVALID_STATE instead of testing the actual callback logic. Co-Authored-By: Claude <noreply@anthropic.com>
These functions used pool.query() directly without JWT context setup. The actual callback handler uses a dedicated dbClient with proper set_config calls for user_agent and origin audit fields. Co-Authored-By: Claude <noreply@anthropic.com>
Remove the 'message' query parameter that exposed raw error.message content (potentially database errors, function names, or internal details) in the redirect URL. The generic 'CALLBACK_FAILED' error code is sufficient for the frontend, and detailed errors are still logged server-side. Co-Authored-By: Claude <noreply@anthropic.com>
Move OAuthRoutesConfig interface to graphql/types package and add oauth property to ConstructiveOptions, removing the need for `(opts as any).oauth` type assertion. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Code Review ResponseThanks for the detailed review @devin-ai-integration! Must Fix ✅ All Done
Should Fix
Follow-Up Items (Separate PRs)
Ready for re-review. All Must Fix items are complete. |
Summary
Implements OAuth identity sign-in with support for GitHub/Google/Apple providers, cross-origin token exchange, and multi-tenant support.
Based on #749 (Cookie/CSRF infrastructure).
Architecture
Commits
Cookie/CSRF Infrastructure (#749)
7f9b7a4960eefc2f1f37bd133c29e393e6bb1a0c73b1190bcc3310d29b0e35fOAuth Sign-In (#750)
5be361f6c752b69c147f6563c5b9d5646e7dda188ad200ab5b22a513Key Design
1. Cross-Origin vs Same-Origin
signInCrossOriginfor access_token2. Security
OAUTH_SECRETenvironment variable required3. Multi-Tenant
identity_providerstable)encrypted_secrets)Environment Variables
OAUTH_SECRETTests
oauth.test.ts(939 lines) - middleware, multi-tenant isolation, error handling🤖 Generated with Claude Code