mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-06 17:59:03 +02:00
feat: restore old behavior of automatically creating client secret
This commit is contained in:
@@ -7,6 +7,7 @@ import type {
|
||||
InteractionStep,
|
||||
OidcClient,
|
||||
OidcClientCreate,
|
||||
OidcClientCreated,
|
||||
OidcClientMetaData,
|
||||
OidcClientSecret,
|
||||
OidcClientSecretCreated,
|
||||
@@ -42,7 +43,7 @@ class OidcService extends APIService {
|
||||
};
|
||||
|
||||
createClient = async (client: OidcClientCreate) =>
|
||||
(await this.api.post('/oidc/clients', client)).data as OidcClient;
|
||||
(await this.api.post('/oidc/clients', client)).data as OidcClientCreated;
|
||||
|
||||
removeClient = async (id: string) => {
|
||||
await this.api.delete(`/oidc/clients/${encodeClientIdParam(id)}`);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { writable } from 'svelte/store';
|
||||
// Holds the clear-text value of the client secrets created during the current page visit, keyed by secret ID.
|
||||
// The server never returns those values again, so they are shown until the user navigates away and then forgotten.
|
||||
const clientSecretStore = writable<Record<string, string>>({});
|
||||
export const autoCreatedSecretId = writable<string | null>(null);
|
||||
|
||||
const set = (secretId: string, secret: string) => {
|
||||
clientSecretStore.update((secrets) => ({ ...secrets, [secretId]: secret }));
|
||||
@@ -18,11 +19,18 @@ const remove = (secretId: string) => {
|
||||
|
||||
const clear = () => {
|
||||
clientSecretStore.set({});
|
||||
autoCreatedSecretId.set(null);
|
||||
};
|
||||
|
||||
const setAutoCreated = (secretId: string, secret: string) => {
|
||||
set(secretId, secret);
|
||||
autoCreatedSecretId.set(secretId);
|
||||
};
|
||||
|
||||
export default {
|
||||
subscribe: clientSecretStore.subscribe,
|
||||
set,
|
||||
setAutoCreated,
|
||||
remove,
|
||||
clear
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@ export type AllAppConfig = AppConfig & {
|
||||
webauthnAuthenticatorAttachment: 'any' | 'platform' | 'cross-platform';
|
||||
// OIDC
|
||||
cimdUrlAllowlist: string[];
|
||||
autoCreateOidcClientSecret: boolean;
|
||||
};
|
||||
|
||||
export type AppConfigRawResponse = {
|
||||
|
||||
@@ -68,6 +68,10 @@ export type OidcClient = OidcClientMetaData & {
|
||||
refreshTokenDurationMinutes: number;
|
||||
};
|
||||
|
||||
export type OidcClientCreated = OidcClient & {
|
||||
createdSecret?: OidcClientSecretCreated;
|
||||
};
|
||||
|
||||
export type OidcClientTokenLifetimes = Pick<
|
||||
OidcClient,
|
||||
'accessTokenDurationMinutes' | 'refreshTokenDurationMinutes'
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import type { AllAppConfig } from '$lib/types/application-configuration.type';
|
||||
import { LucideInfo } from '@lucide/svelte';
|
||||
import AppConfigDynamicClientsForm from './forms/app-config-dynamic-clients-form.svelte';
|
||||
import AppConfigClientSecretsForm from './forms/app-config-client-secrets-form.svelte';
|
||||
import AppConfigEmailForm from './forms/app-config-email-form.svelte';
|
||||
import AppConfigGeneralForm from './forms/app-config-general-form.svelte';
|
||||
import AppConfigLdapForm from './forms/app-config-ldap-form.svelte';
|
||||
@@ -191,7 +192,16 @@
|
||||
</Card.Root>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="oidc" id="application-configuration-oidc">
|
||||
<Tabs.Content value="oidc" id="application-configuration-oidc" class="flex flex-col gap-4">
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>{m.general()}</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<AppConfigClientSecretsForm {appConfig} callback={updateAppConfig} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>{m.client_id_metadata_documents()}</Card.Title>
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import SwitchWithLabel from '$lib/components/form/switch-with-label.svelte';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import appConfigStore from '$lib/stores/application-configuration-store';
|
||||
import type { AllAppConfig } from '$lib/types/application-configuration.type';
|
||||
import { createForm } from '$lib/utils/form-util';
|
||||
import { trackFormChanges } from '$lib/utils/unsaved-changes-util.svelte';
|
||||
import { z } from 'zod/v4';
|
||||
|
||||
let {
|
||||
appConfig,
|
||||
callback
|
||||
}: {
|
||||
appConfig: AllAppConfig;
|
||||
callback: (appConfig: Partial<AllAppConfig>) => Promise<void>;
|
||||
} = $props();
|
||||
|
||||
const formSchema = z.object({ autoCreateOidcClientSecret: z.boolean() });
|
||||
let formStore = $derived(
|
||||
createForm(formSchema, { autoCreateOidcClientSecret: appConfig.autoCreateOidcClientSecret })
|
||||
);
|
||||
let inputs = $derived(formStore.inputs);
|
||||
|
||||
trackFormChanges(() => formStore, callback);
|
||||
</script>
|
||||
|
||||
<fieldset disabled={$appConfigStore.uiConfigDisabled}>
|
||||
<SwitchWithLabel
|
||||
id="auto-create-oidc-client-secret"
|
||||
label={m.auto_create_client_secret()}
|
||||
description={m.auto_create_client_secret_description()}
|
||||
bind:checked={$inputs.autoCreateOidcClientSecret.value}
|
||||
/>
|
||||
</fieldset>
|
||||
@@ -21,6 +21,12 @@
|
||||
async function createOIDCClient(client: OidcClientCreateWithLogo) {
|
||||
clientSecretStore.clear();
|
||||
const createdClient = await oidcService.createClient(client);
|
||||
if (createdClient.createdSecret) {
|
||||
clientSecretStore.setAutoCreated(
|
||||
createdClient.createdSecret.id,
|
||||
createdClient.createdSecret.secret
|
||||
);
|
||||
}
|
||||
|
||||
const logoPromise = client.logo
|
||||
? oidcService.updateClientLogo(createdClient, client.logo, true)
|
||||
@@ -30,7 +36,6 @@
|
||||
: Promise.resolve();
|
||||
await Promise.all([logoPromise, darkLogoPromise]);
|
||||
|
||||
// A new client starts without any secret: the admin creates the ones they need from the credentials tab
|
||||
goto(`/settings/admin/oidc-clients/${encodeClientIdParam(createdClient.id)}`);
|
||||
toast.success(m.oidc_client_created_successfully());
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import OidcService from '$lib/services/oidc-service';
|
||||
import ScimService from '$lib/services/scim-service';
|
||||
import clientSecretStore from '$lib/stores/client-secret-store';
|
||||
import clientSecretStore, { autoCreatedSecretId } from '$lib/stores/client-secret-store';
|
||||
import type {
|
||||
OidcClientCreateWithLogo,
|
||||
OidcClientCredentials,
|
||||
@@ -251,6 +251,16 @@
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
{#if $autoCreatedSecretId && clientSecrets.some((secret) => secret.id === $autoCreatedSecretId) && $clientSecretStore[$autoCreatedSecretId]}
|
||||
<div class="mb-2 flex flex-col sm:flex-row sm:items-center">
|
||||
<Field.Label class="w-52">{m.client_secret()}</Field.Label>
|
||||
<CopyToClipboard value={$clientSecretStore[$autoCreatedSecretId]}>
|
||||
<span class="text-muted-foreground text-sm break-all" data-testid="client-secret">
|
||||
{$clientSecretStore[$autoCreatedSecretId]}
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</div>
|
||||
{/if}
|
||||
{#if showAllDetails}
|
||||
<div transition:slide>
|
||||
{#each Object.entries(setupDetails) as [key, value] (key)}
|
||||
|
||||
Reference in New Issue
Block a user