mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
feat(application): set idToken and refreshToken ttl based on client metadata (#176)
* feat(application): set idtoken and refresh token ttl based on client metadata add idToken and refreshToken ttl metadata * fix(application): cr fix cr fix add default constant & set custom client metadata not null
This commit is contained in:
parent
59cd617b2b
commit
77be675bfb
7 changed files with 55 additions and 13 deletions
6
packages/core/src/include.d/oidc-provider.d.ts
vendored
Normal file
6
packages/core/src/include.d/oidc-provider.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { CustomClientMetadata } from '@logto/schemas';
|
||||
import { AllClientMetadata } from 'oidc-provider';
|
||||
|
||||
declare module 'oidc-provider' {
|
||||
export interface AllClientMetadata extends CustomClientMetadata {}
|
||||
}
|
|
@ -23,6 +23,7 @@ export default function postgresAdapter(modelName: string): ReturnType<AdapterFa
|
|||
name: client_name,
|
||||
type,
|
||||
oidcClientMetadata,
|
||||
customClientMetadata,
|
||||
}: ApplicationUpdate): AllClientMetadata => ({
|
||||
client_id,
|
||||
client_name,
|
||||
|
@ -30,6 +31,7 @@ export default function postgresAdapter(modelName: string): ReturnType<AdapterFa
|
|||
grant_types: ['authorization_code', 'refresh_token'],
|
||||
token_endpoint_auth_method: 'none',
|
||||
...snakecaseKeys(oidcClientMetadata),
|
||||
...customClientMetadata, // OIDC Provider won't camelcase custom parameter keys
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -11,3 +11,6 @@ export const publicKey = crypto.createPublicKey(privateKey);
|
|||
|
||||
export const issuer = getEnv('OIDC_ISSUER', `http://localhost:${port}/oidc`);
|
||||
export const adminResource = getEnv('ADMIN_RESOURCE', 'https://api.logto.io');
|
||||
|
||||
export const defaultIdTokenTtl = 60 * 60;
|
||||
export const defaultRefreshTokenTtl = 14 * 24 * 60 * 60;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { customClientMetadataGuard, CustomClientMetadataType } from '@logto/schemas';
|
||||
import { fromKeyLike } from 'jose/jwk/from_key_like';
|
||||
import Koa from 'koa';
|
||||
import mount from 'koa-mount';
|
||||
|
@ -9,7 +10,7 @@ import { findAllScopesWithResourceId } from '@/queries/scopes';
|
|||
import { findUserById } from '@/queries/user';
|
||||
import { routes } from '@/routes/consts';
|
||||
|
||||
import { issuer, privateKey } from './consts';
|
||||
import { issuer, privateKey, defaultIdTokenTtl, defaultRefreshTokenTtl } from './consts';
|
||||
|
||||
export default async function initOidc(app: Koa): Promise<Provider> {
|
||||
const keys = [await fromKeyLike(privateKey)];
|
||||
|
@ -71,6 +72,15 @@ export default async function initOidc(app: Koa): Promise<Provider> {
|
|||
}
|
||||
},
|
||||
},
|
||||
extraClientMetadata: {
|
||||
properties: Object.keys(CustomClientMetadataType),
|
||||
validator: (_ctx, key, value) => {
|
||||
const result = customClientMetadataGuard.pick({ [key]: true }).safeParse({ key: value });
|
||||
if (!result.success) {
|
||||
throw new errors.InvalidClientMetadata(key);
|
||||
}
|
||||
},
|
||||
},
|
||||
clientBasedCORS: (_, origin) => {
|
||||
console.log('origin', origin);
|
||||
return origin.startsWith('http://localhost:3000');
|
||||
|
@ -89,6 +99,19 @@ export default async function initOidc(app: Koa): Promise<Provider> {
|
|||
},
|
||||
};
|
||||
},
|
||||
ttl: {
|
||||
/**
|
||||
* [OIDC Provider Default Settings](https://github.com/panva/node-oidc-provider/blob/main/docs/README.md#ttl)
|
||||
*/
|
||||
IdToken: (ctx, token, client) => {
|
||||
const { idTokenTtl } = client.metadata();
|
||||
return idTokenTtl ?? defaultIdTokenTtl;
|
||||
},
|
||||
RefreshToken: (ctx, token, client) => {
|
||||
const { refreshTokenTtl } = client.metadata();
|
||||
return refreshTokenTtl ?? defaultRefreshTokenTtl;
|
||||
},
|
||||
},
|
||||
});
|
||||
app.use(mount('/oidc', oidc.app));
|
||||
return oidc;
|
||||
|
|
|
@ -5,6 +5,8 @@ import { z } from 'zod';
|
|||
import {
|
||||
OidcClientMetadata,
|
||||
oidcClientMetadataGuard,
|
||||
CustomClientMetadata,
|
||||
customClientMetadataGuard,
|
||||
GeneratedSchema,
|
||||
Guard,
|
||||
} from '../foundations';
|
||||
|
@ -16,8 +18,7 @@ export type ApplicationUpdate = {
|
|||
description?: string | null;
|
||||
type: ApplicationType;
|
||||
oidcClientMetadata: OidcClientMetadata;
|
||||
idTokenTtl?: number;
|
||||
refreshTokenTtl?: number;
|
||||
customClientMetadata?: CustomClientMetadata;
|
||||
createdAt?: number;
|
||||
};
|
||||
|
||||
|
@ -27,8 +28,7 @@ export type Application = {
|
|||
description: string | null;
|
||||
type: ApplicationType;
|
||||
oidcClientMetadata: OidcClientMetadata;
|
||||
idTokenTtl: number;
|
||||
refreshTokenTtl: number;
|
||||
customClientMetadata: CustomClientMetadata;
|
||||
createdAt: number;
|
||||
};
|
||||
|
||||
|
@ -38,8 +38,7 @@ const guard: Guard<ApplicationUpdate> = z.object({
|
|||
description: z.string().optional(),
|
||||
type: z.nativeEnum(ApplicationType),
|
||||
oidcClientMetadata: oidcClientMetadataGuard,
|
||||
idTokenTtl: z.number().optional(),
|
||||
refreshTokenTtl: z.number().optional(),
|
||||
customClientMetadata: customClientMetadataGuard.optional(),
|
||||
createdAt: z.number().optional(),
|
||||
});
|
||||
|
||||
|
@ -52,8 +51,7 @@ export const Applications: GeneratedSchema<ApplicationUpdate> = Object.freeze({
|
|||
description: 'description',
|
||||
type: 'type',
|
||||
oidcClientMetadata: 'oidc_client_metadata',
|
||||
idTokenTtl: 'id_token_ttl',
|
||||
refreshTokenTtl: 'refresh_token_ttl',
|
||||
customClientMetadata: 'custom_client_metadata',
|
||||
createdAt: 'created_at',
|
||||
},
|
||||
fieldKeys: [
|
||||
|
@ -62,8 +60,7 @@ export const Applications: GeneratedSchema<ApplicationUpdate> = Object.freeze({
|
|||
'description',
|
||||
'type',
|
||||
'oidcClientMetadata',
|
||||
'idTokenTtl',
|
||||
'refreshTokenTtl',
|
||||
'customClientMetadata',
|
||||
'createdAt',
|
||||
],
|
||||
guard,
|
||||
|
|
|
@ -22,6 +22,18 @@ export const oidcClientMetadataGuard = z.object({
|
|||
|
||||
export type OidcClientMetadata = z.infer<typeof oidcClientMetadataGuard>;
|
||||
|
||||
export enum CustomClientMetadataType {
|
||||
idTokenTtl = 'idTokenTtl',
|
||||
refreshTokenTtl = 'refreshTokenTtl',
|
||||
}
|
||||
|
||||
export const customClientMetadataGuard = z.object({
|
||||
[CustomClientMetadataType.idTokenTtl]: z.number().optional(),
|
||||
[CustomClientMetadataType.refreshTokenTtl]: z.number().optional(),
|
||||
});
|
||||
|
||||
export type CustomClientMetadata = z.infer<typeof customClientMetadataGuard>;
|
||||
|
||||
export const userLogPayloadGuard = z.object({
|
||||
ip: z.string().optional(),
|
||||
userAgent: z.string().optional(),
|
||||
|
|
|
@ -6,8 +6,7 @@ create table applications (
|
|||
description text,
|
||||
type application_type not null,
|
||||
oidc_client_metadata jsonb /* @use OidcClientMetadata */ not null,
|
||||
id_token_ttl bigint not null default(86400),
|
||||
refresh_token_ttl bigint not null default(2592000),
|
||||
custom_client_metadata jsonb /* @use CustomClientMetadata */ not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default(now()),
|
||||
primary key (id)
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue