mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
feat: various application improvements
- show OpenID Provider configuration endpoint in Console - configure "Rotate Refresh Token" in Console - configure "Refresh Token TTL" in Console - refactor code for OIDC default values
This commit is contained in:
parent
4ed72121b8
commit
e3e3f2c729
25 changed files with 267 additions and 24 deletions
1
packages/console/src/consts/oidc.ts
Normal file
1
packages/console/src/consts/oidc.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const openIdProviderConfigPath = 'oidc/.well-known/openid-configuration';
|
|
@ -1,5 +1,6 @@
|
|||
import type { Application, SnakeCaseOidcConfig } from '@logto/schemas';
|
||||
import { ApplicationType } from '@logto/schemas';
|
||||
import { type Application, type SnakeCaseOidcConfig, ApplicationType } from '@logto/schemas';
|
||||
import { appendPath } from '@silverhand/essentials';
|
||||
import { useContext } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -7,7 +8,10 @@ import CopyToClipboard from '@/components/CopyToClipboard';
|
|||
import FormCard from '@/components/FormCard';
|
||||
import FormField from '@/components/FormField';
|
||||
import Switch from '@/components/Switch';
|
||||
import TextInput from '@/components/TextInput';
|
||||
import TextLink from '@/components/TextLink';
|
||||
import { openIdProviderConfigPath } from '@/consts/oidc';
|
||||
import { AppEndpointsContext } from '@/contexts/AppEndpointsProvider';
|
||||
|
||||
import * as styles from '../index.module.scss';
|
||||
|
||||
|
@ -17,7 +21,11 @@ type Props = {
|
|||
};
|
||||
|
||||
function AdvancedSettings({ applicationType, oidcConfig }: Props) {
|
||||
const { register } = useFormContext<Application & { isAdmin?: boolean }>();
|
||||
const { userEndpoint } = useContext(AppEndpointsContext);
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useFormContext<Application & { isAdmin?: boolean }>();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
|
||||
return (
|
||||
|
@ -26,6 +34,15 @@ function AdvancedSettings({ applicationType, oidcConfig }: Props) {
|
|||
description="application_details.advanced_settings_description"
|
||||
learnMoreLink="https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint"
|
||||
>
|
||||
{userEndpoint && (
|
||||
<FormField title="application_details.config_endpoint">
|
||||
<CopyToClipboard
|
||||
className={styles.textField}
|
||||
value={appendPath(userEndpoint, openIdProviderConfigPath).href}
|
||||
variant="border"
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
<FormField
|
||||
title="application_details.authorization_endpoint"
|
||||
tip={(closeTipHandler) => (
|
||||
|
@ -72,6 +89,31 @@ function AdvancedSettings({ applicationType, oidcConfig }: Props) {
|
|||
/>
|
||||
</FormField>
|
||||
)}
|
||||
{[ApplicationType.Traditional, ApplicationType.Native].includes(applicationType) && (
|
||||
<>
|
||||
<FormField title="application_details.rotate_refresh_token">
|
||||
<Switch
|
||||
label={t('application_details.rotate_refresh_token_label')}
|
||||
{...register('customClientMetadata.rotateRefreshToken')}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField
|
||||
title="application_details.refresh_token_ttl"
|
||||
tip={t('application_details.refresh_token_ttl_tip')}
|
||||
>
|
||||
<TextInput
|
||||
{...register('customClientMetadata.refreshTokenTtlInDays', {
|
||||
min: 1,
|
||||
max: 90,
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
placeholder="14"
|
||||
// Confirm if we need a customized message here
|
||||
error={errors.customClientMetadata?.refreshTokenTtlInDays?.message}
|
||||
/>
|
||||
</FormField>
|
||||
</>
|
||||
)}
|
||||
{applicationType === ApplicationType.MachineToMachine && (
|
||||
<FormField title="application_details.enable_admin_access">
|
||||
<Switch
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { withAppInsights } from '@logto/app-insights/react';
|
||||
import type { Application, ApplicationResponse, SnakeCaseOidcConfig } from '@logto/schemas';
|
||||
import { ApplicationType } from '@logto/schemas';
|
||||
import {
|
||||
type Application,
|
||||
type ApplicationResponse,
|
||||
type SnakeCaseOidcConfig,
|
||||
ApplicationType,
|
||||
customClientMetadataDefault,
|
||||
} from '@logto/schemas';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
@ -23,6 +28,7 @@ import PageMeta from '@/components/PageMeta';
|
|||
import TabNav, { TabNavItem } from '@/components/TabNav';
|
||||
import Tag from '@/components/Tag';
|
||||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
||||
import { openIdProviderConfigPath } from '@/consts/oidc';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useDocumentationUrl from '@/hooks/use-documentation-url';
|
||||
|
@ -53,7 +59,7 @@ function ApplicationDetails() {
|
|||
data: oidcConfig,
|
||||
error: fetchOidcConfigError,
|
||||
mutate: mutateOidcConfig,
|
||||
} = useSWR<SnakeCaseOidcConfig, RequestError>('oidc/.well-known/openid-configuration');
|
||||
} = useSWR<SnakeCaseOidcConfig, RequestError>(openIdProviderConfigPath);
|
||||
const isLoading = (!data && !error) || (!oidcConfig && !fetchOidcConfigError);
|
||||
const requestError = error ?? fetchOidcConfigError;
|
||||
const [isReadmeOpen, setIsReadmeOpen] = useState(false);
|
||||
|
@ -62,7 +68,9 @@ function ApplicationDetails() {
|
|||
const [isDeleted, setIsDeleted] = useState(false);
|
||||
const api = useApi();
|
||||
const navigate = useNavigate();
|
||||
const formMethods = useForm<Application & { isAdmin: boolean }>();
|
||||
const formMethods = useForm<Application & { isAdmin: boolean }>({
|
||||
defaultValues: { customClientMetadata: customClientMetadataDefault },
|
||||
});
|
||||
const { getDocumentationUrl } = useDocumentationUrl();
|
||||
|
||||
const {
|
||||
|
|
|
@ -28,8 +28,6 @@ const loadOidcValues = async (issuer: string, configs: LogtoOidcConfigType) => {
|
|||
jwkSigningAlg,
|
||||
localJWKSet,
|
||||
issuer,
|
||||
defaultIdTokenTtl: 60 * 60,
|
||||
defaultRefreshTokenTtl: 14 * 24 * 60 * 60,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
46
packages/core/src/oidc/defaults.ts
Normal file
46
packages/core/src/oidc/defaults.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import type Provider from 'oidc-provider';
|
||||
import { type KoaContextWithOIDC } from 'oidc-provider';
|
||||
|
||||
/**
|
||||
* Keep the default pre-checks from oidc-provider.
|
||||
*
|
||||
* @see {@link https://github.com/panva/node-oidc-provider/blob/d6edf2a0b9efc777081e6f9cc358a0677ccd9897/docs/README.md#ttl | ttl's default value}
|
||||
*/
|
||||
const refreshTokenTtl = (
|
||||
...[ctx, token, client]: Parameters<Provider.TTLFunction<InstanceType<Provider['RefreshToken']>>>
|
||||
) => {
|
||||
if (
|
||||
ctx.oidc.entities.RotatedRefreshToken &&
|
||||
client.applicationType === 'web' &&
|
||||
client.clientAuthMethod === 'none' &&
|
||||
!token.isSenderConstrained()
|
||||
) {
|
||||
// Non-Sender Constrained SPA RefreshTokens do not have infinite expiration through rotation
|
||||
return ctx.oidc.entities.RotatedRefreshToken.remainingTTL;
|
||||
}
|
||||
};
|
||||
|
||||
/** @see {@link https://github.com/panva/node-oidc-provider/blob/d6edf2a0b9efc777081e6f9cc358a0677ccd9897/docs/README.md#rotaterefreshtoken | rotateRefreshToken's default value} */
|
||||
const rotateRefreshToken = (ctx: KoaContextWithOIDC) => {
|
||||
const { RefreshToken: refreshToken, Client: client } = ctx.oidc.entities;
|
||||
|
||||
if (!refreshToken || !client) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cap the maximum amount of time a refresh token can be
|
||||
// rotated for up to 1 year, afterwards its TTL is final
|
||||
if (refreshToken.totalLifetime() >= 365.25 * 24 * 60 * 60) {
|
||||
return false;
|
||||
}
|
||||
// Rotate non sender-constrained public client refresh tokens
|
||||
if (client.clientAuthMethod === 'none' && !refreshToken.isSenderConstrained()) {
|
||||
return true;
|
||||
}
|
||||
// Rotate if the token is nearing expiration (it's beyond 70% of its lifetime)
|
||||
return refreshToken.ttlPercentagePassed() >= 70;
|
||||
};
|
||||
|
||||
const defaults = { refreshTokenTtl, rotateRefreshToken };
|
||||
|
||||
export default defaults;
|
|
@ -5,8 +5,10 @@ import { readFileSync } from 'node:fs';
|
|||
import { userClaims } from '@logto/core-kit';
|
||||
import type { I18nKey } from '@logto/phrases';
|
||||
import {
|
||||
customClientMetadataDefault,
|
||||
CustomClientMetadataKey,
|
||||
demoAppApplicationId,
|
||||
inSeconds,
|
||||
logtoCookieKey,
|
||||
type LogtoUiCookie,
|
||||
} from '@logto/schemas';
|
||||
|
@ -27,6 +29,7 @@ import type Libraries from '#src/tenants/Libraries.js';
|
|||
import type Queries from '#src/tenants/Queries.js';
|
||||
import { consoleLog } from '#src/utils/console.js';
|
||||
|
||||
import defaults from './defaults.js';
|
||||
import { getUserClaimData, getUserClaims } from './scope.js';
|
||||
import { OIDCExtraParametersKey, InteractionMode } from './type.js';
|
||||
|
||||
|
@ -39,14 +42,7 @@ export default function initOidc(
|
|||
queries: Queries,
|
||||
libraries: Libraries
|
||||
): Provider {
|
||||
const {
|
||||
issuer,
|
||||
cookieKeys,
|
||||
privateJwks,
|
||||
jwkSigningAlg,
|
||||
defaultIdTokenTtl,
|
||||
defaultRefreshTokenTtl,
|
||||
} = envSet.oidc;
|
||||
const { issuer, cookieKeys, privateJwks, jwkSigningAlg } = envSet.oidc;
|
||||
const {
|
||||
resources: { findResourceByIndicator, findDefaultResource },
|
||||
users: { findUserById },
|
||||
|
@ -252,12 +248,25 @@ export default function initOidc(
|
|||
IdToken: (_ctx, _token, client) => {
|
||||
const { idTokenTtl } = client.metadata();
|
||||
|
||||
return idTokenTtl ?? defaultIdTokenTtl;
|
||||
return idTokenTtl ?? customClientMetadataDefault.idTokenTtl;
|
||||
},
|
||||
RefreshToken: (_ctx, _token, client) => {
|
||||
const { refreshTokenTtl } = client.metadata();
|
||||
RefreshToken: (ctx, token, client) => {
|
||||
const defaultTtl = defaults.refreshTokenTtl(ctx, token, client);
|
||||
|
||||
return refreshTokenTtl ?? defaultRefreshTokenTtl;
|
||||
if (defaultTtl !== undefined) {
|
||||
return defaultTtl;
|
||||
}
|
||||
|
||||
/** Customized logic for Refresh Token TTL */
|
||||
const { refreshTokenTtlInDays, refreshTokenTtl } = client.metadata();
|
||||
|
||||
if (refreshTokenTtlInDays !== undefined) {
|
||||
return refreshTokenTtlInDays * inSeconds.oneDay;
|
||||
}
|
||||
|
||||
return (
|
||||
refreshTokenTtl ?? customClientMetadataDefault.refreshTokenTtlInDays * inSeconds.oneDay
|
||||
);
|
||||
},
|
||||
AccessToken: (ctx, token) => {
|
||||
if (token.resourceServer) {
|
||||
|
@ -270,6 +279,18 @@ export default function initOidc(
|
|||
Session: 1_209_600 /* 14 days in seconds */,
|
||||
Grant: 1_209_600 /* 14 days in seconds */,
|
||||
},
|
||||
rotateRefreshToken: (ctx) => {
|
||||
const { Client: client } = ctx.oidc.entities;
|
||||
|
||||
// Directly return false only when `rotateRefreshToken` has been explicitly set to `false`.
|
||||
if (
|
||||
!(client?.metadata()?.rotateRefreshToken ?? customClientMetadataDefault.rotateRefreshToken)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return defaults.rotateRefreshToken(ctx);
|
||||
},
|
||||
pkce: {
|
||||
required: (ctx, client) => {
|
||||
return client.clientAuthMethod !== 'client_secret_basic';
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Meine App',
|
||||
description: 'Beschreibung',
|
||||
description_placeholder: 'Gib eine Beschreibung ein',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Autorisierungs-Endpoint',
|
||||
authorization_endpoint_tip:
|
||||
'Der Endpoint, der für die Authentifizierung und <a>Autorisierung</a> via OpenID Connect verwendet wird.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Immer den Refresh Token ausgeben',
|
||||
always_issue_refresh_token_label:
|
||||
'Durch Aktivieren dieser Konfiguration kann Logto immer Refresh Tokens ausgeben, unabhängig davon, ob in der Authentifizierungsanforderung "prompt=consent" angegeben ist. Diese Praxis wird jedoch nur dann empfohlen, wenn es notwendig ist, da sie nicht mit OpenID Connect kompatibel ist und möglicherweise Probleme verursacht.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Diese Aktion kann nicht rückgängig gemacht werden. Die Anwendung wird permanent gelöscht. Bitte gib den Anwendungsnamen <span>{{name}}</span> zur Bestätigung ein.',
|
||||
enter_your_application_name: 'Gib einen Anwendungsnamen ein',
|
||||
|
|
|
@ -12,6 +12,7 @@ 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',
|
||||
authorization_endpoint_tip:
|
||||
"The endpoint to perform authentication and authorization. It's used for OpenID Connect <a>Authentication</a>.",
|
||||
|
@ -43,7 +44,13 @@ const application_details = {
|
|||
'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_label:
|
||||
'Enabling this configuration will allow Logto to 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.',
|
||||
'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 during which a refresh token can be used to request new access tokens before it expires and becomes invalid.',
|
||||
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.',
|
||||
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',
|
||||
|
|
|
@ -12,6 +12,7 @@ const detalles_aplicacion = {
|
|||
application_name_placeholder: 'Mi App',
|
||||
description: 'Descripción',
|
||||
description_placeholder: 'Ingresa la descripción de tu aplicación',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Endpoint de Autorización',
|
||||
authorization_endpoint_tip:
|
||||
'El endpoint para la autenticación y autorización. Se utiliza para OpenID Connect <a>Autenticación</a>.',
|
||||
|
@ -44,6 +45,12 @@ const detalles_aplicacion = {
|
|||
always_issue_refresh_token: 'Siempre emitir Token de Refresco',
|
||||
always_issue_refresh_token_label:
|
||||
'Al habilitar esta configuración, Logto siempre emitirá Tokens de Refresco, independientemente de si se presenta o no “prompt=consent” en la solicitud de autenticación. Sin embargo, esta práctica no está recomendada a menos que sea necesario, ya que no es compatible con OpenID Connect y puede causar problemas potenciales.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Esta acción no se puede deshacer. Eliminará permanentemente la aplicación. Ingresa el nombre de la aplicación <span>{{name}}</span> para confirmar.',
|
||||
enter_your_application_name: 'Ingresa el nombre de tu aplicación',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Mon App',
|
||||
description: 'Description',
|
||||
description_placeholder: 'Entrez la description de votre application',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: "Point de terminaison d'autorisation",
|
||||
authorization_endpoint_tip:
|
||||
"Le point de terminaison pour effectuer l'authentification et l'autorisation. Il est utilisé pour <a>l'authentification</a> OpenID Connect.",
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Toujours émettre le Refresh Token.',
|
||||
always_issue_refresh_token_label:
|
||||
"En activant cette configuration, Logto pourra toujours émettre des Refresh Tokens, indépendamment de la présentation ou non de la demande d'authentification `prompt=consent`. Cependant, cette pratique est découragée sauf si nécessaire, car elle n'est pas compatible avec OpenID Connect et peut potentiellement causer des problèmes.",
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
"Cette action ne peut être annulée. Elle supprimera définitivement l'application. Veuillez entrer le nom de l'application <span>{{nom}}</span> pour confirmer.",
|
||||
enter_your_application_name: 'Entrez le nom de votre application',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'La mia app',
|
||||
description: 'Descrizione',
|
||||
description_placeholder: 'Inserisci la descrizione della tua applicazione',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Authorization Endpoint',
|
||||
authorization_endpoint_tip:
|
||||
"L'endpoint per effettuare l'autenticazione e l'autorizzazione. Viene utilizzato per la connessione OpenID <a>autenticazione</a>.",
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Rilascia sempre il token di aggiornamento',
|
||||
always_issue_refresh_token_label:
|
||||
'Abilitando questa configurazione, Logto potrà rilasciare sempre token di aggiornamento, anche se `prompt=consent` non viene presentata nella richiesta di autenticazione. Tuttavia, questa pratica è scoraggiata a meno che non sia necessaria, in quanto non è compatibile con OpenID Connect e potrebbe potenzialmente causare problemi.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
"Questa azione non può essere annullata. Eliminerà definitivamente l'applicazione. Inserisci il nome dell'applicazione <span>{{name}}</span> per confermare.",
|
||||
enter_your_application_name: 'Inserisci il nome della tua applicazione',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: '私のアプリ',
|
||||
description: '説明',
|
||||
description_placeholder: 'アプリケーションの説明を入力してください',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: '認可エンドポイント',
|
||||
authorization_endpoint_tip:
|
||||
'認証と認可を実行するエンドポイントです。 OpenID Connectの<a>認証</a>に使用されます。',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: '常にRefresh Tokenを発行する',
|
||||
always_issue_refresh_token_label:
|
||||
'この設定を有効にすると、Logtoは、認証要求に「prompt = consent」が提示されたかどうかにかかわらず、常にRefresh Tokenを発行することができます。ただし、OpenID Connectと互換性がないため、必要でない限りこのプラクティスは推奨されず、問題が発生する可能性があります。',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'この操作は元に戻すことはできません。アプリケーション名「<span>{{name}}</span>」を入力して確認してください。',
|
||||
enter_your_application_name: 'アプリケーション名を入力してください',
|
||||
|
|
|
@ -12,7 +12,8 @@ const application_details = {
|
|||
application_name_placeholder: '나의 앱',
|
||||
description: '설명',
|
||||
description_placeholder: '어플리케이션 설명을 적어주세요.',
|
||||
authorization_endpoint: '인증 End-Point',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: '인증 Endpoint',
|
||||
authorization_endpoint_tip:
|
||||
'인증 및 권한 부여를 진행할 End-Point예요. OpenID Connect <a>인증</a>에서 사용되던 값이에요.',
|
||||
application_id: '앱 ID',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: '항상 Refresh Token을 발급하세요',
|
||||
always_issue_refresh_token_label:
|
||||
'다음 구성을 활성화하면 Logto가 인증 요청에 `prompt=consent`가 제시되었는지 여부와 상관없이 항상 Refresh Token을 발급할 수 있게 됩니다. 그러나 OpenID Connect와 호환되지 않으며 문제가 발생할 수 있으므로 필요하지 않은 경우에는 이러한 방법을 권장하지 않습니다. ',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'이 행동은 취소될 수 없어요. 어플리케이션을 영원히 삭제할 거에요. 삭제를 진행하기 위해 <span>{{name}}</span> 를 입력해주세요.',
|
||||
enter_your_application_name: '어플리케이션 이름을 입력해 주세요.',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Moja aplikacja',
|
||||
description: 'Opis',
|
||||
description_placeholder: 'Wpisz opis swojej aplikacji',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Endpoint autoryzacji',
|
||||
authorization_endpoint_tip:
|
||||
'Endpoint wykorzystywany do autentykacji i autoryzacji. Używany jest dla OpenID Connect <a>Autentykacji</a>.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Zawsze wydawaj Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'Rozwiazanie tej konfiguracji pozwoli Logto zawsze wydawac cwiecze tokeny, bez wzgledu na to, czy w zadaniu autoryzacji zostal przedstawiony `prompt=consent`. Jednak ta praktyka jest odstraszana, chyba ze konieczne, jak nie jest w pelni kompatybilna z OpenID Connect i moze potencjalnie powodowac problemy.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Ta operacja nie może zostać cofnięta. Skutkuje ona trwałym usunięciem aplikacji. Aby potwierdzić, wpisz nazwę aplikacji <span>{{name}}</span>.',
|
||||
enter_your_application_name: 'Wpisz nazwę swojej aplikacji',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Meu aplicativo',
|
||||
description: 'Descrição',
|
||||
description_placeholder: 'Digite a descrição do seu aplicativo',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Endpoint de autorização',
|
||||
authorization_endpoint_tip:
|
||||
'O endpoint para executar autenticação e autorização. É usado para <a>autenticação</a> OpenID Connect.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Emitir sempre o token de refresh',
|
||||
always_issue_refresh_token_label:
|
||||
'Ativar esta configuração permitirá que a Logto emita sempre tokens de Refresh, independentemente de "prompt=consent" ser apresentado na solicitação de autenticação. No entanto, essa prática é desencorajada, a menos que seja necessária, pois não é compatível com o OpenID Connect e pode potencialmente causar problemas.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Essa ação não pode ser desfeita. Isso excluirá permanentemente o aplicativo. Insira o nome do aplicativo <span>{{name}}</span> para confirmar.',
|
||||
enter_your_application_name: 'Digite o nome do seu aplicativo',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Ex: Site da Empresa',
|
||||
description: 'Descrição',
|
||||
description_placeholder: 'Insira a descrição da sua aplicação',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Endpoint de autorização',
|
||||
authorization_endpoint_tip:
|
||||
'O endpoint para realizar a autenticação e autorização. É usado para <a>autenticação</a> OpenID Connect.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Sempre emitir Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'Ao ativar essa configuração, a Logto sempre emitirá tokens de atualização, independentemente de `prompt=consent`ser apresentado na solicitação de autenticação. No entanto, essa prática é desencorajada, a menos que seja necessária, pois não é compatível com OpenID Connect e pode causar problemas.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Esta ação não pode ser revertida. Esta ação irá eliminar permanentemente a aplicação. Insira o nome da aplicação <span>{{name}}</span> para confirmar.',
|
||||
enter_your_application_name: 'Insira o nome da aplicação',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Мое приложение',
|
||||
description: 'Описание',
|
||||
description_placeholder: 'Введите описание своего приложения',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Конечная точка авторизации',
|
||||
authorization_endpoint_tip:
|
||||
'Конечная точка для аутентификации и авторизации. Он используется для аутентификации <a> OpenID Connect </a>.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Всегда выдавать Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'Включение этой настройки позволит Logto всегда выдавать Refresh Tokens, независимо от того, была ли в запросе на аутентификацию предложена команда `prompt=consent`. Однако данная практика не рекомендуется, если это необходимо, поскольку она несовместима с OpenID Connect и может вызвать проблемы.',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Это действие нельзя отменить. Оно навсегда удалит приложение. Введите название приложения <span> {{name}} </span>, чтобы подтвердить.',
|
||||
enter_your_application_name: 'Введите название своего приложения',
|
||||
|
|
|
@ -12,6 +12,7 @@ const application_details = {
|
|||
application_name_placeholder: 'Uygulamam',
|
||||
description: 'Açıklama',
|
||||
description_placeholder: 'Uygulama açıklamasını giriniz',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: 'Yetkilendirme bitiş noktası',
|
||||
authorization_endpoint_tip:
|
||||
'Kimlik doğrulama ve yetkilendirme gerçekleştirmek için bitiş noktası. OpenID Connect <a>Authentication</a> için kullanılır.',
|
||||
|
@ -44,6 +45,12 @@ const application_details = {
|
|||
always_issue_refresh_token: 'Her zaman Refresh Token ver',
|
||||
always_issue_refresh_token_label:
|
||||
"Bu yapılandırmayı etkinleştirmek, Logto'nun OpenID Connect ile uyumlu olmayan ve olası sorunlara neden olabilecek her zaman Refresh Token çıkarmasına izin verir `prompt=consent` kimlik doğrulama isteğinin sunulup sunulmadığına bakılmaksızın. Ancak, bu uygulama yalnızca zorunlu olduğunda caydırılmayan bir uygulamadır.",
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'Bu eylem geri alınamaz. Uygulama kalıcı olarak silinecektir. Lütfen onaylamak için uygulama adı <span>{{name}}</span> girin.',
|
||||
enter_your_application_name: 'Uygulama adı giriniz',
|
||||
|
|
|
@ -11,6 +11,7 @@ const application_details = {
|
|||
application_name_placeholder: '我的应用',
|
||||
description: '描述',
|
||||
description_placeholder: '请输入应用描述',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: '授权端点',
|
||||
authorization_endpoint_tip: '进行鉴权与授权的端点。用于 OpenID Connect 中的 <a>鉴权</a> 流程。',
|
||||
application_id: '应用 ID',
|
||||
|
@ -42,6 +43,12 @@ const application_details = {
|
|||
always_issue_refresh_token: '总是颁发 Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'启用此配置将允许 Logto 始终颁发 Refresh Token,无论身份验证请求中是否呈现 `prompt=consent`。 然而,除非必要,否则不推荐这样做,因为它与 OpenID Connect 不兼容,可能会导致问题。',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description: '本操作会永久性地删除该应用,且不可撤销。输入 <span>{{name}}</span> 确认。',
|
||||
enter_your_application_name: '输入你的应用名称',
|
||||
application_deleted: '应用 {{name}} 成功删除。',
|
||||
|
|
|
@ -11,6 +11,7 @@ const application_details = {
|
|||
application_name_placeholder: '我的應用程式',
|
||||
description: '描述',
|
||||
description_placeholder: '請輸入應用程式描述',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: '授權端點',
|
||||
authorization_endpoint_tip: '進行驗證和授權的端點。用於 OpenID Connect 中的<a> 驗證 </a> 流程。',
|
||||
application_id: '應用程式 ID',
|
||||
|
@ -42,6 +43,12 @@ const application_details = {
|
|||
always_issue_refresh_token: '始終發放 Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'啟用此配置將允許 Logto 始終發行 Refresh Token,無論是否在驗證請求中呈現 `prompt=consent`。但是,除非必要,否則不建議這樣做,因為它不兼容 OpenID Connect,可能會引起問題。',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description: '本操作會永久性地刪除該應用,且不可撤銷。輸入 <span>{{name}}</span> 確認。',
|
||||
enter_your_application_name: '輸入你的應用程式名稱',
|
||||
application_deleted: '應用 {{name}} 成功刪除。',
|
||||
|
|
|
@ -11,6 +11,7 @@ const application_details = {
|
|||
application_name_placeholder: '我的應用程式',
|
||||
description: '說明',
|
||||
description_placeholder: '請輸入應用程式說明',
|
||||
config_endpoint: 'OpenID Provider configuration endpoint', // UNTRANSLATED
|
||||
authorization_endpoint: '授權端點',
|
||||
authorization_endpoint_tip: '進行驗證與授權的端點。用於 OpenID Connect 中的 <a>驗證</a> 流程。',
|
||||
application_id: '應用程式 ID',
|
||||
|
@ -42,6 +43,12 @@ const application_details = {
|
|||
always_issue_refresh_token: '始終發放 Refresh Token',
|
||||
always_issue_refresh_token_label:
|
||||
'啟用此配置將使 Logto 無論在驗證請求中是否提供 prompt=consent,都能始終發放 Refresh Token。然而,除非必要,否則不鼓勵這種做法,因為它與 OpenID Connect 不相容並可能引起問題。',
|
||||
refresh_token_ttl: 'Refresh Token Time to Live (TTL) in days', // UNTRANSLATED
|
||||
refresh_token_ttl_tip:
|
||||
'The duration during which a refresh token can be used to request new access tokens before it expires and becomes invalid.', // UNTRANSLATED
|
||||
rotate_refresh_token: 'Rotate Refresh Token', // UNTRANSLATED
|
||||
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.', // UNTRANSLATED
|
||||
delete_description:
|
||||
'本操作會永久性地刪除該應用程式,且不可撤銷。輸入 <span>{{name}}</span> 確認。',
|
||||
enter_your_application_name: '輸入你的應用程式姓名',
|
||||
|
|
1
packages/schemas/src/consts/date.ts
Normal file
1
packages/schemas/src/consts/date.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const inSeconds = Object.freeze({ oneMinute: 60, oneHour: 60 * 60, oneDay: 24 * 60 * 60 });
|
|
@ -1,3 +1,4 @@
|
|||
export * from './cookie.js';
|
||||
export * from './system.js';
|
||||
export * from './oidc.js';
|
||||
export * from './date.js';
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
import { type CustomClientMetadata } from '../foundations/jsonb-types.js';
|
||||
|
||||
import { inSeconds } from './date.js';
|
||||
|
||||
export const tenantIdKey = 'tenant_id';
|
||||
|
||||
export const customClientMetadataDefault = Object.freeze({
|
||||
idTokenTtl: inSeconds.oneHour,
|
||||
refreshTokenTtlInDays: 14,
|
||||
rotateRefreshToken: true,
|
||||
} as const satisfies Partial<CustomClientMetadata>);
|
||||
|
|
|
@ -67,7 +67,9 @@ export type OidcClientMetadata = z.infer<typeof oidcClientMetadataGuard>;
|
|||
export enum CustomClientMetadataKey {
|
||||
CorsAllowedOrigins = 'corsAllowedOrigins',
|
||||
IdTokenTtl = 'idTokenTtl',
|
||||
/** @deprecated Use {@link RefreshTokenTtlInDays} instead. */
|
||||
RefreshTokenTtl = 'refreshTokenTtl',
|
||||
RefreshTokenTtlInDays = 'refreshTokenTtlInDays',
|
||||
TenantId = 'tenantId',
|
||||
/**
|
||||
* Enabling this configuration will allow Logto to always issue Refresh Tokens, regardless of whether `prompt=consent` is presented in the authentication request.
|
||||
|
@ -77,15 +79,23 @@ export enum CustomClientMetadataKey {
|
|||
* This config is for the third-party integrations that do not strictly follow OpenID Connect standards due to some reasons (e.g. they only know OAuth, but requires a Refresh Token to be returned anyway).
|
||||
*/
|
||||
AlwaysIssueRefreshToken = 'alwaysIssueRefreshToken',
|
||||
/**
|
||||
* When enabled (default), Logto will issue a new Refresh Token for token requests when 70% of the original Time to Live (TTL) has passed.
|
||||
*
|
||||
* It can be turned off for only traditional web apps for enhanced security.
|
||||
*/
|
||||
RotateRefreshToken = 'rotateRefreshToken',
|
||||
}
|
||||
|
||||
export const customClientMetadataGuard = z.object({
|
||||
[CustomClientMetadataKey.CorsAllowedOrigins]: z.string().url().array().optional(),
|
||||
[CustomClientMetadataKey.IdTokenTtl]: z.number().optional(),
|
||||
[CustomClientMetadataKey.RefreshTokenTtl]: z.number().optional(),
|
||||
[CustomClientMetadataKey.RefreshTokenTtlInDays]: z.number().optional(),
|
||||
[CustomClientMetadataKey.TenantId]: z.string().optional(),
|
||||
[CustomClientMetadataKey.AlwaysIssueRefreshToken]: z.boolean().optional(),
|
||||
});
|
||||
[CustomClientMetadataKey.RotateRefreshToken]: z.boolean().optional(),
|
||||
} satisfies Record<CustomClientMetadataKey, z.ZodType>);
|
||||
|
||||
/**
|
||||
* @see {@link CustomClientMetadataKey} for key descriptions.
|
||||
|
|
Loading…
Add table
Reference in a new issue