mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(core,console): enable backchannel logout
This commit is contained in:
parent
da5c71d916
commit
f28a083ed0
7 changed files with 105 additions and 17 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -54,6 +54,7 @@
|
|||
"timestamptz",
|
||||
"topbar",
|
||||
"upsell",
|
||||
"withtyped"
|
||||
"withtyped",
|
||||
"backchannel"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import { type Application } from '@logto/schemas';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
|
||||
import FormCard from '@/components/FormCard';
|
||||
import FormField from '@/ds-components/FormField';
|
||||
import Switch from '@/ds-components/Switch';
|
||||
import TextInput from '@/ds-components/TextInput';
|
||||
|
||||
function BackchannelLogout() {
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useFormContext<Application>();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
return (
|
||||
<FormCard
|
||||
title="application_details.backchannel_logout"
|
||||
description="application_details.backchannel_logout_description"
|
||||
learnMoreLink={{ href: 'https://openid.net/specs/openid-connect-backchannel-1_0-final.html' }}
|
||||
>
|
||||
<FormField title="application_details.backchannel_logout_uri">
|
||||
<TextInput
|
||||
error={errors.oidcClientMetadata?.backchannelLogoutUri?.message}
|
||||
placeholder="https://your.website.com/backchannel_logout"
|
||||
{...register('oidcClientMetadata.backchannelLogoutUri', {
|
||||
validate: (value) =>
|
||||
z.string().url().optional().safeParse(value).success ||
|
||||
t('errors.invalid_uri_format'),
|
||||
})}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField title="application_details.backchannel_logout_uri_session_required">
|
||||
<Switch
|
||||
label={
|
||||
<Trans i18nKey="admin_console.application_details.backchannel_logout_uri_session_required_description" />
|
||||
}
|
||||
{...register('oidcClientMetadata.backchannelLogoutSessionRequired')}
|
||||
/>
|
||||
</FormField>
|
||||
</FormCard>
|
||||
);
|
||||
}
|
||||
|
||||
export default BackchannelLogout;
|
|
@ -36,6 +36,7 @@ import RefreshTokenSettings from './RefreshTokenSettings';
|
|||
import Settings from './Settings';
|
||||
import * as styles from './index.module.scss';
|
||||
import { type ApplicationForm, applicationFormDataParser } from './utils';
|
||||
import BackchannelLogout from './BackchannelLogout';
|
||||
|
||||
type Props = {
|
||||
readonly data: ApplicationResponse;
|
||||
|
@ -204,6 +205,7 @@ function ApplicationDetailsContent({ data, oidcConfig, onApplicationUpdated }: P
|
|||
{![ApplicationType.MachineToMachine, ApplicationType.Protected].includes(data.type) && (
|
||||
<RefreshTokenSettings data={data} />
|
||||
)}
|
||||
<BackchannelLogout />
|
||||
</DetailsForm>
|
||||
</FormProvider>
|
||||
{tab === ApplicationDetailsTabs.Settings && (
|
||||
|
|
|
@ -112,6 +112,7 @@ export default function initOidc(
|
|||
introspection: { enabled: true },
|
||||
devInteractions: { enabled: false },
|
||||
clientCredentials: { enabled: true },
|
||||
backchannelLogout: { enabled: true },
|
||||
rpInitiatedLogout: {
|
||||
logoutSource: (ctx, form) => {
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
|
|
|
@ -22,8 +22,8 @@ const application_details = {
|
|||
application_name_placeholder: 'My App',
|
||||
description: 'Description',
|
||||
description_placeholder: 'Enter your application description',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint',
|
||||
authorization_endpoint: 'Authorization Endpoint',
|
||||
config_endpoint: 'OpenID provider configuration endpoint',
|
||||
authorization_endpoint: 'Authorization endpoint',
|
||||
authorization_endpoint_tip:
|
||||
"The endpoint to perform authentication and authorization. It's used for OpenID Connect <a>Authentication</a>.",
|
||||
show_endpoint_details: 'Show endpoint details',
|
||||
|
@ -39,8 +39,8 @@ const application_details = {
|
|||
redirect_uri_placeholder_native: 'io.logto://callback',
|
||||
redirect_uri_tip:
|
||||
'The URI redirects after a user sign-in (whether successful or not). See OpenID Connect <a>AuthRequest</a> for more info.',
|
||||
post_sign_out_redirect_uri: 'Post Sign-out Redirect URI',
|
||||
post_sign_out_redirect_uris: 'Post Sign-out Redirect URIs',
|
||||
post_sign_out_redirect_uri: 'Post sign-out redirect URI',
|
||||
post_sign_out_redirect_uris: 'Post sign-out redirect URIs',
|
||||
post_sign_out_redirect_uri_placeholder: 'https://your.website.com/home',
|
||||
post_sign_out_redirect_uri_tip:
|
||||
'The URI redirects after a user sign-out (optional). It may have no practical effect in some app types.',
|
||||
|
@ -48,20 +48,27 @@ const application_details = {
|
|||
cors_allowed_origins_placeholder: 'https://your.website.com',
|
||||
cors_allowed_origins_tip:
|
||||
'By default, all the origins of Redirect URIs will be allowed. Usually no action is required for this field. See the <a>MDN doc</a> for detailed info.',
|
||||
token_endpoint: 'Token Endpoint',
|
||||
user_info_endpoint: 'Userinfo Endpoint',
|
||||
token_endpoint: 'Token endpoint',
|
||||
user_info_endpoint: 'Userinfo endpoint',
|
||||
enable_admin_access: 'Enable admin access',
|
||||
enable_admin_access_label:
|
||||
'Enable or disable the access to Management API. Once enabled, you can use access tokens to call Management API on behalf on this application.',
|
||||
always_issue_refresh_token: 'Always issue Refresh Token',
|
||||
always_issue_refresh_token: 'Always issue refresh token',
|
||||
always_issue_refresh_token_label:
|
||||
'When enabled, Logto will always issue Refresh Tokens, regardless of whether `prompt=consent` is presented in the authentication request. However, this practice is discouraged unless necessary, as it is not compatible with OpenID Connect and may potentially cause issues.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days',
|
||||
'When enabled, Logto will always issue refresh tokens, regardless of whether `prompt=consent` is presented in the authentication request. However, this practice is discouraged unless necessary, as it is not compatible with OpenID Connect and may potentially cause issues.',
|
||||
refresh_token_ttl: 'Refresh token time to live (TTL) in days',
|
||||
refresh_token_ttl_tip:
|
||||
'The duration for which a Refresh Token can be used to request new access tokens before it expires and becomes invalid. Token requests will extend the TTL of the Refresh Token to this value.',
|
||||
rotate_refresh_token: 'Rotate Refresh Token',
|
||||
'The duration for which a refresh token can be used to request new access tokens before it expires and becomes invalid. Token requests will extend the TTL of the refresh token to this value.',
|
||||
rotate_refresh_token: 'Rotate refresh token',
|
||||
rotate_refresh_token_label:
|
||||
'When enabled, Logto will issue a new Refresh Token for token requests when 70% of the original Time to Live (TTL) has passed or certain conditions are met. <a>Learn more</a>',
|
||||
'When enabled, Logto will issue a new refresh token for token requests when 70% of the original time to live (TTL) has passed or certain conditions are met. <a>Learn more</a>',
|
||||
backchannel_logout: 'Backchannel Logout',
|
||||
backchannel_logout_description:
|
||||
'Configure the OpenID Connect backchannel logout endpoint and if session is required for this application.',
|
||||
backchannel_logout_uri: 'Backchannel logout URI',
|
||||
backchannel_logout_uri_session_required: 'Is session required?',
|
||||
backchannel_logout_uri_session_required_description:
|
||||
'When enabled, the RP requires that a `sid` (session ID) claim be included in the logout token to identify the RP session with the OP when the `backchannel_logout_uri` is used.',
|
||||
delete_description:
|
||||
'This action cannot be undone. It will permanently delete the application. Please enter the application name <span>{{name}}</span> to confirm.',
|
||||
enter_your_application_name: 'Enter your application name',
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { validateRedirectUrl } from '@logto/core-kit';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { type ToZodObject } from '../../utils/zod.js';
|
||||
|
||||
export const oidcModelInstancePayloadGuard = z
|
||||
.object({
|
||||
userCode: z.string().optional(),
|
||||
|
@ -15,6 +17,34 @@ export const oidcModelInstancePayloadGuard = z
|
|||
|
||||
export type OidcModelInstancePayload = z.infer<typeof oidcModelInstancePayloadGuard>;
|
||||
|
||||
export type OidcClientMetadata = {
|
||||
/**
|
||||
* The redirect URIs that the client is allowed to use.
|
||||
*
|
||||
* @see {@link https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata | OpenID Connect Dynamic Client Registration 1.0}
|
||||
*/
|
||||
redirectUris: string[];
|
||||
/**
|
||||
* The post-logout redirect URIs that the client is allowed to use.
|
||||
*
|
||||
* @see {@link https://openid.net/specs/openid-connect-rpinitiated-1_0.html#ClientMetadata | OpenID Connect RP-Initiated Logout 1.0}
|
||||
*/
|
||||
postLogoutRedirectUris: string[];
|
||||
/**
|
||||
* The URI for backchannel logout.
|
||||
*
|
||||
* @see {@link https://openid.net/specs/openid-connect-backchannel-1_0-final.html#BCRegistration | OpenID Connect Back-Channel Logout 1.0}
|
||||
*/
|
||||
backchannelLogoutUri?: string;
|
||||
/**
|
||||
* Whether the RP requires that a `sid` (session ID) Claim be included in the Logout Token.
|
||||
*
|
||||
* @see {@link https://openid.net/specs/openid-connect-backchannel-1_0-final.html#BCRegistration | OpenID Connect Back-Channel Logout 1.0}
|
||||
*/
|
||||
backchannelLogoutSessionRequired?: boolean;
|
||||
logoUri?: string;
|
||||
};
|
||||
|
||||
export const oidcClientMetadataGuard = z.object({
|
||||
redirectUris: z
|
||||
.string()
|
||||
|
@ -22,10 +52,10 @@ export const oidcClientMetadataGuard = z.object({
|
|||
.or(z.string().refine((url) => validateRedirectUrl(url, 'mobile')))
|
||||
.array(),
|
||||
postLogoutRedirectUris: z.string().url().array(),
|
||||
backchannelLogoutUri: z.string().url().optional(),
|
||||
backchannelLogoutSessionRequired: z.boolean().optional(),
|
||||
logoUri: z.string().optional(),
|
||||
});
|
||||
|
||||
export type OidcClientMetadata = z.infer<typeof oidcClientMetadataGuard>;
|
||||
}) satisfies ToZodObject<OidcClientMetadata>;
|
||||
|
||||
export enum CustomClientMetadataKey {
|
||||
CorsAllowedOrigins = 'corsAllowedOrigins',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { type z } from 'zod';
|
||||
|
||||
export type ToZodObject<T> = z.ZodObject<{
|
||||
[K in keyof T]: z.ZodType<T[K]>;
|
||||
[K in keyof T]-?: z.ZodType<T[K]>;
|
||||
}>;
|
||||
|
|
Loading…
Reference in a new issue