63 lines
1.7 KiB
TypeScript
63 lines
1.7 KiB
TypeScript
import type { MiddlewareHandler } from 'hono'
|
|
import { getCookie, setCookie } from 'hono/cookie'
|
|
import { HTTPException } from 'hono/http-exception'
|
|
|
|
import { getRandomState } from '../../utils/getRandomState'
|
|
import { AuthFlow } from './authFlow'
|
|
|
|
export function googleAuth(options: {
|
|
scope: string[]
|
|
login_hint?: string
|
|
prompt?: 'none' | 'consent' | 'select_account'
|
|
client_id?: string
|
|
client_secret?: string
|
|
}): MiddlewareHandler {
|
|
return async (c, next) => {
|
|
const newState = getRandomState()
|
|
// Create new Auth instance
|
|
const auth = new AuthFlow({
|
|
client_id: options.client_id || (c.env?.GOOGLE_ID as string),
|
|
client_secret: options.client_secret || (c.env?.GOOGLE_SECRET as string),
|
|
redirect_uri: c.req.url.split('?')[0],
|
|
login_hint: options.login_hint,
|
|
prompt: options.prompt,
|
|
scope: options.scope,
|
|
state: newState,
|
|
code: c.req.query('code'),
|
|
token: {
|
|
token: c.req.query('access_token') as string,
|
|
expires_in: Number(c.req.query('expires-in')) as number,
|
|
},
|
|
})
|
|
|
|
// Avoid CSRF attack by checking state
|
|
if (c.req.url.includes('?')) {
|
|
const storedState = getCookie(c, 'state')
|
|
if (c.req.query('state') !== storedState) {
|
|
throw new HTTPException(401)
|
|
}
|
|
}
|
|
|
|
// Redirect to login dialog
|
|
if (!auth.code) {
|
|
setCookie(c, 'state', newState, {
|
|
maxAge: 60 * 10,
|
|
httpOnly: true,
|
|
path: '/',
|
|
// secure: true,
|
|
})
|
|
return c.redirect(auth.redirect())
|
|
}
|
|
|
|
// Retrieve user data from google
|
|
await auth.getUserData()
|
|
|
|
// Set return info
|
|
c.set('token', auth.token)
|
|
c.set('user-google', auth.user)
|
|
c.set('granted-scopes', auth.granted_scopes)
|
|
|
|
await next()
|
|
}
|
|
}
|