83 lines
2.0 KiB
TypeScript
83 lines
2.0 KiB
TypeScript
import { OAuth2Client } from 'google-auth-library'
|
|
|
|
const client = new OAuth2Client(
|
|
process.env.GOOGLE_CLIENT_ID,
|
|
process.env.GOOGLE_CLIENT_SECRET,
|
|
process.env.GOOGLE_REDIRECT_URI ||
|
|
`${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:4023'}/api/auth/google/callback`
|
|
)
|
|
|
|
export interface GoogleUserInfo {
|
|
id: string
|
|
email: string
|
|
name: string
|
|
picture?: string
|
|
given_name?: string
|
|
family_name?: string
|
|
verified_email: boolean
|
|
}
|
|
|
|
export const getGoogleAuthURL = () => {
|
|
const scopes = ['openid', 'profile', 'email']
|
|
|
|
return client.generateAuthUrl({
|
|
access_type: 'offline',
|
|
scope: scopes,
|
|
prompt: 'consent',
|
|
state: 'google_oauth',
|
|
})
|
|
}
|
|
|
|
export const getGoogleUser = async (code: string): Promise<GoogleUserInfo> => {
|
|
const { tokens } = await client.getToken(code)
|
|
|
|
if (!tokens.access_token) {
|
|
throw new Error('No access token received from Google')
|
|
}
|
|
|
|
// Get user info from Google
|
|
const response = await fetch(
|
|
`https://www.googleapis.com/oauth2/v2/userinfo?access_token=${tokens.access_token}`
|
|
)
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch user info from Google')
|
|
}
|
|
|
|
const userInfo = (await response.json()) as GoogleUserInfo
|
|
|
|
if (!userInfo.verified_email) {
|
|
throw new Error('Google email not verified')
|
|
}
|
|
|
|
return userInfo
|
|
}
|
|
|
|
export const verifyGoogleToken = async (token: string): Promise<GoogleUserInfo> => {
|
|
try {
|
|
const ticket = await client.verifyIdToken({
|
|
idToken: token,
|
|
audience: process.env.GOOGLE_CLIENT_ID,
|
|
})
|
|
|
|
const payload = ticket.getPayload()
|
|
if (!payload) {
|
|
throw new Error('Invalid Google token payload')
|
|
}
|
|
|
|
return {
|
|
id: payload.sub,
|
|
email: payload.email!,
|
|
name: payload.name!,
|
|
picture: payload.picture,
|
|
given_name: payload.given_name,
|
|
family_name: payload.family_name,
|
|
verified_email: payload.email_verified || false,
|
|
}
|
|
} catch (error) {
|
|
throw new Error('Failed to verify Google token')
|
|
}
|
|
}
|
|
|
|
export { client as googleOAuthClient }
|