From 18d82daa7dcacfa59b6481feb698fa946e0a4366 Mon Sep 17 00:00:00 2001 From: Bryan Brooks Date: Wed, 4 Feb 2026 19:29:56 -0600 Subject: [PATCH] Fix TypeScript errors in OIDC callback flow - Add state field to AuthorizationCode type and database schema - Fix oauthService.handleCallback to use URLSearchParams - Add database migration for state column on existing databases --- gateway/src/routes/oidc/authorize.ts | 9 ++++++++- gateway/src/services/database.ts | 15 +++++++++++++-- gateway/src/types/oidc.ts | 1 + 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/gateway/src/routes/oidc/authorize.ts b/gateway/src/routes/oidc/authorize.ts index 95cf60b..589616d 100644 --- a/gateway/src/routes/oidc/authorize.ts +++ b/gateway/src/routes/oidc/authorize.ts @@ -140,6 +140,7 @@ export function createAuthorizeRouter( client_id, redirect_uri, scope: scopeValidation.scopes.join(' '), + state, nonce, code_challenge, code_challenge_method: code_challenge_method as 'S256' | 'plain' | undefined, @@ -427,7 +428,13 @@ export function createAuthorizeRouter( } // Exchange the AT Protocol code for tokens - const callbackResult = await oauthService.handleCallback(code, state, iss || ''); + // Build URLSearchParams from the callback query parameters + const callbackParams = new URLSearchParams(); + callbackParams.set('code', code); + callbackParams.set('state', state); + if (iss) callbackParams.set('iss', iss); + + const callbackResult = await oauthService.handleCallback(callbackParams); if (!callbackResult) { return res.status(500).json({ error: 'server_error', diff --git a/gateway/src/services/database.ts b/gateway/src/services/database.ts index 8939273..c8d95ce 100644 --- a/gateway/src/services/database.ts +++ b/gateway/src/services/database.ts @@ -139,6 +139,7 @@ export class DatabaseService { client_id TEXT NOT NULL, redirect_uri TEXT NOT NULL, scope TEXT NOT NULL, + state TEXT, nonce TEXT, code_challenge TEXT, code_challenge_method TEXT, @@ -154,6 +155,13 @@ export class DatabaseService { CREATE INDEX IF NOT EXISTS idx_auth_codes_expires ON authorization_codes(expires_at); `); + // Add state column if it doesn't exist (migration for existing databases) + try { + this.db.exec('ALTER TABLE authorization_codes ADD COLUMN state TEXT'); + } catch { + // Column already exists + } + // Create refresh tokens table this.db.exec(` CREATE TABLE IF NOT EXISTS refresh_tokens ( @@ -577,14 +585,15 @@ export class DatabaseService { saveAuthorizationCode(code: AuthorizationCode): void { const stmt = this.db.prepare(` - INSERT INTO authorization_codes (code, client_id, redirect_uri, scope, nonce, code_challenge, code_challenge_method, did, handle, user_id, created_at, expires_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + INSERT INTO authorization_codes (code, client_id, redirect_uri, scope, state, nonce, code_challenge, code_challenge_method, did, handle, user_id, created_at, expires_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run( code.code, code.client_id, code.redirect_uri, code.scope, + code.state, code.nonce, code.code_challenge, code.code_challenge_method, @@ -603,6 +612,7 @@ export class DatabaseService { client_id: string; redirect_uri: string; scope: string; + state: string | null; nonce: string | null; code_challenge: string | null; code_challenge_method: 'S256' | 'plain' | null; @@ -619,6 +629,7 @@ export class DatabaseService { client_id: row.client_id, redirect_uri: row.redirect_uri, scope: row.scope, + state: row.state ?? undefined, nonce: row.nonce ?? undefined, code_challenge: row.code_challenge ?? undefined, code_challenge_method: row.code_challenge_method ?? undefined, diff --git a/gateway/src/types/oidc.ts b/gateway/src/types/oidc.ts index 546b13d..0ecfded 100644 --- a/gateway/src/types/oidc.ts +++ b/gateway/src/types/oidc.ts @@ -73,6 +73,7 @@ export interface AuthorizationCode { client_id: string; redirect_uri: string; scope: string; + state?: string; nonce?: string; code_challenge?: string; code_challenge_method?: 'S256' | 'plain'; -- knotmirror 0.0.1