fix(@hono/oauth-providers): Added missing URL parameters prompt, login_hint, and access_type in the Google OAuth provider. (#697)

* fix: google provider attach custom parameters

* fix format

* Create rare-fishes-sort.md
pull/698/head
Taishi Naritomi 2024-08-19 09:23:23 +09:00 committed by GitHub
parent 2528a9fd63
commit c3b67a6c3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 42 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
"@hono/oauth-providers": patch
---
fix(@hono/oauth-providers): google provider attach custom parameters

View File

@ -14,6 +14,7 @@ type GoogleAuthFlow = {
state?: string
login_hint?: string
prompt?: 'none' | 'consent' | 'select_account'
access_type?: 'offline' | 'online'
}
export class AuthFlow {
@ -28,6 +29,7 @@ export class AuthFlow {
prompt: 'none' | 'consent' | 'select_account' | undefined
user: Partial<GoogleUser> | undefined
granted_scopes: string[] | undefined
access_type: 'offline' | 'online' | undefined
constructor({
client_id,
@ -39,6 +41,7 @@ export class AuthFlow {
state,
code,
token,
access_type,
}: GoogleAuthFlow) {
this.client_id = client_id
this.client_secret = client_secret
@ -51,6 +54,7 @@ export class AuthFlow {
this.token = token
this.user = undefined
this.granted_scopes = undefined
this.access_type = access_type
if (
this.client_id === undefined ||
@ -71,6 +75,9 @@ export class AuthFlow {
include_granted_scopes: true,
scope: this.scope.join(' '),
state: this.state,
prompt: this.prompt,
login_hint: this.login_hint,
access_type: this.access_type,
})
return `https://accounts.google.com/o/oauth2/v2/auth?${parsedOptions}`
}

View File

@ -1,6 +1,6 @@
import type { MiddlewareHandler } from 'hono'
import { getCookie, setCookie } from 'hono/cookie'
import { env } from 'hono/adapter'
import { getCookie, setCookie } from 'hono/cookie'
import { HTTPException } from 'hono/http-exception'
import { getRandomState } from '../../utils/getRandomState'
@ -10,6 +10,7 @@ export function googleAuth(options: {
scope: string[]
login_hint?: string
prompt?: 'none' | 'consent' | 'select_account'
access_type?: 'online' | 'offline'
client_id?: string
client_secret?: string
state?: string
@ -24,6 +25,7 @@ export function googleAuth(options: {
redirect_uri: options.redirect_uri || c.req.url.split('?')[0],
login_hint: options.login_hint,
prompt: options.prompt,
access_type: options.access_type,
scope: options.scope,
state: newState,
code: c.req.query('code'),

View File

@ -70,6 +70,18 @@ describe('OAuth Middleware', () => {
redirect_uri: 'http://localhost:3000/google',
})(c, next)
})
app.use('/google-custom-params', (c, next) => {
return googleAuth({
client_id,
client_secret,
scope: ['openid', 'email', 'profile'],
redirect_uri: 'http://localhost:3000/google',
login_hint: 'test-login-hint',
prompt: 'select_account',
state: 'test-state',
access_type: 'offline',
})(c, next)
})
app.get('/google', (c) => {
const user = c.get('user-google')
const token = c.get('token')
@ -356,6 +368,21 @@ describe('OAuth Middleware', () => {
expect(redirectUrl.searchParams.get('redirect_uri')).toBe('http://localhost:3000/google')
})
it('Should attach custom parameters', async () => {
const res = await app.request('/google-custom-params')
expect(res).not.toBeNull()
expect(res.status).toBe(302)
const redirectLocation = res.headers.get('location')!
const redirectUrl = new URL(redirectLocation)
expect(redirectUrl.searchParams.get('redirect_uri')).toBe('http://localhost:3000/google')
expect(redirectUrl.searchParams.get('scope')).toBe('openid email profile')
expect(redirectUrl.searchParams.get('login_hint')).toBe('test-login-hint')
expect(redirectUrl.searchParams.get('prompt')).toBe('select_account')
expect(redirectUrl.searchParams.get('state')).toBe('test-state')
expect(redirectUrl.searchParams.get('access_type')).toBe('offline')
})
it('Prevent CSRF attack', async () => {
const res = await app.request(`/google?code=${dummyCode}&state=malware-state`)