Skip to content

Commit 1661aa9

Browse files
refactor(api-keys): drop custom CSRF and Bearer token checks; migrate to NextAuth server session to standardize auth flow and reduce surface area.
🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
1 parent 7aa8c53 commit 1661aa9

File tree

1 file changed

+12
-55
lines changed

1 file changed

+12
-55
lines changed

web/src/app/api/api-keys/route.ts

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,15 @@ import type { NextRequest } from 'next/server'
1010

1111
import { authOptions } from '@/app/api/auth/[...nextauth]/auth-options'
1212
import { logger } from '@/util/logger'
13-
import { siteConfig } from '@/lib/constant'
14-
15-
function isSameOrigin(request: NextRequest) {
16-
try {
17-
const base = new URL(siteConfig.url()).origin
18-
const origin = request.headers.get('origin')
19-
const referer = request.headers.get('referer')
20-
if (origin && new URL(origin).origin === base) return true
21-
if (referer && new URL(referer).origin === base) return true
22-
} catch {}
23-
return false
24-
}
2513

2614
export async function GET(request: NextRequest) {
27-
const authHeader = request.headers.get('authorization')
28-
let userId: string | null = null
29-
if (authHeader && authHeader.startsWith('Bearer ')) {
30-
const authToken = authHeader.split(' ')[1]
31-
const user = await db.query.session.findFirst({
32-
where: eq(schema.session.sessionToken, authToken),
33-
columns: { userId: true },
34-
})
35-
userId = user?.userId ?? null
36-
} else {
37-
const session = await getServerSession(authOptions)
38-
userId = session?.user?.id ?? null
39-
}
40-
41-
if (!userId) {
15+
const session = await getServerSession(authOptions)
16+
if (!session?.user?.id) {
4217
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
4318
}
4419

20+
const userId = session.user.id
21+
4522
try {
4623
// Get PAT sessions (type='pat', no fingerprint)
4724
// CLI sessions are type='cli' and have fingerprint_id
@@ -79,45 +56,25 @@ export async function GET(request: NextRequest) {
7956
}
8057

8158
export async function POST(request: NextRequest) {
59+
const session = await getServerSession(authOptions)
60+
if (!session?.user?.id) {
61+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
62+
}
63+
64+
const userId = session.user.id
65+
8266
const reqJson = await request.json()
8367
const parsedJson = z
8468
.object({
8569
name: z.string().min(1, 'Token name cannot be empty').optional(),
8670
expiresInDays: z.number().min(1).max(365).optional().default(365),
87-
authToken: z.string().optional(),
8871
})
8972
.safeParse(reqJson)
9073
if (!parsedJson.success) {
9174
return NextResponse.json({ error: 'Invalid request body' }, { status: 400 })
9275
}
9376

94-
// Enforce CSRF for browser requests (skip for CLI auth)
95-
const hasCliAuth =
96-
!!parsedJson.data.authToken ||
97-
(request.headers.get('authorization') || '').startsWith('Bearer ')
98-
if (!hasCliAuth && !isSameOrigin(request)) {
99-
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
100-
}
101-
102-
const { name, expiresInDays, authToken } = parsedJson.data
103-
104-
// Resolve userId from either provided authToken (CLI) or cookie session (web)
105-
let userId: string | null = null
106-
if (authToken) {
107-
// authToken should already include cb-pat- prefix
108-
const user = await db.query.session.findFirst({
109-
where: eq(schema.session.sessionToken, authToken),
110-
columns: { userId: true },
111-
})
112-
userId = user?.userId ?? null
113-
} else {
114-
const session = await getServerSession(authOptions)
115-
userId = session?.user?.id ?? null
116-
}
117-
118-
if (!userId) {
119-
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
120-
}
77+
const { name, expiresInDays } = parsedJson.data
12178

12279
try {
12380
// Generate a new session token for the PAT with cb-pat- prefix baked in

0 commit comments

Comments
 (0)