mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-02-10 03:14:19 +00:00
feat: allow custom client IDs (#864)
This commit is contained in:
@@ -4,6 +4,7 @@ import type {
|
||||
OidcClient,
|
||||
OidcClientCreate,
|
||||
OidcClientMetaData,
|
||||
OidcClientUpdate,
|
||||
OidcClientWithAllowedUserGroups,
|
||||
OidcClientWithAllowedUserGroupsCount,
|
||||
OidcDeviceCodeInfo
|
||||
@@ -67,7 +68,7 @@ class OidcService extends APIService {
|
||||
return (await this.api.get(`/oidc/clients/${id}/meta`)).data as OidcClientMetaData;
|
||||
}
|
||||
|
||||
async updateClient(id: string, client: OidcClientCreate) {
|
||||
async updateClient(id: string, client: OidcClientUpdate) {
|
||||
return (await this.api.put(`/oidc/clients/${id}`, client)).data as OidcClient;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,13 @@ export type OidcClientWithAllowedUserGroupsCount = OidcClient & {
|
||||
allowedUserGroupsCount: number;
|
||||
};
|
||||
|
||||
export type OidcClientCreate = Omit<OidcClient, 'id' | 'logoURL' | 'hasLogo'>;
|
||||
export type OidcClientUpdate = Omit<OidcClient, 'id' | 'logoURL' | 'hasLogo'>;
|
||||
export type OidcClientCreate = OidcClientUpdate & {
|
||||
id?: string;
|
||||
};
|
||||
export type OidcClientUpdateWithLogo = OidcClientUpdate & {
|
||||
logo: File | null | undefined;
|
||||
};
|
||||
|
||||
export type OidcClientCreateWithLogo = OidcClientCreate & {
|
||||
logo: File | null | undefined;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import z from 'zod/v4';
|
||||
|
||||
export const optionalString = z
|
||||
.string()
|
||||
.transform((v) => (v === '' ? undefined : v))
|
||||
.optional();
|
||||
export const emptyToUndefined = <T>(validation: z.ZodType<T>) =>
|
||||
z.preprocess((v) => (v === '' ? undefined : v), validation);
|
||||
|
||||
export const optionalUrl = z
|
||||
.url()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import type { ApiKeyCreate } from '$lib/types/api-key.type';
|
||||
import { preventDefault } from '$lib/utils/event-util';
|
||||
import { createForm } from '$lib/utils/form-util';
|
||||
import { optionalString } from '$lib/utils/zod-util';
|
||||
import { emptyToUndefined } from '$lib/utils/zod-util';
|
||||
import { z } from 'zod/v4';
|
||||
|
||||
let {
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().min(3).max(50),
|
||||
description: optionalString,
|
||||
description: emptyToUndefined(z.string().optional()),
|
||||
expiresAt: z.date().min(new Date(), m.expiration_date_must_be_in_the_future())
|
||||
});
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
{#if expandAddClient}
|
||||
<div transition:slide>
|
||||
<Card.Content>
|
||||
<OIDCClientForm callback={createOIDCClient} />
|
||||
<OIDCClientForm mode="create" callback={createOIDCClient} />
|
||||
</Card.Content>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
</Card.Root>
|
||||
<Card.Root>
|
||||
<Card.Content>
|
||||
<OidcForm existingClient={client} callback={updateClient} />
|
||||
<OidcForm mode="update" existingClient={client} callback={updateClient} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<CollapsibleCard
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import Label from '$lib/components/ui/label/label.svelte';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import type { OidcClient, OidcClientCreateWithLogo } from '$lib/types/oidc.type';
|
||||
import type {
|
||||
OidcClient,
|
||||
OidcClientCreateWithLogo,
|
||||
OidcClientUpdateWithLogo
|
||||
} from '$lib/types/oidc.type';
|
||||
import { cachedOidcClientLogo } from '$lib/utils/cached-image-util';
|
||||
import { preventDefault } from '$lib/utils/event-util';
|
||||
import { createForm } from '$lib/utils/form-util';
|
||||
import { cn } from '$lib/utils/style';
|
||||
import { optionalUrl } from '$lib/utils/zod-util';
|
||||
import { emptyToUndefined, optionalUrl } from '$lib/utils/zod-util';
|
||||
import { LucideChevronDown } from '@lucide/svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { z } from 'zod/v4';
|
||||
@@ -20,10 +24,12 @@
|
||||
|
||||
let {
|
||||
callback,
|
||||
existingClient
|
||||
existingClient,
|
||||
mode
|
||||
}: {
|
||||
existingClient?: OidcClient;
|
||||
callback: (user: OidcClientCreateWithLogo) => Promise<boolean>;
|
||||
callback: (client: OidcClientCreateWithLogo | OidcClientUpdateWithLogo) => Promise<boolean>;
|
||||
mode: 'create' | 'update';
|
||||
} = $props();
|
||||
|
||||
let isLoading = $state(false);
|
||||
@@ -34,6 +40,7 @@
|
||||
);
|
||||
|
||||
const client = {
|
||||
id: '',
|
||||
name: existingClient?.name || '',
|
||||
callbackURLs: existingClient?.callbackURLs || [],
|
||||
logoutCallbackURLs: existingClient?.logoutCallbackURLs || [],
|
||||
@@ -47,6 +54,16 @@
|
||||
};
|
||||
|
||||
const formSchema = z.object({
|
||||
id: emptyToUndefined(
|
||||
z
|
||||
.string()
|
||||
.min(2)
|
||||
.max(128)
|
||||
.regex(/^[a-zA-Z0-9_-]+$/, {
|
||||
message: m.invalid_client_id()
|
||||
})
|
||||
.optional()
|
||||
),
|
||||
name: z.string().min(2).max(50),
|
||||
callbackURLs: z.array(z.string().nonempty()).default([]),
|
||||
logoutCallbackURLs: z.array(z.string().nonempty()),
|
||||
@@ -185,7 +202,16 @@
|
||||
</div>
|
||||
|
||||
{#if showAdvancedOptions}
|
||||
<div class="mt-5 md:col-span-2" transition:slide={{ duration: 200 }}>
|
||||
<div class="mt-7 flex flex-col gap-y-7 md:col-span-2" transition:slide={{ duration: 200 }}>
|
||||
{#if mode == 'create'}
|
||||
<FormInput
|
||||
label={m.client_id()}
|
||||
placeholder={m.generated()}
|
||||
class="w-full md:w-1/2"
|
||||
description={m.custom_client_id_description()}
|
||||
bind:input={$inputs.id}
|
||||
/>
|
||||
{/if}
|
||||
<FederatedIdentitiesInput
|
||||
client={existingClient}
|
||||
bind:federatedIdentities={$inputs.credentials.value.federatedIdentities}
|
||||
|
||||
Reference in New Issue
Block a user