User friendly admin app OIDC Client dialog. Permissions domain scoping to OIDC Clients.

This commit is contained in:
Leo Vasanko
2026-02-16 17:43:52 +00:00
parent b73b2d6fe9
commit e7e0097fba
9 changed files with 179 additions and 87 deletions
+33 -39
View File
@@ -406,18 +406,44 @@ function deletePermission(p) {
}
// OIDC Client actions
function createOidcClient() {
openDialog('oidc-create', { name: '', redirect_uris: '' })
async function createOidcClient() {
try {
// Create the record on the server immediately, then open edit dialog
const result = await apiJson('/auth/api/admin/oidc-clients', { method: 'POST', body: {} })
await loadOidcClients()
openDialog('oidc-edit', {
client_id: result.client_id,
client_secret: result.client_secret,
isNew: true,
name: '',
redirect_uris: ''
})
} catch (e) {
authStore.showMessage(e.message || 'Failed to create OIDC client', 'error')
}
}
function editOidcClient(client) {
openDialog('oidc-edit', {
client,
client_id: client.uuid,
name: client.name,
redirect_uris: client.redirect_uris.join('\n')
})
}
async function resetOidcSecret(clientId) {
try {
const result = await apiJson(`/auth/api/admin/oidc-clients/${clientId}/reset-secret`, { method: 'POST' })
// Update the dialog data in place so the new secret is shown
if (dialog.value.type === 'oidc-edit' && dialog.value.data?.client_id === clientId) {
dialog.value.data.client_secret = result.client_secret
}
authStore.showMessage('Client secret has been reset.', 'success', 2500)
} catch (e) {
authStore.showMessage(e.message || 'Failed to reset client secret', 'error')
}
}
function deleteOidcClient(client) {
openDialog('confirm', {
message: `Delete OIDC client "${client.name}"? This will break any applications using this client.`,
@@ -771,51 +797,18 @@ async function submitDialog() {
authStore.showMessage(e.message || 'Failed to create permission', 'error')
})
return // Don't call closeDialog() again
} else if (t === 'oidc-create') {
const name = dialog.value.data.name?.trim()
const uris = dialog.value.data.redirect_uris?.trim()
if (!name) throw new Error('Client name required')
if (!uris) throw new Error('Redirect URIs required')
const redirect_uris = uris.split('\n').map(u => u.trim()).filter(u => u)
if (redirect_uris.length === 0) throw new Error('At least one redirect URI required')
// Close dialog immediately, then perform async operation
closeDialog()
apiJson('/auth/api/admin/oidc-clients', { method: 'POST', body: { name, redirect_uris } })
.then((result) => {
// Show success dialog with client credentials
openDialog('oidc-created', {
client_id: result.client_id,
client_secret: result.client_secret
})
loadOidcClients()
})
.catch(e => {
authStore.showMessage(e.message || 'Failed to create OIDC client', 'error')
})
return // Don't call closeDialog() again
} else if (t === 'oidc-edit') {
const { client } = dialog.value.data
const { client_id } = dialog.value.data
const name = dialog.value.data.name?.trim()
const uris = dialog.value.data.redirect_uris?.trim()
if (!name) throw new Error('Client name required')
if (!uris) throw new Error('Redirect URIs required')
const redirect_uris = uris.split('\n').map(u => u.trim()).filter(u => u)
if (redirect_uris.length === 0) throw new Error('At least one redirect URI required')
const redirect_uris = uris ? uris.split('\n').map(u => u.trim()).filter(u => u) : []
// Close dialog immediately, then perform async operation
closeDialog()
// Check if anything changed
const oldUris = [...client.redirect_uris].sort().join('\n')
const newUris = [...redirect_uris].sort().join('\n')
if (name === client.name && oldUris === newUris) {
return // No changes
}
apiJson(`/auth/api/admin/oidc-clients/${client.uuid}`, { method: 'PATCH', body: { name, redirect_uris } })
apiJson(`/auth/api/admin/oidc-clients/${client_id}`, { method: 'PATCH', body: { name, redirect_uris } })
.then(() => {
authStore.showMessage(`OIDC client "${name}" updated.`, 'success', 2500)
loadOidcClients()
@@ -942,6 +935,7 @@ async function submitDialog() {
:settings="authStore.settings"
@submit-dialog="submitDialog"
@close-dialog="closeDialog"
@reset-oidc-secret="resetOidcSecret"
/>
</div>
</template>