refactor: reconcile steam auth with merged #2226

This commit is contained in:
Lulu
2026-08-07 23:25:46 +08:00
parent 946cb04d19
commit e8ffa37405
8 changed files with 11 additions and 33 deletions
@@ -97,9 +97,6 @@ export function createAuthService(params: {
signingInFlight = true
try {
// Clean up any previous in-flight login
closeLoopback?.()
const codeVerifier = generateCodeVerifier()
const codeChallenge = await generateCodeChallenge(codeVerifier)
const state = generateState()
@@ -125,7 +125,6 @@ describe('ui-server-auth sign-in flow helpers', () => {
expect(JSON.parse(String((init as RequestInit).body))).toEqual({
provider: 'google',
callbackURL: 'https://api.airi.test/api/auth/oauth2/authorize?client_id=airi-stage-web',
disableRedirect: true,
})
})
@@ -147,7 +146,6 @@ describe('ui-server-auth sign-in flow helpers', () => {
expect(String(url)).toBe('https://api.airi.test/api/auth/sign-in/steam')
expect(JSON.parse(String((init as RequestInit).body))).toEqual({
callbackURL: 'https://api.airi.test/api/auth/oauth2/authorize?client_id=airi-stage-web',
disableRedirect: true,
})
})
+2 -2
View File
@@ -107,8 +107,8 @@ export async function requestSocialSignInRedirect(params: SocialSignInRedirectPa
// `/sign-in/steam`, surfaced here as the typed `signIn.steam` action.
// Other providers use the standard `/sign-in/social`.
const result = params.provider === 'steam'
? await client.signIn.steam({ callbackURL: params.callbackURL, disableRedirect: true })
: await client.signIn.social({ provider: params.provider, callbackURL: params.callbackURL, disableRedirect: true })
? await client.signIn.steam({ callbackURL: params.callbackURL })
: await client.signIn.social({ provider: params.provider, callbackURL: params.callbackURL })
const url = result.data?.url
if (typeof url === 'string')
+3 -1
View File
@@ -7,6 +7,8 @@ import { SERVER_URL } from './server'
const OIDC_AUTHORIZE_PATH = '/api/auth/oauth2/authorize'
const OIDC_TOKEN_PATH = '/api/auth/oauth2/token'
export type SocialOAuthProvider = 'google' | 'github'
export interface OIDCFlowParams {
clientId: string
redirectUri: string
@@ -17,7 +19,7 @@ export interface OIDCFlowParams {
*/
clientSecret?: string
/** Social provider hint — skips the server-side picker page. */
provider?: 'google' | 'github' | 'steam'
provider?: SocialOAuthProvider
}
export interface OIDCFlowState {
+3 -9
View File
@@ -1,4 +1,4 @@
import type { OIDCFlowParams, TokenResponse } from './auth-oidc'
import type { OIDCFlowParams, SocialOAuthProvider, TokenResponse } from './auth-oidc'
import { createAuthClient } from 'better-auth/vue'
@@ -8,7 +8,7 @@ import { buildAuthorizationURL, persistFlowState } from './auth-oidc'
import { SERVER_URL } from './server'
import { steamClient } from './steam-auth-client'
export type OAuthProvider = 'google' | 'github' | 'steam'
export type OAuthProvider = SocialOAuthProvider | 'steam'
// NOTICE: reads the same localStorage key ('auth/v1/token') that useAuthStore's
// `token` ref writes via useLocalStorage. We bypass the store here because
@@ -194,12 +194,6 @@ export async function signInOIDC(params: OIDCFlowParams) {
return
}
if (provider === 'steam') {
// Steam is OpenID 2.0; only the Steam plugin endpoint can start it.
await authClient.signIn.steam({ callbackURL: url.toString() })
return
}
await authClient.signIn.social({
provider,
callbackURL: url.toString(),
@@ -226,7 +220,7 @@ export async function signInOIDC(params: OIDCFlowParams) {
* social provider. Omit to land on the project's hosted login page
* (ui-server-auth) where the user can choose email/password or social.
*/
export async function triggerSignIn(opts?: { provider?: OAuthProvider }): Promise<void> {
export async function triggerSignIn(opts?: { provider?: SocialOAuthProvider }): Promise<void> {
await signInOIDC({
clientId: OIDC_CLIENT_ID,
redirectUri: OIDC_REDIRECT_URI,
@@ -9,7 +9,6 @@ import type { BetterFetch } from '@better-fetch/fetch'
export interface SteamOAuthStartArgs {
callbackURL: string
errorCallbackURL?: string
disableRedirect?: boolean
}
/**
@@ -1,6 +1,6 @@
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
import { beforeAll, describe, expect, it, vi } from 'vitest'
import { mockDB } from '../mock-db'
import { steam } from './steam'
@@ -74,8 +74,6 @@ describe('steam auth plugin', () => {
auth = await createTestAuth()
})
afterEach(() => vi.unstubAllGlobals())
// NOTICE:
// We mock the module-global `fetch` for Steam's `check_authentication`
// dumb-mode verification POST instead of hitting the real
@@ -104,15 +102,6 @@ describe('steam auth plugin', () => {
expect(url.searchParams.get('openid.return_to')).toContain('/steam/callback?state=')
})
it('skips the automatic redirect when disableRedirect is set', async () => {
const { response } = await auth.api.signInSteam({
body: { callbackURL: 'http://localhost/ui/profile', disableRedirect: true },
returnHeaders: true,
})
expect(response.redirect).toBe(false)
})
it('creates a user with a placeholder email on first sign-in and reuses the same account on later sign-ins', async () => {
mockSteamVerification(true)
const context = await auth.$context
@@ -23,7 +23,6 @@ const STEAM_CLAIMED_ID_PATTERN = /^https:\/\/steamcommunity\.com\/openid\/id\/(\
const SignInBodySchema = z.object({
callbackURL: z.string().meta({ description: 'The URL to redirect to after sign in' }),
errorCallbackURL: z.string().meta({ description: 'The URL to redirect to if an error occurs' }).optional(),
disableRedirect: z.boolean().optional(),
})
const CallbackQuerySchema = z.looseObject({
@@ -121,7 +120,7 @@ export function steam() {
const { state } = await generateState(ctx, undefined, undefined)
return ctx.json({
url: buildOpenIdRedirectURL(ctx.context.baseURL, state),
redirect: !ctx.body.disableRedirect,
redirect: true,
})
})
@@ -145,7 +144,7 @@ export function steam() {
const { state } = await generateState(ctx, { userId: session.user.id, email: session.user.email }, undefined)
return ctx.json({
url: buildOpenIdRedirectURL(ctx.context.baseURL, state),
redirect: !ctx.body.disableRedirect,
redirect: true,
})
})