Files
sim/apps/sim/app/api/auth/oauth2/authorize-params/route.ts
Waleed 3fa4bb4c12 feat(auth): add OAuth 2.1 provider for MCP connector support (#3274)
* feat(auth): add OAuth 2.1 provider for MCP connector support

* fix(auth): rename redirect_u_r_ls column to redirect_urls

* chore(db): regenerate oauth migration with correct column naming

* fix(auth): reorder CORS headers and handle missing redirectURI

* fix(auth): redirect to login without stale callbackUrl on account switch

* chore: run lint

* fix(auth): override credentials header on OAuth CORS entries

* fix(auth): preserve OAuth flow when switching accounts on consent page

* fix(auth): add session and user-id checks to authorize-params endpoint

* fix(auth): add expiry check, credentials, MCP CORS, and scope in WWW-Authenticate

* feat(mcp): add tool annotations for Connectors Directory compliance
2026-02-20 15:56:15 -08:00

60 lines
1.8 KiB
TypeScript

import { db } from '@sim/db'
import { verification } from '@sim/db/schema'
import { and, eq, gt } from 'drizzle-orm'
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
/**
* Returns the original OAuth authorize parameters stored in the verification record
* for a given consent code. Used by the consent page to reconstruct the authorize URL
* when switching accounts.
*/
export async function GET(request: NextRequest) {
const session = await getSession()
if (!session?.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const consentCode = request.nextUrl.searchParams.get('consent_code')
if (!consentCode) {
return NextResponse.json({ error: 'consent_code is required' }, { status: 400 })
}
const [record] = await db
.select({ value: verification.value })
.from(verification)
.where(and(eq(verification.identifier, consentCode), gt(verification.expiresAt, new Date())))
.limit(1)
if (!record) {
return NextResponse.json({ error: 'Invalid or expired consent code' }, { status: 404 })
}
const data = JSON.parse(record.value) as {
clientId: string
redirectURI: string
scope: string[]
userId: string
codeChallenge: string
codeChallengeMethod: string
state: string | null
nonce: string | null
}
if (data.userId !== session.user.id) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
}
return NextResponse.json({
client_id: data.clientId,
redirect_uri: data.redirectURI,
scope: data.scope.join(' '),
code_challenge: data.codeChallenge,
code_challenge_method: data.codeChallengeMethod,
state: data.state,
nonce: data.nonce,
response_type: 'code',
})
}