You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

178 lines
5.5 KiB
TypeScript

import type { APIContext } from 'astro'
import {
checkUserExists,
createLoginLog,
createSession,
createUser,
saveOauthToken,
updateOauthToken,
} from '../../../../lib/auth'
export async function GET({ request, clientAddress, cookies }: APIContext) {
const code = new URL(request.url).searchParams?.get('code')
const state = new URL(request.url).searchParams?.get('state')
const storedState = cookies.get('google_oauth_state')?.value
const codeVerifier = cookies.get('google_code_challenge')?.value
if (storedState !== state || !codeVerifier || !code) {
cookies.delete('google_oauth_state', { path: '/' })
cookies.delete('google_code_challenge', { path: '/' })
console.log('state mismatch')
return new Response(null, {
status: 302,
headers: {
Location: '/login?error=Server+Error',
},
})
}
try {
const tokenUrl = 'https://www.googleapis.com/oauth2/v4/token'
const formData = new URLSearchParams()
formData.append('grant_type', 'authorization_code')
formData.append('client_id', import.meta.env.OAUTH_GOOGLE_CLIENT_ID)
formData.append('client_secret', import.meta.env.OAUTH_GOOGLE_CLIENT_SECRET)
formData.append('redirect_uri', import.meta.env.OAUTH_GOOGLE_CALLBACK_URL)
formData.append('code', code)
formData.append('code_verifier', codeVerifier)
console.log('fetching token', formData)
const fetchToken = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData,
})
const fetchTokenRes = await fetchToken.json()
console.log('fetchTokenRes', fetchTokenRes)
const fetchUser = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: { Authorization: `Bearer ${fetchTokenRes.access_token}` },
})
const fetchUserRes = await fetchUser.json()
console.log('fetchUserRes', fetchUserRes)
const userExists = await checkUserExists({
email: fetchUserRes.email,
strategy: 'google',
})
console.log('userExists', userExists)
if (!userExists) {
const { userId } = await createUser({
email: fetchUserRes.email,
fullName: fetchUserRes.name,
profilePhoto: fetchUserRes.picture,
userName: fetchUserRes.email.split('@')[0],
})
await saveOauthToken({
userId: userId,
strategy: 'google',
accessToken: fetchTokenRes.access_token,
refreshToken: fetchTokenRes.refresh_token,
})
const { sessionId } = await createSession({
userId: userId,
})
// log
await createLoginLog({
sessionId,
userAgent: request.headers.get('user-agent'),
userId: userId,
ip: clientAddress ?? 'dev',
})
cookies.delete('google_oauth_state', { path: '/' })
cookies.delete('google_code_challenge', { path: '/' })
cookies.set('app_auth_token', sessionId, {
path: '/',
httpOnly: true,
sameSite: 'lax',
secure: import.meta.env.PROD,
})
return new Response(null, {
status: 302,
headers: {
Location: '/profile',
},
})
} else {
if (userExists.oauthTokens.length > 0) {
// oauth strategy exists
// update token
await updateOauthToken({
userId: userExists.id,
strategy: 'google',
accessToken: fetchTokenRes.access_token,
refreshToken: fetchTokenRes.refresh_token,
})
} else {
await saveOauthToken({
userId: userExists.id,
strategy: 'google',
accessToken: fetchTokenRes.access_token,
refreshToken: fetchTokenRes.refresh_token,
})
}
const { sessionId } = await createSession({
userId: userExists.id,
})
await createLoginLog({
sessionId,
userAgent: request.headers.get('user-agent'),
userId: userExists.id,
ip: clientAddress ?? 'dev',
})
cookies.delete('google_oauth_state', { path: '/' })
cookies.delete('google_code_challenge', { path: '/' })
cookies.set('app_auth_token', sessionId, {
path: '/',
httpOnly: true,
sameSite: 'lax',
secure: import.meta.env.PROD,
})
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
})
}
} catch (error) {
cookies.delete('google_oauth_state', { path: '/' })
cookies.delete('google_code_challenge', { path: '/' })
console.error(error)
return new Response(null, {
status: 302,
headers: {
Location: '/login?error=Server+Error',
},
})
}
}