Admin OIDC cleanup.
This commit is contained in:
@@ -96,45 +96,6 @@ function copyText(value, label) {
|
||||
</label>
|
||||
<p class="small muted">A domain ({{ rpId }} or subdomain) restricts this permission to that host. An OIDC client UUID sends it as a <em>groups</em> claim to that client.</p>
|
||||
</template>
|
||||
<template v-else-if="dialog.type==='oidc-edit'">
|
||||
<template v-if="dialog.data.client_id">
|
||||
<dl class="oidc-dl">
|
||||
<dt>Auth Name (opt)</dt>
|
||||
<dd @click="copyText('paskia', 'Authentication Name')" title="Click to copy"><output>paskia</output></dd>
|
||||
<dt>Discovery URL</dt>
|
||||
<dd @click="copyText(discoveryUrl, 'OpenID Connect Discovery URL')" title="Click to copy"><output>{{ discoveryUrl }}</output></dd>
|
||||
<dt>Client ID</dt>
|
||||
<dd @click="copyText(dialog.data.client_id, 'Client ID')" title="Click to copy"><output>{{ dialog.data.client_id }}</output></dd>
|
||||
<dt>Client Secret</dt>
|
||||
<dd v-if="dialog.data.client_secret" @click="copyText(dialog.data.client_secret, 'Client Secret')" title="Click to copy"><output>{{ dialog.data.client_secret }}</output></dd>
|
||||
<dd v-else class="oidc-reset-row">
|
||||
<button type="button" class="icon-btn" @click="$emit('resetOidcSecret', dialog.data.client_id)" title="Revoke and re-generate secret">🔄</button>
|
||||
</dd>
|
||||
<dt>Groups <button type="button" class="icon-btn" @click="$emit('createPermissionForClient', dialog.data.client_id)" title="Add permission scoped to this client">➕</button></dt>
|
||||
<dd class="oidc-groups">
|
||||
<template v-if="dialog.data.groups?.length">
|
||||
<div v-for="group in dialog.data.groups" :key="group.uuid" class="oidc-group" @click="copyText(group.scope, 'Group Value')" :title="group.display_name">
|
||||
<output>{{ group.scope }}</output>
|
||||
</div>
|
||||
</template>
|
||||
<span v-else class="small muted">No permissions defined.</span>
|
||||
</dd>
|
||||
</dl>
|
||||
<p v-if="dialog.data.client_secret && dialog.data.isNew" class="small"><strong>⚠️ Save the secret now — it cannot be retrieved later.</strong></p>
|
||||
<p v-else-if="dialog.data.client_secret" class="small"><strong>⚠️ Saving will prevent access with the old secret.</strong></p>
|
||||
</template>
|
||||
<p class="small muted">Configure these in the client application.</p>
|
||||
<hr class="oidc-divider" />
|
||||
|
||||
<label>Client Name
|
||||
<input v-model="dialog.data.name" placeholder="My Application" required />
|
||||
</label>
|
||||
<label>Redirect URIs
|
||||
<p class="small muted">This should be provided by the client application.</p>
|
||||
<textarea v-model="dialog.data.redirect_uris" placeholder="(autodiscover one on first use)" rows="2"></textarea>
|
||||
</label>
|
||||
|
||||
</template>
|
||||
<template v-else-if="dialog.type==='confirm'">
|
||||
<p>{{ dialog.data.message }}</p>
|
||||
</template>
|
||||
|
||||
@@ -125,27 +125,37 @@ defineExpose({ focusFirstElement })
|
||||
<p class="section-description">Configure these values in the client application.</p>
|
||||
|
||||
<dl class="oidc-dl">
|
||||
<dt>Auth Name (opt)</dt>
|
||||
<dd @click="copyText('paskia', 'Authentication Name')" title="Click to copy"><output>paskia</output></dd>
|
||||
<dt>Authentication Name</dt>
|
||||
<dd>
|
||||
<output @click="copyText(authStore.settings.rp_name, 'Authentication Name')" title="Click to copy">{{ authStore.settings.rp_name }}</output>
|
||||
<span class="small muted"> (Login With, may affect URLs – optional)</span>
|
||||
</dd>
|
||||
|
||||
<dt>Discovery URL</dt>
|
||||
<dd @click="copyText(discoveryUrl, 'OpenID Connect Discovery URL')" title="Click to copy"><output>{{ discoveryUrl }}</output></dd>
|
||||
<dd><output @click="copyText(discoveryUrl, 'OpenID Connect Discovery URL')" title="Click to copy">{{ discoveryUrl }}</output></dd>
|
||||
|
||||
<dt>Client ID</dt>
|
||||
<dd @click="copyText(clientId, 'Client ID')" title="Click to copy"><output>{{ clientId }}</output></dd>
|
||||
<dd><output @click="copyText(clientId, 'Client ID')" title="Click to copy">{{ clientId }}</output></dd>
|
||||
|
||||
<dt>Client Secret <button v-if="!clientSecret" type="button" class="icon-btn" @click="handleResetSecret" title="Revoke and re-generate secret">🔄</button></dt>
|
||||
<dd v-if="clientSecret" @click="copyText(clientSecret, 'Client Secret')" title="Click to copy"><output>{{ clientSecret }}</output></dd>
|
||||
<dd v-else class="muted small">(only stored in hashed form)</dd>
|
||||
<dd>
|
||||
<output v-if="clientSecret" @click="copyText(clientSecret, 'Client Secret')" title="Click to copy">{{ clientSecret }}</output>
|
||||
<span v-else class="small muted">(only stored in hashed form)</span>
|
||||
</dd>
|
||||
|
||||
<template v-if="clientGroups.length">
|
||||
<dt>Groups Name</dt>
|
||||
<dd>
|
||||
<output @click="copyText('groups', 'Groups Name')" title="Click to copy">groups</output>
|
||||
</dd>
|
||||
</template>
|
||||
|
||||
<dt>Groups <button type="button" class="icon-btn" @click="handleCreatePermission" title="Add permission scoped to this client">➕</button></dt>
|
||||
<dd class="oidc-groups">
|
||||
<template v-if="clientGroups.length">
|
||||
<div v-for="group in clientGroups" :key="group.uuid" class="oidc-group" @click="copyText(group.scope, 'Group Value')" :title="group.display_name">
|
||||
<output>{{ group.scope }}</output>
|
||||
</div>
|
||||
<output v-for="group in clientGroups" :key="group.uuid" class="oidc-group" @click="copyText(group.scope, 'Group Value')" :title="group.display_name">{{ group.scope }}</output>
|
||||
</template>
|
||||
<span v-else class="small muted">No permissions defined.</span>
|
||||
<span v-else class="small muted">(no permissions defined)</span>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@@ -236,17 +246,18 @@ defineExpose({ focusFirstElement })
|
||||
|
||||
.oidc-dl dd {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.oidc-dl output {
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 0.85rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
@@ -254,9 +265,8 @@ defineExpose({ focusFirstElement })
|
||||
margin: var(--space-sm) 0 0 0;
|
||||
}
|
||||
|
||||
.oidc-groups { cursor: default; }
|
||||
.oidc-group { cursor: pointer; }
|
||||
.oidc-group output { white-space: normal; word-break: break-all; }
|
||||
.oidc-group { display: block; }
|
||||
.oidc-group { white-space: normal; word-break: break-all; }
|
||||
|
||||
.oidc-divider {
|
||||
border: none;
|
||||
|
||||
@@ -279,6 +279,10 @@ button:disabled {
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
|
||||
output[title="Click to copy"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(to bottom, oklch(1 0 0 / 0.15), transparent 60%) var(--color-accent);
|
||||
color: var(--color-accent-contrast);
|
||||
|
||||
@@ -111,9 +111,8 @@ class ApiSession(msgspec.Struct, omit_defaults=True):
|
||||
user_agent=useragent.compact_user_agent(s.user_agent),
|
||||
last_renewed=s.expiry - expires_delta,
|
||||
is_current=s.key == current_key,
|
||||
is_current_host=not s.client_uuid and bool(
|
||||
normalized_host and s.host and s.host == normalized_host
|
||||
),
|
||||
is_current_host=not s.client_uuid
|
||||
and bool(normalized_host and s.host and s.host == normalized_host),
|
||||
client_uuid=s.client_uuid,
|
||||
client_name=client_name,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user