0
Fork 0
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:
Gao Sun 2024-06-07 22:12:24 +08:00
parent da5c71d916
commit f28a083ed0
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
7 changed files with 105 additions and 17 deletions

View file

@ -54,6 +54,7 @@
"timestamptz",
"topbar",
"upsell",
"withtyped"
"withtyped",
"backchannel"
]
}

View file

@ -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;

View file

@ -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 && (

View file

@ -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

View file

@ -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',

View file

@ -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',

View file

@ -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]>;
}>;