From cc3a991661b91c8b049304c541d2cb7cb3dae830 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Sat, 3 Jan 2026 13:49:23 +1000 Subject: [PATCH] debug: add comprehensive logging to api-keys POST endpoint - Log each step: auth, body parsing, schema validation, encryption, db upsert - Check for API_KEY_ENCRYPTION_SECRET presence before encrypt - Log timing, error details with stack traces - Return specific error messages for each failure point --- apps/web/src/app/api/user/api-keys/route.ts | 134 ++++++++++++++++---- 1 file changed, 107 insertions(+), 27 deletions(-) diff --git a/apps/web/src/app/api/user/api-keys/route.ts b/apps/web/src/app/api/user/api-keys/route.ts index e81ae7b..a1318af 100644 --- a/apps/web/src/app/api/user/api-keys/route.ts +++ b/apps/web/src/app/api/user/api-keys/route.ts @@ -46,58 +46,138 @@ export async function GET(): Promise { * Add or update an API key for a provider */ export async function POST(request: NextRequest): Promise { + const startTime = Date.now(); + console.log('[api-keys] POST request received'); + try { + // Step 1: Auth check + console.log('[api-keys] Checking session...'); const session = await auth.api.getSession({ headers: await headers() }); if (!session?.user?.id) { + console.log('[api-keys] Unauthorized - no session or user id'); return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 }); } + console.log('[api-keys] Session valid for user:', session.user.id); - const body = await request.json(); + // Step 2: Parse request body + console.log('[api-keys] Parsing request body...'); + let body: unknown; + try { + body = await request.json(); + console.log('[api-keys] Body parsed, provider:', (body as { provider?: string })?.provider); + } catch (parseError) { + console.error('[api-keys] Failed to parse JSON body:', parseError); + return NextResponse.json( + { success: false, error: 'Invalid JSON body' }, + { status: 400 } + ); + } + + // Step 3: Validate schema + console.log('[api-keys] Validating schema...'); const parsed = AddApiKeySchema.safeParse(body); if (!parsed.success) { + console.error('[api-keys] Schema validation failed:', parsed.error.flatten()); return NextResponse.json( { success: false, error: 'Invalid request', details: parsed.error.flatten() }, { status: 400 } ); } + console.log('[api-keys] Schema valid, provider:', parsed.data.provider); const { provider, apiKey } = parsed.data; - const { encrypted, iv } = encryptApiKey(apiKey); - const keyHint = getKeyHint(apiKey); + console.log('[api-keys] API key length:', apiKey.length, 'chars'); - const result = await prisma.userApiKey.upsert({ - where: { - userId_provider: { + // Step 4: Encrypt the key + console.log('[api-keys] Encrypting API key...'); + let encrypted: string; + let iv: string; + try { + const hasEncryptionSecret = !!process.env.API_KEY_ENCRYPTION_SECRET; + console.log('[api-keys] API_KEY_ENCRYPTION_SECRET present:', hasEncryptionSecret); + if (!hasEncryptionSecret) { + console.error('[api-keys] CRITICAL: API_KEY_ENCRYPTION_SECRET is not set!'); + return NextResponse.json( + { success: false, error: 'Server configuration error: encryption not configured' }, + { status: 500 } + ); + } + const result = encryptApiKey(apiKey); + encrypted = result.encrypted; + iv = result.iv; + console.log('[api-keys] Encryption successful, encrypted length:', encrypted.length); + } catch (encryptError) { + console.error('[api-keys] Encryption failed:', encryptError); + return NextResponse.json( + { success: false, error: 'Failed to encrypt API key' }, + { status: 500 } + ); + } + + const keyHint = getKeyHint(apiKey); + console.log('[api-keys] Key hint:', keyHint); + + // Step 5: Upsert to database + console.log('[api-keys] Upserting to database...'); + console.log('[api-keys] Where clause: userId_provider =', { userId: session.user.id, provider }); + + let result; + try { + result = await prisma.userApiKey.upsert({ + where: { + userId_provider: { + userId: session.user.id, + provider, + }, + }, + create: { userId: session.user.id, provider, + encryptedKey: encrypted, + keyIv: iv, + keyHint, }, - }, - create: { - userId: session.user.id, - provider, - encryptedKey: encrypted, - keyIv: iv, - keyHint, - }, - update: { - encryptedKey: encrypted, - keyIv: iv, - keyHint, - }, - select: { - provider: true, - keyHint: true, - createdAt: true, - updatedAt: true, - }, - }); + update: { + encryptedKey: encrypted, + keyIv: iv, + keyHint, + }, + select: { + provider: true, + keyHint: true, + createdAt: true, + updatedAt: true, + }, + }); + console.log('[api-keys] Upsert successful:', result.provider, 'updated at', result.updatedAt); + } catch (dbError) { + console.error('[api-keys] Database upsert failed:', dbError); + console.error('[api-keys] Database error details:', { + name: (dbError as Error).name, + message: (dbError as Error).message, + stack: (dbError as Error).stack?.slice(0, 500), + }); + return NextResponse.json( + { success: false, error: 'Failed to save API key to database' }, + { status: 500 } + ); + } + + const duration = Date.now() - startTime; + console.log(`[api-keys] POST completed successfully in ${duration}ms`); return NextResponse.json({ success: true, data: result, }); } catch (error) { - console.error('Failed to save API key:', error); + const duration = Date.now() - startTime; + console.error(`[api-keys] Unexpected error after ${duration}ms:`, error); + console.error('[api-keys] Error details:', { + name: (error as Error).name, + message: (error as Error).message, + stack: (error as Error).stack?.slice(0, 500), + }); return NextResponse.json({ success: false, error: 'Failed to save API key' }, { status: 500 }); } }