mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-01 22:26:04 +08:00
The auth guard asked the issuer to come back to the page the visitor wanted. The issuer appends ?code= to whatever URL it is given, but only /auth/callback redeems a code — so it arrived on the target page, sat there unread, the guard found no session and bounced back for a fresh code. The browser ping-ponged between the two hosts until the user gave up. The guard now hands over /auth/callback and carries the wanted page in its redirect parameter, which is exactly what that page already expected. A spent code in the URL is dropped rather than carried along, so a stale link cannot turn into a redemption error one hop later. URL building moved into shared/utils/ssoHandoff.ts because the same mistake existed twice — the retry button on the callback page had it too — and because a redirect loop deserves a regression test that does not need a browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
39 lines
1.1 KiB
TypeScript
39 lines
1.1 KiB
TypeScript
import { defineNuxtRouteMiddleware, navigateTo, useRuntimeConfig } from '#app'
|
|
import { useAuthStore } from '~/stores/auth'
|
|
import { buildIssuerLoginUrl } from '~~/shared/utils/ssoHandoff'
|
|
|
|
export default defineNuxtRouteMiddleware(async (to) => {
|
|
const config = useRuntimeConfig()
|
|
|
|
// AUTH_MODE=open: a self-hosted instance has no login, so there is nothing to
|
|
// guard. The server resolves every request to the single local identity.
|
|
if (config.public.authMode === 'open') {
|
|
return
|
|
}
|
|
|
|
const auth = useAuthStore()
|
|
|
|
if (!auth.accessToken) {
|
|
await auth.tryRefresh().catch(() => false)
|
|
}
|
|
|
|
if (!auth.initialized || !auth.user) {
|
|
await auth.fetchUser().catch(() => null)
|
|
}
|
|
|
|
if (auth.user) return
|
|
|
|
const target = to.fullPath || '/'
|
|
const issuer = String(config.public.authIssuer || '').replace(/\/+$/, '')
|
|
|
|
// No issuer configured means website and app still share an origin — the
|
|
// local /login page is the login page.
|
|
if (!issuer) {
|
|
return navigateTo(`/login?redirect=${encodeURIComponent(target)}`)
|
|
}
|
|
|
|
return navigateTo(buildIssuerLoginUrl(issuer, window.location.origin, target), {
|
|
external: true,
|
|
})
|
|
})
|