From 13c3fd211d5e3c7df3c4892818d73468095986b9 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Thu, 29 Feb 2024 14:56:50 +0800 Subject: [PATCH] feat(schemas): update logto_configs table related types --- packages/schemas/src/types/index.ts | 2 +- .../index.ts} | 65 +++++++++++++++- .../src/types/logto-config/oidc-provider.ts | 75 +++++++++++++++++++ 3 files changed, 138 insertions(+), 4 deletions(-) rename packages/schemas/src/types/{logto-config.ts => logto-config/index.ts} (62%) create mode 100644 packages/schemas/src/types/logto-config/oidc-provider.ts diff --git a/packages/schemas/src/types/index.ts b/packages/schemas/src/types/index.ts index cd460391c..d806afa9e 100644 --- a/packages/schemas/src/types/index.ts +++ b/packages/schemas/src/types/index.ts @@ -2,7 +2,7 @@ export * from './connector.js'; export * from './log/index.js'; export * from './oidc-config.js'; export * from './user.js'; -export * from './logto-config.js'; +export * from './logto-config/index.js'; export * from './interactions.js'; export * from './search.js'; export * from './resource.js'; diff --git a/packages/schemas/src/types/logto-config.ts b/packages/schemas/src/types/logto-config/index.ts similarity index 62% rename from packages/schemas/src/types/logto-config.ts rename to packages/schemas/src/types/logto-config/index.ts index 08cc6fda5..d27b586c1 100644 --- a/packages/schemas/src/types/logto-config.ts +++ b/packages/schemas/src/types/logto-config/index.ts @@ -1,6 +1,12 @@ import type { ZodType } from 'zod'; import { z } from 'zod'; +import { jsonObjectGuard } from '../../foundations/index.js'; + +import { accessTokenGuard, clientCredentialsGuard } from './oidc-provider.js'; + +export * from './oidc-provider.js'; + /** * Logto OIDC signing key types, used mainly in REST API routes. */ @@ -45,6 +51,55 @@ export const logtoOidcConfigGuard: Readonly<{ [LogtoOidcConfigKey.CookieKeys]: oidcConfigKeyGuard.array(), }); +/** + * Logto JWT customizer token types, used in REST API routes. + */ +export enum LogtoJwtTokenKeyType { + AccessToken = 'access-token', + ClientCredentials = 'client-credentials', +} + +export enum LogtoJwtTokenKey { + AccessToken = 'jwt.accessToken', + ClientCredentials = 'jwt.clientCredentials', +} + +export const jwtCustomizerGuard = z + .object({ + script: z.string(), + envVars: z.record(z.string()), + contextSample: jsonObjectGuard, + // This `tokenSample` field will be overridden by the `tokenSample` field once the `tokenType` is determined. + tokenSample: jsonObjectGuard, + }) + .partial(); + +export const jwtCustomizerAccessTokenGuard = jwtCustomizerGuard.extend({ + // Use partial token guard since users customization may not rely on all fields. + tokenSample: accessTokenGuard.partial().optional(), +}); + +export type JwtCustomizerAccessToken = z.infer; + +export const jwtCustomizerClientCredentialsGuard = jwtCustomizerGuard.extend({ + // Use partial token guard since users customization may not rely on all fields. + tokenSample: clientCredentialsGuard.partial().optional(), +}); + +export type JwtCustomizerClientCredentials = z.infer; + +export type JwtCustomizerType = { + [LogtoJwtTokenKey.AccessToken]: JwtCustomizerAccessToken; + [LogtoJwtTokenKey.ClientCredentials]: JwtCustomizerClientCredentials; +}; + +export const jwtCustomizerConfigGuard: Readonly<{ + [key in LogtoJwtTokenKey]: ZodType; +}> = Object.freeze({ + [LogtoJwtTokenKey.AccessToken]: jwtCustomizerAccessTokenGuard, + [LogtoJwtTokenKey.ClientCredentials]: jwtCustomizerClientCredentialsGuard, +}); + /* --- Logto tenant configs --- */ export const adminConsoleDataGuard = z.object({ signInExperienceCustomized: z.boolean(), @@ -101,17 +156,21 @@ export const logtoTenantConfigGuard: Readonly<{ }); /* --- Summary --- */ -export type LogtoConfigKey = LogtoOidcConfigKey | LogtoTenantConfigKey; -export type LogtoConfigType = LogtoOidcConfigType | LogtoTenantConfigType; -export type LogtoConfigGuard = typeof logtoOidcConfigGuard & typeof logtoTenantConfigGuard; +export type LogtoConfigKey = LogtoOidcConfigKey | LogtoJwtTokenKey | LogtoTenantConfigKey; +export type LogtoConfigType = LogtoOidcConfigType | JwtCustomizerType | LogtoTenantConfigType; +export type LogtoConfigGuard = typeof logtoOidcConfigGuard & + typeof jwtCustomizerConfigGuard & + typeof logtoTenantConfigGuard; export const logtoConfigKeys: readonly LogtoConfigKey[] = Object.freeze([ ...Object.values(LogtoOidcConfigKey), + ...Object.values(LogtoJwtTokenKey), ...Object.values(LogtoTenantConfigKey), ]); export const logtoConfigGuards: LogtoConfigGuard = Object.freeze({ ...logtoOidcConfigGuard, + ...jwtCustomizerConfigGuard, ...logtoTenantConfigGuard, }); diff --git a/packages/schemas/src/types/logto-config/oidc-provider.ts b/packages/schemas/src/types/logto-config/oidc-provider.ts new file mode 100644 index 000000000..13a0d4e08 --- /dev/null +++ b/packages/schemas/src/types/logto-config/oidc-provider.ts @@ -0,0 +1,75 @@ +/** + * Manually implement zod guards of some node OIDC provider types. + */ +import { z } from 'zod'; + +import { jsonObjectGuard } from '../../foundations/index.js'; + +/** + * Does not include built-in methods. + * Ref: + * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b7b01b70c4c211a4f69caf05008228ac065413c/types/oidc-provider/index.d.ts#L310 + * https://github.com/panva/node-oidc-provider/blob/270af1da83dda4c49edb4aaab48908f737d73379/lib/models/base_model.js#L11 + * https://github.com/panva/node-oidc-provider/blob/270af1da83dda4c49edb4aaab48908f737d73379/lib/models/base_token.js#L62 + */ +const baseTokenGuardObject = { + jti: z.string(), + iat: z.number(), + exp: z.number().optional(), + clientId: z.string().optional(), + kind: z.string(), +}; + +// Ref: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b7b01b70c4c211a4f69caf05008228ac065413c/types/oidc-provider/index.d.ts#L144 +const claimsParameterMemberGuard = z + .object({ + essential: z.boolean(), + value: z.string(), + values: z.array(z.string()), + }) + .partial() + .catchall(jsonObjectGuard); + +// Ref: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b7b01b70c4c211a4f69caf05008228ac065413c/types/oidc-provider/index.d.ts#L152 +const claimsParameterGuard = z.object({ + id_token: z.record(claimsParameterMemberGuard.nullable()).optional(), + userinfo: z.record(claimsParameterMemberGuard.nullable()).optional(), +}); + +/** + * Ref: + * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b7b01b70c4c211a4f69caf05008228ac065413c/types/oidc-provider/index.d.ts#L550 + * https://github.com/panva/node-oidc-provider/blob/270af1da83dda4c49edb4aaab48908f737d73379/lib/models/access_token.js#L17 + */ +export const accessTokenGuard = z + .object({ + ...baseTokenGuardObject, + kind: z.literal('AccessToken'), + accountId: z.string(), + aud: z.string().or(z.array(z.string())), + claims: claimsParameterGuard.optional(), + extra: jsonObjectGuard.optional(), + grantId: z.string(), + scope: z.string().optional(), + sid: z.string().optional(), + }) + .catchall(jsonObjectGuard); + +export type AccessToken = z.infer; + +/** + * Ref: + * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0b7b01b70c4c211a4f69caf05008228ac065413c/types/oidc-provider/index.d.ts#L515 + * https://github.com/panva/node-oidc-provider/blob/270af1da83dda4c49edb4aaab48908f737d73379/lib/models/client_credentials.js#L11 + */ +export const clientCredentialsGuard = z + .object({ + ...baseTokenGuardObject, + kind: z.literal('ClientCredentials'), + aud: z.string().or(z.array(z.string())), + extra: jsonObjectGuard.optional(), + scope: z.string().optional(), + }) + .catchall(jsonObjectGuard); + +export type ClientCredentials = z.infer;