0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-27 21:39:16 -05:00

feat(core,schemas): log extraTokenClaims exception (#5539)

This commit is contained in:
Darcy Ye 2024-04-02 15:19:52 +08:00 committed by GitHub
parent 866c58e233
commit e09318d3e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 10 deletions

View file

@ -1,4 +1,4 @@
import type { AuditLogKey, LogKey, WebhookLogKey } from '@logto/schemas';
import type { AuditLogKey, WebhookLogKey, JwtCustomizerLogKey, LogKey } from '@logto/schemas';
import { type Optional } from '@silverhand/essentials';
export const auditLogEventTitle: Record<string, Optional<string>> &
@ -86,7 +86,14 @@ const webhookLogEventTitle: Record<string, Optional<string>> &
'TriggerHook.PostSignIn': undefined,
});
const jwtCustomizerLogEventTitle: Record<string, Optional<string>> &
Record<JwtCustomizerLogKey, Optional<string>> = Object.freeze({
'JwtCustomizer.AccessToken': undefined,
'JwtCustomizer.ClientCredentials': undefined,
});
export const logEventTitle: Record<string, Optional<string>> & Record<LogKey, Optional<string>> = {
...auditLogEventTitle,
...webhookLogEventTitle,
...jwtCustomizerLogEventTitle,
};

View file

@ -21,7 +21,7 @@ import { type WebhookDetailsOutletContext } from '../types';
import * as styles from './index.module.scss';
const hooLogEventOptions = Object.values(HookEvent).map((event) => ({
const hookLogEventOptions = Object.values(HookEvent).map((event) => ({
title: <DynamicT forKey={hookEventLabel[event]} />,
value: hookEventLogKey[event],
}));
@ -64,7 +64,7 @@ function WebhookLogs() {
<div className={styles.eventSelector}>
<EventSelector
value={event}
options={hooLogEventOptions}
options={hookLogEventOptions}
onChange={(event) => {
updateSearchParameters({ event, page: undefined });
}}

View file

@ -17,7 +17,10 @@ import {
LogtoJwtTokenPath,
ExtraParamsKey,
type Json,
jwtCustomizer as jwtCustomizerLog,
LogResult,
} from '@logto/schemas';
import { generateStandardId } from '@logto/shared';
import { conditional, trySafe, tryThat } from '@silverhand/essentials';
import i18next from 'i18next';
import koaBody from 'koa-body';
@ -29,7 +32,7 @@ import RequestError from '#src/errors/RequestError/index.js';
import { addOidcEventListeners } from '#src/event-listeners/index.js';
import { type CloudConnectionLibrary } from '#src/libraries/cloud-connection.js';
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
import koaAuditLog from '#src/middleware/koa-audit-log.js';
import koaAuditLog, { LogEntry } from '#src/middleware/koa-audit-log.js';
import koaBodyEtag from '#src/middleware/koa-body-etag.js';
import postgresAdapter from '#src/oidc/adapter.js';
import {
@ -65,6 +68,7 @@ export default function initOidc(
resources: { findDefaultResource },
users: { findUserById },
organizations,
logs: { insertLog },
} = queries;
const logoutSource = readFileSync('static/html/logout.html', 'utf8');
const logoutSuccessSource = readFileSync('static/html/post-logout/index.html', 'utf8');
@ -206,7 +210,7 @@ export default function initOidc(
},
},
extraParams: Object.values(ExtraParamsKey),
// eslint-disable-next-line complexity
extraTokenClaims: async (ctx, token) => {
const { isDevFeaturesEnabled, isCloud } = EnvSet.values;
@ -215,9 +219,14 @@ export default function initOidc(
return;
}
try {
const isTokenClientCredentials = token instanceof ctx.oidc.provider.ClientCredentials;
const isTokenClientCredentials = token instanceof ctx.oidc.provider.ClientCredentials;
try {
/**
* It is by design to use `trySafe` here to catch the error but not log it since we do not
* want to insert an error log every time the OIDC provider issues a token when the JWT
* customizer is not configured.
*/
const { script, envVars } =
(await trySafe(
logtoConfigs.getJwtCustomizer(
@ -270,8 +279,28 @@ export default function initOidc(
context: { user: logtoUserInfo as Record<string, Json> },
},
});
} catch {
// TODO: Log the error
} catch (error: unknown) {
const entry = new LogEntry(
`${jwtCustomizerLog.prefix}.${
isTokenClientCredentials
? jwtCustomizerLog.Type.ClientCredentials
: jwtCustomizerLog.Type.AccessToken
}`
);
entry.append({
result: LogResult.Error,
error: { message: String(error) },
});
const { payload } = entry;
await insertLog({
id: generateStandardId(),
key: payload.key,
payload: {
...payload,
tenantId: envSet.tenantId,
token,
},
});
}
},
extraClientMetadata: {

View file

@ -1,16 +1,19 @@
import type * as hook from './hook.js';
import type * as interaction from './interaction.js';
import type * as jwtCustomizer from './jwt-customizer.js';
import type * as token from './token.js';
export * as interaction from './interaction.js';
export * as token from './token.js';
export * as hook from './hook.js';
export * as jwtCustomizer from './jwt-customizer.js';
/** Fallback for empty or unrecognized log keys. */
export const LogKeyUnknown = 'Unknown';
export type AuditLogKey = typeof LogKeyUnknown | interaction.LogKey | token.LogKey;
export type WebhookLogKey = hook.LogKey;
export type JwtCustomizerLogKey = jwtCustomizer.LogKey;
/**
* The union type of all available log keys.
@ -19,4 +22,4 @@ export type WebhookLogKey = hook.LogKey;
* @see {@link interaction.LogKey} for interaction log keys.
* @see {@link token.LogKey} for token log keys.
**/
export type LogKey = AuditLogKey | WebhookLogKey;
export type LogKey = AuditLogKey | WebhookLogKey | JwtCustomizerLogKey;

View file

@ -0,0 +1,11 @@
export type Prefix = 'JwtCustomizer';
export const prefix: Prefix = 'JwtCustomizer';
/** The type of a custom JWT scenario. */
export enum Type {
AccessToken = 'AccessToken',
ClientCredentials = 'ClientCredentials',
}
export type LogKey = `${Prefix}.${Type.AccessToken | Type.ClientCredentials}`;