mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-01 07:19:05 +02:00
feat(oauth): add support for Pushed Authorization Requests (RFC9126) (#1404)
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
co-authored by
Elias Schneider
parent
2eada149af
commit
68a5abdcca
@@ -24,7 +24,8 @@ class OidcService extends APIService {
|
||||
codeChallengeMethod?: string,
|
||||
reauthenticationToken?: string,
|
||||
responseMode?: string,
|
||||
prompt?: string
|
||||
prompt?: string,
|
||||
requestURI?: string
|
||||
) => {
|
||||
const res = await this.api.post('/oidc/authorize', {
|
||||
scope,
|
||||
@@ -35,19 +36,21 @@ class OidcService extends APIService {
|
||||
codeChallengeMethod,
|
||||
reauthenticationToken,
|
||||
responseMode,
|
||||
prompt
|
||||
prompt,
|
||||
requestURI
|
||||
});
|
||||
|
||||
return res.data as AuthorizeResponse;
|
||||
};
|
||||
|
||||
isAuthorizationRequired = async (clientId: string, scope: string) => {
|
||||
isAuthorizationRequired = async (clientId: string, scope: string, requestURI?: string) => {
|
||||
const res = await this.api.post('/oidc/authorization-required', {
|
||||
scope,
|
||||
clientId
|
||||
clientId,
|
||||
requestURI
|
||||
});
|
||||
|
||||
return res.data.authorizationRequired as boolean;
|
||||
return res.data as { authorizationRequired: boolean; scope: string };
|
||||
};
|
||||
|
||||
listClients = async (options?: ListRequestOptions) => {
|
||||
|
||||
@@ -26,6 +26,7 @@ export type OidcClient = OidcClientMetaData & {
|
||||
isPublic: boolean;
|
||||
pkceEnabled: boolean;
|
||||
requiresReauthentication: boolean;
|
||||
requiresPushedAuthorizationRequests: boolean;
|
||||
credentials?: OidcClientCredentials;
|
||||
launchURL?: string;
|
||||
isGroupRestricted: boolean;
|
||||
|
||||
@@ -25,16 +25,16 @@
|
||||
let { data }: PageProps = $props();
|
||||
let {
|
||||
client,
|
||||
scope,
|
||||
callbackURL,
|
||||
nonce,
|
||||
codeChallenge,
|
||||
codeChallengeMethod,
|
||||
authorizeState,
|
||||
prompt,
|
||||
responseMode
|
||||
responseMode,
|
||||
requestURI
|
||||
} = data;
|
||||
|
||||
let scope = $state(data.scope);
|
||||
let isLoading = $state(false);
|
||||
let success = $state(false);
|
||||
let errorMessage: string | null = $state(null);
|
||||
@@ -112,7 +112,16 @@
|
||||
}
|
||||
|
||||
if (!authorizationConfirmed) {
|
||||
authorizationRequired = await oidService.isAuthorizationRequired(client!.id, scope);
|
||||
const authRequired = await oidService.isAuthorizationRequired(
|
||||
client!.id,
|
||||
scope,
|
||||
requestURI
|
||||
);
|
||||
authorizationRequired = authRequired.authorizationRequired;
|
||||
|
||||
if (requestURI) {
|
||||
scope = authRequired.scope;
|
||||
}
|
||||
|
||||
// If prompt=consent, always show consent UI
|
||||
if (hasPromptConsent) {
|
||||
@@ -153,7 +162,8 @@
|
||||
codeChallengeMethod,
|
||||
reauthToken,
|
||||
responseMode,
|
||||
prompt
|
||||
prompt,
|
||||
requestURI
|
||||
);
|
||||
|
||||
// Check if backend returned a redirect error
|
||||
|
||||
@@ -16,6 +16,7 @@ export const load: PageLoad = async ({ url }) => {
|
||||
codeChallenge: url.searchParams.get('code_challenge')!,
|
||||
codeChallengeMethod: url.searchParams.get('code_challenge_method')!,
|
||||
prompt: url.searchParams.get('prompt') || undefined,
|
||||
responseMode: url.searchParams.get('response_mode') || undefined
|
||||
responseMode: url.searchParams.get('response_mode') || undefined,
|
||||
requestURI: url.searchParams.get('request_uri') || undefined
|
||||
};
|
||||
};
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
[m.logout_url()]: `https://${page.url.host}/api/oidc/end-session`,
|
||||
[m.certificate_url()]: `https://${page.url.host}/.well-known/jwks.json`,
|
||||
[m.pkce()]: client.pkceEnabled ? m.enabled() : m.disabled(),
|
||||
[m.requires_reauthentication()]: client.requiresReauthentication ? m.enabled() : m.disabled()
|
||||
[m.requires_reauthentication()]: client.requiresReauthentication ? m.enabled() : m.disabled(),
|
||||
[m.requires_pushed_authorization_requests()]: client.requiresPushedAuthorizationRequests
|
||||
? m.enabled()
|
||||
: m.disabled()
|
||||
});
|
||||
|
||||
async function updateClient(updatedClient: OidcClientCreateWithLogo) {
|
||||
@@ -71,6 +74,8 @@
|
||||
|
||||
await Promise.all([dataPromise, imagePromise, darkImagePromise])
|
||||
.then(() => {
|
||||
setupDetails[m.requires_pushed_authorization_requests()] =
|
||||
updatedClient.requiresPushedAuthorizationRequests ? m.enabled() : m.disabled();
|
||||
if (updatedClient.logoUrl) {
|
||||
cachedOidcClientLogo.bustCache(client.id, true);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
isPublic: existingClient?.isPublic || false,
|
||||
pkceEnabled: existingClient?.pkceEnabled || false,
|
||||
requiresReauthentication: existingClient?.requiresReauthentication || false,
|
||||
requiresPushedAuthorizationRequests:
|
||||
existingClient?.requiresPushedAuthorizationRequests || false,
|
||||
launchURL: existingClient?.launchURL || '',
|
||||
credentials: {
|
||||
federatedIdentities: existingClient?.credentials?.federatedIdentities || []
|
||||
@@ -74,6 +76,7 @@
|
||||
isPublic: z.boolean(),
|
||||
pkceEnabled: z.boolean(),
|
||||
requiresReauthentication: z.boolean(),
|
||||
requiresPushedAuthorizationRequests: z.boolean(),
|
||||
launchURL: optionalUrl,
|
||||
logoUrl: optionalUrl,
|
||||
darkLogoUrl: optionalUrl,
|
||||
@@ -205,6 +208,7 @@
|
||||
onCheckedChange={(v) => {
|
||||
if (v) {
|
||||
$inputs.pkceEnabled.value = true;
|
||||
$inputs.requiresPushedAuthorizationRequests.value = false;
|
||||
}
|
||||
}}
|
||||
bind:checked={$inputs.isPublic.value}
|
||||
@@ -270,6 +274,13 @@
|
||||
|
||||
{#if showAdvancedOptions}
|
||||
<div class="mt-7 flex flex-col gap-y-7 md:col-span-2" transition:slide={{ duration: 200 }}>
|
||||
<SwitchWithLabel
|
||||
id="requires-par"
|
||||
label={m.requires_pushed_authorization_requests()}
|
||||
description={m.requires_pushed_authorization_requests_description()}
|
||||
disabled={$inputs.isPublic.value}
|
||||
bind:checked={$inputs.requiresPushedAuthorizationRequests.value}
|
||||
/>
|
||||
{#if mode == 'create'}
|
||||
<FormInput
|
||||
label={m.client_id()}
|
||||
|
||||
@@ -59,6 +59,13 @@
|
||||
sortable: true,
|
||||
filterableValues: booleanFilterValues
|
||||
},
|
||||
{
|
||||
label: m.par(),
|
||||
column: 'requiresPushedAuthorizationRequests',
|
||||
sortable: true,
|
||||
hidden: true,
|
||||
filterableValues: booleanFilterValues
|
||||
},
|
||||
{
|
||||
label: m.client_launch_url(),
|
||||
column: 'launchURL',
|
||||
|
||||
Reference in New Issue
Block a user