Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: request token #147

Merged
merged 11 commits into from
Sep 2, 2024
41 changes: 17 additions & 24 deletions src/runtime/server/lib/oauth/auth0.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { H3Event } from 'h3'
import { eventHandler, getQuery, getRequestURL, sendRedirect } from 'h3'
import { withQuery, parsePath } from 'ufo'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleMissingConfiguration, handleAccessTokenErrorResponse } from '../utils'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig } from '#imports'
import type { OAuthConfig } from '#auth-utils'

Expand Down Expand Up @@ -70,16 +70,17 @@ export function oauthAuth0EventHandler({ config, onSuccess, onError }: OAuthConf
config = defu(config, useRuntimeConfig(event).oauth?.auth0, {
authorizationParams: {},
}) as OAuthAuth0Config
const { code } = getQuery(event)

if (!config.clientId || !config.clientSecret || !config.domain) {
return handleMissingConfiguration(event, 'auth0', ['clientId', 'clientSecret', 'domain'], onError)
}
const authorizationURL = `https://${config.domain}/authorize`
const tokenURL = `https://${config.domain}/oauth/token`

const redirectURL = config.redirectURL || getRequestURL(event).href
if (!code) {
const query = getQuery<{ code?: string }>(event)
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || ['openid', 'offline_access']
if (config.emailRequired && !config.scope.includes('email')) {
config.scope.push('email')
Expand All @@ -100,25 +101,17 @@ export function oauthAuth0EventHandler({ config, onSuccess, onError }: OAuthConf
)
}

// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(
tokenURL as string,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: {
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: parsePath(redirectURL).pathname,
code,
},
const tokens = await requestAccessToken(tokenURL as string, {
headers: {
'Content-Type': 'application/json',
},
body: {
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: redirectURL,
code: query.code,
},
).catch((error) => {
return { error }
})

if (tokens.error) {
Expand Down
47 changes: 18 additions & 29 deletions src/runtime/server/lib/oauth/battledotnet.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { randomUUID } from 'node:crypto'
import type { H3Event } from 'h3'
import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from 'h3'
import { withQuery, parsePath } from 'ufo'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleAccessTokenErrorResponse, handleMissingConfiguration } from '../utils'
import { useRuntimeConfig } from '#imports'
import { randomUUID } from 'uncrypto'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig, createError } from '#imports'
import type { OAuthConfig } from '#auth-utils'

export interface OAuthBattledotnetConfig {
Expand Down Expand Up @@ -62,8 +62,7 @@ export function oauthBattledotnetEventHandler({ config, onSuccess, onError }: OA
authorizationParams: {},
}) as OAuthBattledotnetConfig

const query = getQuery(event)
const { code } = query
const query = getQuery<{ code?: string, error?: string }>(event)

if (query.error) {
const error = createError({
Expand All @@ -80,8 +79,9 @@ export function oauthBattledotnetEventHandler({ config, onSuccess, onError }: OA
)
}

const redirectURL = config.redirectURL || getRequestURL(event).href
if (!code) {
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || ['openid']
config.region = config.region || 'EU'

Expand Down Expand Up @@ -109,27 +109,16 @@ export function oauthBattledotnetEventHandler({ config, onSuccess, onError }: OA
config.scope.push('openid')
}

const authCode = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString('base64')

// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(
config.tokenURL as string,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${authCode}`,
},
params: {
code,
grant_type: 'authorization_code',
scope: config.scope.join(' '),
redirect_uri: parsePath(redirectURL).pathname,
},
const tokens = await requestAccessToken(config.tokenURL as string, {
headers: {
Authorization: `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString('base64')}`,
},
params: {
grant_type: 'authorization_code',
scope: config.scope.join(' '),
redirect_uri: redirectURL,
code: query.code,
},
).catch((error) => {
return { error }
})

if (tokens.error) {
Expand Down
31 changes: 15 additions & 16 deletions src/runtime/server/lib/oauth/cognito.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { H3Event } from 'h3'
import { eventHandler, getQuery, getRequestURL, sendRedirect } from 'h3'
import { withQuery, parsePath } from 'ufo'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleAccessTokenErrorResponse, handleMissingConfiguration } from '../utils'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig } from '#imports'
import type { OAuthConfig } from '#auth-utils'

Expand Down Expand Up @@ -54,7 +54,6 @@ export function oauthCognitoEventHandler({ config, onSuccess, onError }: OAuthCo
config = defu(config, useRuntimeConfig(event).oauth?.cognito, {
authorizationParams: {},
}) as OAuthCognitoConfig
const { code } = getQuery(event)

if (!config.clientId || !config.clientSecret || !config.userPoolId || !config.region) {
return handleMissingConfiguration(event, 'cognito', ['clientId', 'clientSecret', 'userPoolId', 'region'], onError)
Expand All @@ -65,8 +64,10 @@ export function oauthCognitoEventHandler({ config, onSuccess, onError }: OAuthCo
const authorizationURL = `https://${urlBase}/oauth2/authorize`
const tokenURL = `https://${urlBase}/oauth2/token`

const redirectURL = config.redirectURL || getRequestURL(event).href
if (!code) {
const query = getQuery<{ code?: string }>(event)
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || ['openid', 'profile']
// Redirect to Cognito login page
return sendRedirect(
Expand All @@ -81,20 +82,18 @@ export function oauthCognitoEventHandler({ config, onSuccess, onError }: OAuthCo
)
}

// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(
const tokens = await requestAccessToken(
tokenURL as string,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
body: {
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: redirectURL,
code: query.code,
},
body: `grant_type=authorization_code&client_id=${config.clientId}&client_secret=${config.clientSecret}&redirect_uri=${parsePath(redirectURL).pathname}&code=${code}`,
},
).catch((error) => {
return { error }
})
)

if (tokens.error) {
return handleAccessTokenErrorResponse(event, 'cognito', tokens, onError)
Expand Down
40 changes: 14 additions & 26 deletions src/runtime/server/lib/oauth/discord.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { H3Event } from 'h3'
import { eventHandler, getQuery, getRequestURL, sendRedirect } from 'h3'
import { withQuery, parseURL, stringifyParsedURL } from 'ufo'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleAccessTokenErrorResponse, handleMissingConfiguration } from '../utils'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig } from '#imports'
import type { OAuthConfig } from '#auth-utils'

Expand Down Expand Up @@ -67,14 +67,15 @@ export function oauthDiscordEventHandler({ config, onSuccess, onError }: OAuthCo
profileRequired: true,
authorizationParams: {},
}) as OAuthDiscordConfig
const { code } = getQuery(event)
const query = getQuery<{ code?: string }>(event)

if (!config.clientId || !config.clientSecret) {
return handleMissingConfiguration(event, 'discord', ['clientId', 'clientSecret'], onError)
}

const redirectURL = config.redirectURL || getRequestURL(event).href
if (!code) {
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || []
if (config.emailRequired && !config.scope.includes('email')) {
config.scope.push('email')
Expand All @@ -96,27 +97,14 @@ export function oauthDiscordEventHandler({ config, onSuccess, onError }: OAuthCo
)
}

const parsedRedirectUrl = parseURL(redirectURL)
parsedRedirectUrl.search = ''
// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(
config.tokenURL as string,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: config.clientId,
client_secret: config.clientSecret,
grant_type: 'authorization_code',
redirect_uri: stringifyParsedURL(parsedRedirectUrl),
code: code as string,
}).toString(),
const tokens = await requestAccessToken(config.tokenURL as string, {
body: {
client_id: config.clientId,
client_secret: config.clientSecret,
grant_type: 'authorization_code',
redirect_uri: redirectURL,
code: query.code,
},
).catch((error) => {
return { error }
})

if (tokens.error) {
Expand Down
24 changes: 9 additions & 15 deletions src/runtime/server/lib/oauth/facebook.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import type { H3Event } from 'h3'
import {
eventHandler,
createError,
getQuery,
getRequestURL,
sendRedirect,
} from 'h3'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleAccessTokenErrorResponse, handleMissingConfiguration } from '../utils'
import { useRuntimeConfig } from '#imports'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig, createError } from '#imports'
import type { OAuthConfig } from '#auth-utils'

export interface OAuthFacebookConfig {
Expand Down Expand Up @@ -74,7 +68,8 @@ export function oauthFacebookEventHandler({
tokenURL: 'https://graph.facebook.com/v19.0/oauth/access_token',
authorizationParams: {},
}) as OAuthFacebookConfig
const query = getQuery(event)

const query = getQuery<{ code?: string, error?: string }>(event)

if (query.error) {
const error = createError({
Expand All @@ -90,7 +85,8 @@ export function oauthFacebookEventHandler({
return handleMissingConfiguration(event, 'facebook', ['clientId'], onError)
}

const redirectURL = config.redirectURL || getRequestURL(event).href
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || []
// Redirect to Facebook Oauth page
Expand All @@ -104,13 +100,11 @@ export function oauthFacebookEventHandler({
)
}

// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(config.tokenURL as string, {
method: 'POST',
const tokens = await requestAccessToken(config.tokenURL as string, {
body: {
client_id: config.clientId,
client_secret: config.clientSecret,
grant_type: 'authorization_code',
redirect_uri: redirectURL,
code: query.code,
},
Expand Down
34 changes: 16 additions & 18 deletions src/runtime/server/lib/oauth/github.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { H3Event } from 'h3'
import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from 'h3'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { defu } from 'defu'
import { handleAccessTokenErrorResponse, handleMissingConfiguration } from '../utils'
import { useRuntimeConfig } from '#imports'
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from '../utils'
import { useRuntimeConfig, createError } from '#imports'
import type { OAuthConfig } from '#auth-utils'

export interface OAuthGitHubConfig {
Expand Down Expand Up @@ -64,7 +64,8 @@ export function oauthGitHubEventHandler({ config, onSuccess, onError }: OAuthCon
tokenURL: 'https://github.com/login/oauth/access_token',
authorizationParams: {},
}) as OAuthGitHubConfig
const query = getQuery(event)

const query = getQuery<{ code?: string, error?: string }>(event)

if (query.error) {
const error = createError({
Expand All @@ -80,13 +81,14 @@ export function oauthGitHubEventHandler({ config, onSuccess, onError }: OAuthCon
return handleMissingConfiguration(event, 'github', ['clientId', 'clientSecret'], onError)
}

const redirectURL = config.redirectURL || getOAuthRedirectURL(event)

if (!query.code) {
config.scope = config.scope || []
if (config.emailRequired && !config.scope.includes('user:email')) {
config.scope.push('user:email')
}
// Redirect to GitHub Oauth page
const redirectURL = config.redirectURL || getRequestURL(event).href

return sendRedirect(
event,
withQuery(config.authorizationURL as string, {
Expand All @@ -98,19 +100,15 @@ export function oauthGitHubEventHandler({ config, onSuccess, onError }: OAuthCon
)
}

// TODO: improve typing
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tokens: any = await $fetch(
config.tokenURL as string,
{
method: 'POST',
body: {
client_id: config.clientId,
client_secret: config.clientSecret,
code: query.code,
},
const tokens = await requestAccessToken(config.tokenURL as string, {
body: {
grant_type: 'authorization_code',
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: redirectURL,
code: query.code,
},
)
})

if (tokens.error) {
return handleAccessTokenErrorResponse(event, 'github', tokens, onError)
Expand Down
Loading