feat: onUserAuthenticated hook

master
Guillermo Pages 3 months ago
parent 318a3de0b0
commit 40bf4b1647

@ -8,18 +8,28 @@ import { buildOidcConfig } from '../oidc/oidcConfigBuilder';
* Compatible with express-knifey's middleware system * Compatible with express-knifey's middleware system
*/ */
const loadDictElement: LoadDictElement<(path: string | '*') => void> = { const loadDictElement: LoadDictElement<(path: string | '*') => void> = {
before: async ({ serviceLocator, deps }) => {
if (serviceLocator.couldLoad('oidcUserRegistrar')) {
const onUserAuthenticated = await serviceLocator.get('oidcUserRegistrar');
return { ...deps, onUserAuthenticated };
}
return deps;
},
factory: ({ factory: ({
app, app,
logger, logger,
sessionService, sessionService,
appConfig, appConfig,
redisClient redisClient,
onUserAuthenticated
}) => { }) => {
// Build configuration using shared builder // Build configuration using shared builder
const baseConfig = buildOidcConfig(appConfig, redisClient);
const config = { const config = {
logger, logger,
sessionService, sessionService,
...buildOidcConfig(appConfig, redisClient) ...baseConfig,
...(onUserAuthenticated ? { onUserAuthenticated } : {})
}; };
const router = createOidcStandardRoutes(config); const router = createOidcStandardRoutes(config);

@ -0,0 +1,11 @@
import type { MiddlewareHandle } from 'express-knifey';
export const SWISSOID_MIDDLEWARE = {
oidcStandardRoutes: {
name: 'oidcStandardRoutesMiddleware',
defaultPriority: 50,
defaultPath: '*',
} satisfies MiddlewareHandle,
} as const;
export type SwissoidMiddlewareHandle = typeof SWISSOID_MIDDLEWARE[keyof typeof SWISSOID_MIDDLEWARE];

@ -11,6 +11,14 @@ import { jwtVerify, createRemoteJWKSet, SignJWT } from 'jose';
* Using stateless signed state to avoid third-party cookie issues * Using stateless signed state to avoid third-party cookie issues
*/ */
export interface OnUserAuthenticatedEvent {
claims: Record<string, any>;
tokenResponse: Record<string, any>;
request: Request;
}
type OnUserAuthenticatedHandler = (event: OnUserAuthenticatedEvent) => Promise<void>;
interface OidcStandardConfig { interface OidcStandardConfig {
logger: any; logger: any;
sessionService: any; sessionService: any;
@ -35,6 +43,9 @@ interface OidcStandardConfig {
// State signing secret (should be different from session secret) // State signing secret (should be different from session secret)
stateSigningSecret: string; stateSigningSecret: string;
// Optional hook invoked after id_token verification succeeds
onUserAuthenticated?: OnUserAuthenticatedHandler;
} }
export function createOidcStandardRoutes(config: OidcStandardConfig): Router { export function createOidcStandardRoutes(config: OidcStandardConfig): Router {
@ -299,6 +310,19 @@ export function createOidcStandardRoutes(config: OidcStandardConfig): Router {
return res.status(401).send('Nonce mismatch'); return res.status(401).send('Nonce mismatch');
} }
if (config.onUserAuthenticated) {
try {
await config.onUserAuthenticated({
claims: payload,
tokenResponse: tokenData,
request: req,
});
} catch (handlerError) {
logger.error('onUserAuthenticated handler failed', handlerError);
return res.status(500).send('Unable to process user registration');
}
}
// Clear the optional nonce cookie if it was set // Clear the optional nonce cookie if it was set
res.clearCookie('rp_nonce', getCookieOptions()); res.clearCookie('rp_nonce', getCookieOptions());

Loading…
Cancel
Save