Use rp-name for frontend branding
This commit is contained in:
parent
0b285e6ef0
commit
7036338b33
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/src/assets/icon.webp" />
|
<link rel="icon" href="/src/assets/icon.webp" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Passkey Admin</title>
|
<title>Admin</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="admin-app"></div>
|
<div id="admin-app"></div>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/src/assets/icon.webp">
|
<link rel="icon" href="/src/assets/icon.webp">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Passkey Authentication</title>
|
<title>Authentication</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
@ -26,6 +26,8 @@ onMounted(async () => {
|
|||||||
if (!location.pathname.startsWith('/auth/')) {
|
if (!location.pathname.startsWith('/auth/')) {
|
||||||
store.setRestrictedMode(true)
|
store.setRestrictedMode(true)
|
||||||
}
|
}
|
||||||
|
// Load branding / settings first (non-blocking for auth flow)
|
||||||
|
await store.loadSettings()
|
||||||
// Was an error message passed in the URL hash?
|
// Was an error message passed in the URL hash?
|
||||||
const message = location.hash.substring(1)
|
const message = location.hash.substring(1)
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -277,8 +277,12 @@ function deletePermission(p) {
|
|||||||
} })
|
} })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
window.addEventListener('hashchange', parseHash)
|
window.addEventListener('hashchange', parseHash)
|
||||||
|
await authStore.loadSettings()
|
||||||
|
if (authStore.settings?.rp_name) {
|
||||||
|
document.title = authStore.settings.rp_name + ' Admin'
|
||||||
|
}
|
||||||
load()
|
load()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -435,7 +439,7 @@ async function submitDialog() {
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 v-if="!selectedUser">
|
<h1 v-if="!selectedUser">
|
||||||
<template v-if="!selectedOrg">Passkey Admin</template>
|
<template v-if="!selectedOrg">{{ (authStore.settings?.rp_name || 'Passkey') + ' Admin' }}</template>
|
||||||
<template v-else>Organization Admin</template>
|
<template v-else>Organization Admin</template>
|
||||||
<a href="/auth/" class="back-link" title="Back to User App">User</a>
|
<a href="/auth/" class="back-link" title="Back to User App">User</a>
|
||||||
<a v-if="selectedOrg && info?.is_global_admin" @click.prevent="goOverview" href="#overview" class="nav-link" title="Back to overview">Overview</a>
|
<a v-if="selectedOrg && info?.is_global_admin" @click.prevent="goOverview" href="#overview" class="nav-link" title="Back to overview">Overview</a>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="view active">
|
<div class="view active">
|
||||||
<h1>🔐 Passkey Login</h1>
|
<h1>🔐 {{ (authStore.settings?.rp_name || 'Passkey') + ' Login' }}</h1>
|
||||||
<form @submit.prevent="handleLogin">
|
<form @submit.prevent="handleLogin">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@ -5,6 +5,7 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
// Auth State
|
// Auth State
|
||||||
userInfo: null, // Contains the full user info response: {user, credentials, aaguid_info, session_type, authenticated}
|
userInfo: null, // Contains the full user info response: {user, credentials, aaguid_info, session_type, authenticated}
|
||||||
|
settings: null, // Server provided settings (/auth/settings)
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
resetToken: null, // transient reset token
|
resetToken: null, // transient reset token
|
||||||
restrictedMode: false, // If true, app loaded outside /auth/ and should restrict to login or permission denied
|
restrictedMode: false, // If true, app loaded outside /auth/ and should restrict to login or permission denied
|
||||||
@ -106,6 +107,19 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
this.userInfo = result
|
this.userInfo = result
|
||||||
console.log('User info loaded:', result)
|
console.log('User info loaded:', result)
|
||||||
},
|
},
|
||||||
|
async loadSettings() {
|
||||||
|
try {
|
||||||
|
const res = await fetch('/auth/settings')
|
||||||
|
if (!res.ok) return
|
||||||
|
const data = await res.json()
|
||||||
|
this.settings = data
|
||||||
|
if (data?.rp_name) {
|
||||||
|
document.title = data.rp_name
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
},
|
||||||
async deleteCredential(uuid) {
|
async deleteCredential(uuid) {
|
||||||
const response = await fetch(`/auth/credential/${uuid}`, {method: 'Delete'})
|
const response = await fetch(`/auth/credential/${uuid}`, {method: 'Delete'})
|
||||||
const result = await response.json()
|
const result = await response.json()
|
||||||
|
@ -53,6 +53,18 @@ def register_api_routes(app: FastAPI):
|
|||||||
s = await authz.verify(auth, perm)
|
s = await authz.verify(auth, perm)
|
||||||
return {"valid": True, "user_uuid": str(s.user_uuid)}
|
return {"valid": True, "user_uuid": str(s.user_uuid)}
|
||||||
|
|
||||||
|
@app.get("/auth/settings")
|
||||||
|
async def get_settings():
|
||||||
|
"""Return server runtime settings safe for public consumption.
|
||||||
|
|
||||||
|
Provides relying party metadata used by the frontend to brand UI.
|
||||||
|
"""
|
||||||
|
pk = global_passkey.instance
|
||||||
|
return {
|
||||||
|
"rp_id": pk.rp_id,
|
||||||
|
"rp_name": pk.rp_name,
|
||||||
|
}
|
||||||
|
|
||||||
@app.post("/auth/user-info")
|
@app.post("/auth/user-info")
|
||||||
async def api_user_info(reset: str | None = None, auth=Cookie(None)):
|
async def api_user_info(reset: str | None = None, auth=Cookie(None)):
|
||||||
"""Get user information.
|
"""Get user information.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user