mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-01 06:06:05 +08:00
fix(routing): catch the paths the split left pointing at nothing
Three dead ends, one cause: these routes resolved to pages that stayed on the website, and nothing here answered them any more. /start — this page became the app's front page in the split (it is index.vue now), so every pre-split bookmark and the website's own redirect landed on a 404. Caught here so the app's old URLs work without waiting for the website to be redeployed. /login — the app has no login by design, identity comes from the issuer. But five call sites still send people there: logout, the live-atc session guard, the bridge pairing screen. In the monorepo that path was the website's login form; since the split it was nothing, so signing out dropped the user on a blank page. It is a forwarder to the issuer, not a login form. /logout — after clearing the app session it sent the user to /login, which under SSO means an issuer where they are still signed in: they would be handed a fresh code and land straight back inside. It now signs them out at the issuer too, which bumps tokenVersion and invalidates every refresh token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
28
app/pages/login.vue
Normal file
28
app/pages/login.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { buildIssuerLoginUrl } from '~~/shared/utils/ssoHandoff'
|
||||
|
||||
/**
|
||||
* Not a login page — the app has none by design, identity comes from the
|
||||
* issuer. This only exists because /login is where the code still sends people
|
||||
* (logout, the live-atc session guard, the bridge pairing screen), and in the
|
||||
* monorepo that path resolved to the website's login form. Since the split it
|
||||
* resolved to nothing, so signing out dropped the user on a 404.
|
||||
*/
|
||||
const route = useRoute()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
definePageMeta({ layout: false })
|
||||
|
||||
const issuer = String(config.public.authIssuer || '').replace(/\/+$/, '')
|
||||
const raw = String(route.query.redirect || '/')
|
||||
// Only same-origin paths — never bounce onward to an absolute URL from the query.
|
||||
const target = raw.startsWith('/') && !raw.startsWith('//') ? raw : '/'
|
||||
|
||||
if (issuer) {
|
||||
await navigateTo(buildIssuerLoginUrl(issuer, window.location.origin, target), { external: true })
|
||||
}
|
||||
else {
|
||||
// AUTH_MODE=open: no login exists at all, every request is the local identity.
|
||||
await navigateTo(target, { replace: true })
|
||||
}
|
||||
</script>
|
||||
@@ -21,6 +21,7 @@ import { useAuthStore } from '~/stores/auth'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
useHead({
|
||||
title: 'Logout – OpenSquawk',
|
||||
@@ -31,7 +32,17 @@ useHead({
|
||||
|
||||
onMounted(async () => {
|
||||
await auth.logout()
|
||||
router.replace('/login')
|
||||
|
||||
// Sign out at the issuer too. Sending the user to the app's own /login would
|
||||
// only forward them back to an issuer where they are still signed in — they
|
||||
// would be handed a fresh code and land straight back inside, which is not
|
||||
// what "log out" means.
|
||||
const issuer = String(config.public.authIssuer || '').replace(/\/+$/, '')
|
||||
if (issuer) {
|
||||
return navigateTo(`${issuer}/logout`, { external: true })
|
||||
}
|
||||
|
||||
router.replace('/')
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user