Draft OpenID Connect support.

This commit is contained in:
Leo Vasanko
2026-02-14 23:01:13 +00:00
parent f195818f07
commit b5a5f2707a
12 changed files with 941 additions and 19 deletions
@@ -2,6 +2,7 @@
<RestrictedAuth
:mode="authMode"
:remote-auth-token="remoteAuthToken"
:oidc-query-string="oidcQueryString"
@authenticated="handleAuthenticated"
@back="handleBack"
/>
@@ -15,6 +16,9 @@ import RestrictedAuth from '@/components/RestrictedAuth.vue'
// The token is a 5-word passphrase like "word1.word2.word3.word4.word5"
const remoteAuthToken = ref(null)
// For OIDC flow, pass the raw query string to preserve exact param values
const oidcQueryString = window.location.search.includes('client_id=') ? window.location.search : null
function extractRemoteToken() {
const path = window.location.pathname
// Match /auth/{token} where token is a passphrase with dots
@@ -41,6 +45,11 @@ function postToParent(message) {
}
function handleAuthenticated(result) {
if (result.redirect_url) {
// OIDC flow: redirect to client with auth code
window.location.href = result.redirect_url
return
}
postToParent({
type: 'auth-success',
authenticated: true,
+11 -1
View File
@@ -67,6 +67,10 @@ const props = defineProps({
type: String,
default: 'login',
validator: (value) => ['login', 'reauth', 'forbidden'].includes(value)
},
oidcQueryString: {
type: String,
default: null
}
})
@@ -163,7 +167,7 @@ async function authenticateUser() {
loading.value = true
showMessage('Starting authentication…', 'info')
let result
try { result = await passkey.authenticate() } catch (error) {
try { result = await passkey.authenticate(props.oidcQueryString) } catch (error) {
loading.value = false
const message = error?.message || 'Passkey authentication cancelled'
const cancelled = message === 'Passkey authentication cancelled'
@@ -171,6 +175,12 @@ async function authenticateUser() {
emit('auth-error', { message, cancelled })
return
}
// OIDC flow: no session cookie, just emit the redirect_url
if (result.redirect_url) {
loading.value = false
emit('authenticated', result)
return
}
try { await setSessionCookie(result) } catch (error) {
loading.value = false
const message = error?.message || 'Failed to establish session'
+7 -2
View File
@@ -54,8 +54,13 @@ export async function register(resetToken = null, displayName = null, onstartreg
}
}
export async function authenticate() {
const ws = await aWebSocket(await makeUrl('/auth/ws/authenticate'))
export async function authenticate(queryString = null) {
// Build URL, optionally appending raw query string (e.g. for OIDC params)
let url = await makeUrl('/auth/ws/authenticate')
if (queryString) {
url += queryString.startsWith('?') ? queryString : `?${queryString}`
}
const ws = await aWebSocket(url)
try {
let res = await ws.receive_json()
if (res.status >= 400) throw new Error(res.detail || `Authentication failed: ${res.status}`)