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
*/
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: ({
app,
logger,
sessionService,
appConfig,
redisClient
redisClient,
onUserAuthenticated
}) => {
// Build configuration using shared builder
const baseConfig = buildOidcConfig(appConfig, redisClient);
const config = {
logger,
sessionService,
...buildOidcConfig(appConfig, redisClient)
...baseConfig,
...(onUserAuthenticated ? { onUserAuthenticated } : {})
};
const router = createOidcStandardRoutes(config);
@ -42,4 +52,4 @@ const loadDictElement: LoadDictElement<(path: string | '*') => void> = {
}
};
export default loadDictElement;
export default loadDictElement;

@ -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
*/
export interface OnUserAuthenticatedEvent {
claims: Record<string, any>;
tokenResponse: Record<string, any>;
request: Request;
}
type OnUserAuthenticatedHandler = (event: OnUserAuthenticatedEvent) => Promise<void>;
interface OidcStandardConfig {
logger: any;
sessionService: any;
@ -35,6 +43,9 @@ interface OidcStandardConfig {
// State signing secret (should be different from session secret)
stateSigningSecret: string;
// Optional hook invoked after id_token verification succeeds
onUserAuthenticated?: OnUserAuthenticatedHandler;
}
export function createOidcStandardRoutes(config: OidcStandardConfig): Router {
@ -299,6 +310,19 @@ export function createOidcStandardRoutes(config: OidcStandardConfig): Router {
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
res.clearCookie('rp_nonce', getCookieOptions());
@ -631,4 +655,4 @@ export function createOidcStandardRoutes(config: OidcStandardConfig): Router {
router.post('/auth/logout', logoutHandler);
return router;
}
}

@ -29,4 +29,4 @@ export function buildOidcConfig(appConfig: SwissoidAppConfig, redisClient: Redis
// State signing secret
stateSigningSecret: appConfig.stateSigningSecret || appConfig.sessionSecret + '-state-signing'
};
}
}

Loading…
Cancel
Save