Files
BYW-VoiceHub/server/utils/oauth-strategies.ts
T
Henry_Du a481e0ae4c
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m13s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
fix(auth): 微信登录按钮放大+主题色 & /api/auth/aggregate 500 诊断日志\n\nUI 改动(微信登录按钮 + 个人页绑定卡片):\n- OAuthButtons.vue:aggregate 微信按钮 48x48 → 56x56,SVG 图标 22px→28px;默认背景微信绿 #07C160,hover #06ad56,active #059a4c;正常态加绿色阴影,纯 #fff 文字;不再和相邻 Google/GitHub 保持原尺寸不变\n- OAuthBindingCard.vue 个人页卡片:aggregate(aggregate):微信图标框 40x40→48x48(h-10→h-12),图标 22px→26px,背景/边框/文字用微信绿 #07C160;未绑定微信色 立即绑定微信 按钮 字号从 xs→sm,py 1.5→2.5,文案 立即绑定→立即绑定微信\n\n500 排错日志(/api/auth/aggregate):\n- loadAggregateSettings:先取 env fallback 前置,DB select 包 try/catch 不抛;并打印 [AggregateOAuth] enabled/appId/appKey 长度/loginType/endpoint 状态(DB=? 配置 / ENV=? 配置 / dbEnabled回退逻辑\n- auxxStrategy.getAuthorizeUrl 全链路结构化日志:\n 1) 参数打印(enabled/endpoint/safe_ok/redirect_uri/state_len\n 2) 配置缺失时逐条枚举原因(APP_ID 空 / APP_KEY 空 / ENDPOINT 空 / enabled=false)\n 3) endpoint 不合法时单独打印 [AggregateOAuth][auxx][getAuthorizeUrl] endpoint 不合法 + JSON(endpoint)\n 4) 请求 auxx.cn/connect.php?act=login 前打印 GET URL(appkey 替换为 ***,日志绝不输出真实密钥)\n 5) $fetch 成功打印 code/msg/has_url/url_prefix\n 6) $fetch 异常打印 err/status/body (response._data 或 data 前 400 字)\n 7) $fetch 加 15000ms 超时,避免 Runner 到 auxx 不通卡死一直挂 30s\n 以上;30s+ 才被 Nitro 强制 500
2026-09-13 01:05:38 +08:00

609 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createError } from 'h3'
import { createHmac, randomUUID } from 'node:crypto'
import { db } from '~/drizzle/db'
import { systemSettings } from '~/drizzle/schema'
import { asc } from 'drizzle-orm'
import {
isSafeAggregateOAuthUrl,
getAggregateOAuthLoginTypesOrDefault
} from './oauth-providers'
export interface OAuthUserInfo {
id: string
username: string
email?: string
name?: string
avatar?: string
}
export interface OAuthStrategy {
/**
* 获取授权跳转 URL
*/
getAuthorizeUrl(redirectUri: string, state: string): string
/**
* 使用 code 换取 access_token
*/
exchangeToken(code: string, redirectUri: string): Promise<string>
/**
* 获取用户信息
*/
getUserInfo(accessToken: string): Promise<OAuthUserInfo>
}
// GitHub 策略实现
const githubStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.GITHUB_CLIENT_ID
if (!clientId)
throw createError({ statusCode: 500, message: 'GitHub Client ID not configured' })
return `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=user:email&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.GITHUB_CLIENT_ID
const clientSecret = process.env.GITHUB_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw createError({ statusCode: 500, message: 'GitHub config missing' })
}
try {
const tokenResponse = await $fetch<any>('https://github.com/login/oauth/access_token', {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('GitHub Token Error:', tokenResponse.error)
throw new Error('授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('GitHub Token Response missing access_token')
throw new Error('未能获取访问令牌')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('GitHub token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
try {
const userInfo = await $fetch<any>('https://api.github.com/user', {
headers: { Authorization: `Bearer ${accessToken}` }
})
return {
id: String(userInfo.id),
username: userInfo.login,
name: userInfo.name,
email: userInfo.email,
avatar: userInfo.avatar_url
}
} catch (e: any) {
console.error('GitHub user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// Casdoor 策略实现
const casdoorStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.CASDOOR_CLIENT_ID
const endpoint = process.env.CASDOOR_ENDPOINT
if (!clientId || !endpoint)
throw createError({ statusCode: 500, message: 'Casdoor config missing' })
return `${endpoint}/login/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(redirectUri)}&scope=read&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.CASDOOR_CLIENT_ID
const clientSecret = process.env.CASDOOR_CLIENT_SECRET
const endpoint = process.env.CASDOOR_ENDPOINT
if (!clientId || !clientSecret || !endpoint) {
throw createError({ statusCode: 500, message: 'Casdoor config missing' })
}
try {
const tokenResponse = await $fetch<any>(`${endpoint}/login/oauth/access_token`, {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('Casdoor Token Error:', tokenResponse.error, tokenResponse.error_description)
throw new Error(tokenResponse.error_description || '授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('Casdoor Token Response missing access_token')
throw new Error('未能获取访问令牌,请检查 Casdoor 配置')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('Casdoor token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
const endpoint = process.env.CASDOOR_ENDPOINT
if (!endpoint) throw createError({ statusCode: 500, message: 'Casdoor config missing' })
let userInfo: any = {}
try {
// Casdoor 用户信息端点通常是 /api/get-account 或 /api/userinfo
// 标准 OIDC 使用 /userinfo
try {
userInfo = await $fetch(`${endpoint}/api/userinfo`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
} catch (e) {
// 尝试备用端点
userInfo = await $fetch(`${endpoint}/api/get-account`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
}
return {
id: String(userInfo.id || userInfo.sub),
username: userInfo.name || userInfo.preferred_username || userInfo.username,
name: userInfo.displayName || userInfo.name,
email: userInfo.email,
avatar: userInfo.avatar
}
} catch (e: any) {
console.error('Casdoor user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// Google 策略实现
const googleStrategy: OAuthStrategy = {
getAuthorizeUrl(redirectUri: string, state: string) {
const clientId = process.env.GOOGLE_CLIENT_ID
if (!clientId)
throw createError({ statusCode: 500, message: 'Google Client ID not configured' })
return `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=openid%20email%20profile&state=${encodeURIComponent(state)}`
},
async exchangeToken(code: string, redirectUri: string) {
const clientId = process.env.GOOGLE_CLIENT_ID
const clientSecret = process.env.GOOGLE_CLIENT_SECRET
if (!clientId || !clientSecret) {
throw createError({ statusCode: 500, message: 'Google config missing' })
}
try {
const tokenResponse = await $fetch<any>('https://oauth2.googleapis.com/token', {
method: 'POST',
body: {
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: redirectUri
},
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
console.error('Google Token Error:', tokenResponse.error)
throw new Error('授权失败,请重试')
}
if (!tokenResponse.access_token) {
console.error('Google Token Response missing access_token')
throw new Error('未能获取访问令牌')
}
return tokenResponse.access_token
} catch (e: any) {
console.error('Google token exchange failed', e.message || e)
const errorMessage = e.data?.error_description || e.message || '令牌请求失败'
throw new Error(errorMessage)
}
},
async getUserInfo(accessToken: string) {
try {
const userInfo = await $fetch<any>('https://www.googleapis.com/oauth2/v3/userinfo', {
headers: { Authorization: `Bearer ${accessToken}` }
})
return {
id: userInfo.sub,
username: userInfo.email, // Google doesn't have a username, use email
name: userInfo.name,
email: userInfo.email,
avatar: userInfo.picture
}
} catch (e: any) {
console.error('Google user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
// 策略注册表
const strategies: Record<string, OAuthStrategy> = {
github: githubStrategy,
casdoor: casdoorStrategy,
google: googleStrategy
}
async function loadAggregateSettings() {
const envAppId = process.env.AGGREGATE_OAUTH_APP_ID
const envAppKey = process.env.AGGREGATE_OAUTH_APP_KEY
const envLoginType = process.env.AGGREGATE_OAUTH_LOGIN_TYPE
const envEndpoint = process.env.AGGREGATE_OAUTH_ENDPOINT
const hasEnvConfig = !!(envAppId && envAppKey && envEndpoint)
let base: any = null
try {
const row = await db
.select({
aggregateOAuthEnabled: systemSettings.aggregateOAuthEnabled,
aggregateOAuthAppId: systemSettings.aggregateOAuthAppId,
aggregateOAuthAppKey: systemSettings.aggregateOAuthAppKey,
aggregateOAuthLoginType: systemSettings.aggregateOAuthLoginType,
aggregateOAuthEndpoint: systemSettings.aggregateOAuthEndpoint
})
.from(systemSettings)
.orderBy(asc(systemSettings.id))
.limit(1)
base = row[0] ?? null
} catch (e: any) {
console.warn(
'[AggregateOAuth][WARN] loadAggregateSettings 查询 DB 失败,回退只用 process.env 配置。' +
` DB 错误:${e?.message || String(e)}。 envAppId=${envAppId ? '已配置(len=' + String(envAppId).length + ')' : '空'} ` +
` envEndpoint=${envEndpoint ? '已配置(' + envEndpoint + ')' : '空'}`
)
}
const dbEnabled = base?.aggregateOAuthEnabled
const dbHasConfig = !!(
base?.aggregateOAuthAppId &&
base?.aggregateOAuthAppKey &&
base?.aggregateOAuthEndpoint
)
const enabled = Boolean(dbEnabled ?? hasEnvConfig)
const appId = (base?.aggregateOAuthAppId || envAppId || '') as string
const appKey = (base?.aggregateOAuthAppKey || envAppKey || '') as string
const loginType = ((base?.aggregateOAuthLoginType as string) || envLoginType || '') as string
const endpoint = ((base?.aggregateOAuthEndpoint as string) || envEndpoint || '') as string
const result: any = {
aggregateOAuthEnabled: enabled && !!(appId && appKey && endpoint),
aggregateOAuthAppId: appId,
aggregateOAuthAppKey: appKey,
aggregateOAuthLoginType: loginType,
aggregateOAuthEndpoint: endpoint,
_dbHasConfig: dbHasConfig,
_hasEnvConfig: hasEnvConfig
}
console.log(
'[AggregateOAuth] loadAggregateSettings -> ' +
` enabled=${result.aggregateOAuthEnabled}` +
` appId=${appId ? 'len=' + String(appId).length : 'EMPTY'}` +
` appKey=${appKey ? 'len=' + String(appKey).length : 'EMPTY'}` +
` loginType=${loginType || 'EMPTY'}` +
` endpoint=${endpoint || 'EMPTY'}` +
` (DB=${dbHasConfig ? '有' : '无'}配置, ENV=${hasEnvConfig ? '有' : '无'}配置, dbEnabled=${dbEnabled ?? '未设置->回退ENV'})`
)
return result
}
function normalizeEndpoint(endpoint: string): string {
return endpoint.replace(/\/+$/, '')
}
function aggregateSign(params: Record<string, string>, appKey: string): string {
const sorted = Object.keys(params)
.filter((k) => params[k] !== undefined && params[k] !== null && params[k] !== '')
.sort()
.map((k) => `${k}=${params[k]}`)
.join('&')
return createHmac('sha256', appKey).update(sorted).digest('hex')
}
const auxxUserInfoCache = new Map<string, any>()
function isAuxxEndpoint(endpoint: string): boolean {
return /(^|\.)auxx\.cn(\/|$)/i.test(endpoint)
}
const auxxStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
console.log(
'[AggregateOAuth][auxx][getAuthorizeUrl] ' +
`enabled=${settings?.aggregateOAuthEnabled}` +
` endpoint=${settings?.aggregateOAuthEndpoint || 'EMPTY'}` +
` endpoint_safe_ok=${isSafeAggregateOAuthUrl(settings?.aggregateOAuthEndpoint || '')}` +
` redirect_uri=${redirectUri}` +
` state_len=${String(state || '').length}`
)
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
const hint = []
if (!settings?.aggregateOAuthEnabled) hint.push('aggregateOAuthEnabled=false')
if (!settings?.aggregateOAuthAppId) hint.push('APP_ID 空')
if (!settings?.aggregateOAuthAppKey) hint.push('APP_KEY 空')
if (!settings?.aggregateOAuthEndpoint) hint.push('ENDPOINT 空')
console.error('[AggregateOAuth][auxx][getAuthorizeUrl] 配置缺失:', hint.join(' | '))
throw createError({ statusCode: 500, message: '聚合登录未配置:' + hint.join(' / ') })
}
if (!isSafeAggregateOAuthUrl(settings.aggregateOAuthEndpoint)) {
console.error(
'[AggregateOAuth][auxx][getAuthorizeUrl] endpoint 不合法,' +
'isSafeAggregateOAuthUrl 返回 false。endpoint=' +
JSON.stringify(settings.aggregateOAuthEndpoint)
)
throw createError({
statusCode: 500,
message:
'聚合登录端点不安全或格式错误:endpoint 必须是 https://xxx 或内网 http://localhost,当前值=' +
settings.aggregateOAuthEndpoint
})
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const loginQueryObj: Record<string, string> = {
act: 'login',
appid: settings.aggregateOAuthAppId,
appkey: settings.aggregateOAuthAppKey,
type: loginType,
redirect_uri: redirectUri
}
const loginQuery = new URLSearchParams(loginQueryObj).toString()
const debugQueryNoKey = new URLSearchParams({ ...loginQueryObj, appkey: '***' }).toString()
console.log(
`[AggregateOAuth][auxx][getAuthorizeUrl] 请求 auxx Step1:GET ${endpoint}/connect.php?${debugQueryNoKey}`
)
try {
const resp: any = await $fetch(`${endpoint}/connect.php?${loginQuery}`, {
headers: { Accept: 'application/json' },
timeout: 15000
})
console.log(
'[AggregateOAuth][auxx][getAuthorizeUrl] auxx Step1 返回:' +
JSON.stringify({
code: resp?.code,
msg: resp?.msg,
has_url: !!resp?.url,
url_prefix: resp?.url ? String(resp.url).slice(0, 80) + '...' : null
})
)
if (resp.code !== 0 || !resp.url) {
throw new Error(resp.msg || `获取登录跳转地址失败(auxx code=${resp?.code ?? 'N/A'})`)
}
const sep = resp.url.includes('?') ? '&' : '?'
return `${resp.url}${sep}state=${encodeURIComponent(state)}`
} catch (e: any) {
const status = e?.response?.status || e?.status || 'N/A'
const body = e?.response?._data ? JSON.stringify(e.response._data).slice(0, 400) : e?.data ? JSON.stringify(e.data).slice(0, 400) : null
console.error(
'[AggregateOAuth][auxx][getAuthorizeUrl] fetch 异常:' +
` err=${e?.message || String(e)} status=${status} body=${body}`
)
throw new Error(e.message || '获取登录跳转地址失败(auxx 不可达或凭据错误)')
}
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const cbQuery = new URLSearchParams({
act: 'callback',
appid: settings.aggregateOAuthAppId,
appkey: settings.aggregateOAuthAppKey,
type: loginType,
code
}).toString()
try {
const resp: any = await $fetch(`${endpoint}/connect.php?${cbQuery}`, {
headers: { Accept: 'application/json' }
})
if (resp.code !== 0 || !resp.access_token || !resp.social_uid) {
throw new Error(resp.msg || '回调换取用户信息失败')
}
const cacheKey = `${settings.aggregateOAuthAppId}:${resp.access_token}`
auxxUserInfoCache.set(cacheKey, resp)
setTimeout(() => auxxUserInfoCache.delete(cacheKey), 10 * 60 * 1000)
return String(resp.access_token)
} catch (e: any) {
console.error('Auxx OAuth token exchange failed', e)
throw new Error(e.message || '回调换取用户信息失败')
}
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
const appId = settings?.aggregateOAuthAppId || ''
const cacheKey = `${appId}:${accessToken}`
let resp = auxxUserInfoCache.get(cacheKey)
if (!resp) {
resp = Array.from(auxxUserInfoCache.values()).find((r: any) => r.access_token === accessToken)
}
if (!resp || resp.code !== 0 || !resp.social_uid) {
throw new Error('获取用户信息失败')
}
return {
id: String(resp.social_uid),
username: resp.nickname || `wx_${String(resp.social_uid).slice(0, 8)}`,
name: resp.nickname || undefined,
email: undefined,
avatar: resp.faceimg || undefined
}
}
}
const standardAggregateStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
if (!isSafeAggregateOAuthUrl(settings.aggregateOAuthEndpoint)) {
throw createError({ statusCode: 500, message: '聚合登录端点不安全或格式错误' })
}
const loginTypes = getAggregateOAuthLoginTypesOrDefault(settings.aggregateOAuthLoginType)
const loginType = loginTypes[0] || 'qq'
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
response_type: 'code',
redirect_uri: redirectUri,
state,
login_type: loginType,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
const query = new URLSearchParams({ ...baseParams, sign }).toString()
return `${endpoint}/oauth/authorize?${query}`
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthEnabled || !settings.aggregateOAuthAppId || !settings.aggregateOAuthAppKey || !settings.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
try {
const tokenResponse = await $fetch<any>(`${endpoint}/oauth/token`, {
method: 'POST',
body: { ...baseParams, sign },
headers: { Accept: 'application/json' }
})
if (tokenResponse.error) {
throw new Error(tokenResponse.error_description || tokenResponse.error || '令牌请求失败')
}
const accessToken = tokenResponse.access_token || tokenResponse.accessToken
if (!accessToken) {
throw new Error('未能获取访问令牌')
}
return accessToken
} catch (e: any) {
console.error('Aggregate OAuth token exchange failed', e)
throw new Error(e.message || '令牌请求失败')
}
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
if (!settings?.aggregateOAuthAppId || !settings?.aggregateOAuthAppKey || !settings?.aggregateOAuthEndpoint) {
throw createError({ statusCode: 500, message: '聚合登录未配置' })
}
const endpoint = normalizeEndpoint(settings.aggregateOAuthEndpoint)
const timestamp = String(Math.floor(Date.now() / 1000))
const nonce = randomUUID().replace(/-/g, '')
const baseParams: Record<string, string> = {
app_id: settings.aggregateOAuthAppId,
access_token: accessToken,
timestamp,
nonce
}
const sign = aggregateSign(baseParams, settings.aggregateOAuthAppKey)
try {
const userInfo = await $fetch<any>(`${endpoint}/oauth/userinfo`, {
method: 'POST',
body: { ...baseParams, sign },
headers: { Accept: 'application/json' }
})
return {
id: String(userInfo.id || userInfo.openid || userInfo.sub || userInfo.userId || ''),
username: userInfo.username || userInfo.nickname || userInfo.name || String(userInfo.id || 'user'),
name: userInfo.name || userInfo.nickname || undefined,
email: userInfo.email || undefined,
avatar: userInfo.avatar || userInfo.avatar_url || userInfo.headimgurl || undefined
}
} catch (e: any) {
console.error('Aggregate OAuth user info failed', e)
throw new Error('获取用户信息失败')
}
}
}
const aggregateStrategy: OAuthStrategy = {
async getAuthorizeUrl(redirectUri: string, state: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.getAuthorizeUrl(redirectUri, state)
: standardAggregateStrategy.getAuthorizeUrl(redirectUri, state)
},
async exchangeToken(code: string, redirectUri: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.exchangeToken(code, redirectUri)
: standardAggregateStrategy.exchangeToken(code, redirectUri)
},
async getUserInfo(accessToken: string) {
const settings = await loadAggregateSettings()
const endpoint = settings?.aggregateOAuthEndpoint || ''
return isAuxxEndpoint(endpoint)
? auxxStrategy.getUserInfo(accessToken)
: standardAggregateStrategy.getUserInfo(accessToken)
}
}
strategies.aggregate = aggregateStrategy
export const getOAuthStrategy = (provider: string): OAuthStrategy => {
const strategy = strategies[provider]
if (!strategy) {
throw createError({ statusCode: 400, message: `Unknown provider: ${provider}` })
}
return strategy
}