Skip to content

Instantly share code, notes, and snippets.

@HarleySalas
Created July 24, 2024 14:10
Show Gist options
  • Save HarleySalas/2116aef5f4896c9053bff74f2aadd66c to your computer and use it in GitHub Desktop.
Save HarleySalas/2116aef5f4896c9053bff74f2aadd66c to your computer and use it in GitHub Desktop.
import { AUTH_REDIRECT_COOKIE, COLLECTION_SLUG } from '@/constants'
import { lucia } from '@/lib/lucia'
import { authProviders } from '@/lib/lucia/providers'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import config from '@/payload.config'
import { OAuth2RequestError } from 'arctic'
import { cookies } from 'next/headers'
import type { NextRequest } from 'next/server'
export async function GET(
request: NextRequest,
{ params }: { params: { provider: keyof typeof authProviders } },
): Promise<Response> {
const url = new URL(request.url)
const provider = String(params?.provider) as keyof typeof authProviders
const code = url.searchParams.get('code')
const state = url.searchParams.get('state')
const storedState = cookies().get(authProviders[provider].cookieName)?.value ?? null
const providerConfig = authProviders[provider] ?? null
if (!code || !state || !storedState || state !== storedState) {
return new Response(null, { status: 400, statusText: 'Invalid OAuth State...' })
}
try {
const payload = await getPayloadHMR({ config })
const { data, email } = await providerConfig.exchangeCodeForUser(request)
let user
const { docs } = await payload.find({
collection: COLLECTION_SLUG.CUSTOMER,
where: {
and: [
{
provider: {
equals: data.provider,
},
},
{
providerAccountId: {
equals: data.providerAccountId,
},
},
],
},
})
user = docs?.at(0) || null
if (user) {
const updatedUser = await payload.update({
collection: COLLECTION_SLUG.CUSTOMER,
id: user.id,
data: {
email: email,
/** @ts-ignore */
metadata: data.metadata,
},
})
user = updatedUser
} else {
user = await payload.create({
collection: COLLECTION_SLUG.CUSTOMER,
data: {
email: email,
password: 'testing123',
provider: data.provider,
providerAccountId: data.providerAccountId,
metadata: data.metadata,
},
})
}
if (!user) {
throw new Error('Failed to create or update user...')
}
//ignored, because payload incorrectly types the update operation as a bulk update, even when it's a single update
/** @ts-ignore */
const session = await lucia.createSession(user.id, {})
const sessionCookie = lucia.createSessionCookie(session.id)
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes)
const redirectTo = cookies().get(AUTH_REDIRECT_COOKIE)?.value ?? null
cookies().delete(AUTH_REDIRECT_COOKIE)
return new Response(null, {
status: 302,
headers: {
Location: redirectTo ? decodeURIComponent(redirectTo) : '/',
},
})
} catch (error) {
console.error(error)
if (error instanceof OAuth2RequestError) {
return new Response(null, {
status: 400,
})
}
return new Response(null, {
status: 500,
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment