Demonstrates iframe-based authentication using postMessage
+
+
+
+
+
Authentication Modes
+
+
+
+
+
+
+
API Tests
+
+
+
+
+
+
+
+
+
Message Events
+
Waiting for messages...
+
+
+
+
+
+
diff --git a/examples/style.css b/examples/style.css
new file mode 100644
index 0000000..4ce7ffd
--- /dev/null
+++ b/examples/style.css
@@ -0,0 +1,22 @@
+:root {
+ color-scheme: light dark;
+}
+
+body:has(iframe) {
+ overflow: hidden; /* prevent scrolling the page */
+}
+
+iframe {
+ /* Fullscreen overlay */
+ border: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+ /* Transparent background with a backdrop effect (optional) */
+ color-scheme: auto;
+ backdrop-filter: blur(4px) brightness(0.7);
+ -webkit-backdrop-filter: blur(4px) brightness(0.7);
+}
diff --git a/frontend/restricted-api/index.html b/frontend/restricted-api/index.html
new file mode 100644
index 0000000..97be4a7
--- /dev/null
+++ b/frontend/restricted-api/index.html
@@ -0,0 +1 @@
+
diff --git a/frontend/src/admin/AdminApp.vue b/frontend/src/admin/AdminApp.vue
index 9ae327d..d790324 100644
--- a/frontend/src/admin/AdminApp.vue
+++ b/frontend/src/admin/AdminApp.vue
@@ -56,7 +56,7 @@ const permissionSummary = computed(() => {
for (const o of orgs.value) {
const orgBase = { uuid: o.uuid, display_name: o.display_name }
const orgPerms = new Set(o.permissions || [])
-
+
// Org-level permissions (direct) - only count if org can grant them
for (const pid of o.permissions || []) {
if (!summary[pid]) summary[pid] = { orgs: [], orgSet: new Set(), userCount: 0 }
@@ -65,13 +65,13 @@ const permissionSummary = computed(() => {
summary[pid].orgSet.add(o.uuid)
}
}
-
+
// Role-based permissions (inheritance) - only count if org can grant them
for (const r of o.roles) {
for (const pid of r.permissions) {
// Only count if the org can grant this permission
if (!orgPerms.has(pid)) continue
-
+
if (!summary[pid]) summary[pid] = { orgs: [], orgSet: new Set(), userCount: 0 }
if (!summary[pid].orgSet.has(o.uuid)) {
summary[pid].orgs.push(orgBase)
@@ -253,14 +253,14 @@ function deleteRole(role) {
async function toggleRolePermission(role, pid, checked) {
// Calculate new permissions array
- const newPermissions = checked
- ? [...role.permissions, pid]
+ const newPermissions = checked
+ ? [...role.permissions, pid]
: role.permissions.filter(p => p !== pid)
-
+
// Optimistic update
const prevPermissions = [...role.permissions]
role.permissions = newPermissions
-
+
try {
const res = await fetch(`/auth/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, {
method: 'PUT',
@@ -450,7 +450,7 @@ async function submitDialog() {
const newDisplay = dialog.value.data.display_name?.trim()
if (!newDisplay) throw new Error('Display name required')
if (!newId) throw new Error('ID required')
-
+
if (newId !== permission.id) {
// ID changed, use rename endpoint
const body = { old_id: permission.id, new_id: newId, display_name: newDisplay }
@@ -484,76 +484,74 @@ async function submitDialog() {
-
-
-
-
{{ pageHeading }}
-
-
+
+
+
{{ pageHeading }}
+
+
-
-
-
Loading…
-
{{ error }}
-
-
-
You must be authenticated.
-
-
-
Insufficient permissions.
-
-
-
+
+
+
Loading…
+
{{ error }}
+
+
+
You must be authenticated.
+
+
+
Insufficient permissions.
+
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
-
-
-
-
📱 Add Another Device
-
Generate a one-time link to set up passkeys on a new device.
-
-
-
-
-
+
+
+
📱 Add Another Device
+
Generate a one-time link to set up passkeys on a new device.
+
+
+
+
@@ -43,10 +41,6 @@ onMounted(async () => {
\ No newline at end of file
+
diff --git a/frontend/src/components/ProfileView.vue b/frontend/src/components/ProfileView.vue
index f17c2d9..dee765a 100644
--- a/frontend/src/components/ProfileView.vue
+++ b/frontend/src/components/ProfileView.vue
@@ -1,92 +1,90 @@
-
-
-
👋 Welcome!
-
-
Manage your account details and passkeys.
-
+
+
👋 Welcome!
+
+
Manage your account details and passkeys.
+
-
-
+
+
+
+
+
+
Your Passkeys
+
Keep at least one trusted passkey so you can always sign in.
+
+
+
-
-
-
-
-
Your Passkeys
-
Keep at least one trusted passkey so you can always sign in.
+
+
+
-
-
-
-
-
-
-
-
+
+
-
+
-
-
Edit Display Name
-
-
+
+
Edit Display Name
+
+
-
-
-
-
-
-
-
-
-
-
Logout from {{ currentSessionHost }}.
-
Logout this session on {{ currentSessionHost }}, or All sessions across all sites and devices for {{ rpName }}. You'll need to log in again with your passkey afterwards.
-
-
-
+
+
+
+
+
+
+
+
+
+
Logout from {{ currentSessionHost }}.
+
Logout this session on {{ currentSessionHost }}, or All sessions across all sites and devices for {{ rpName }}. You'll need to log in again with your passkey afterwards.