function getAuthenticateUserExpressHandler<const UserKey extends string>({
allowedAudience,
requiredAppId,
userKey,
}: {
allowedAudience: string;
requiredAppId: number | undefined;
userKey: UserKey;
}) {
return async (req: Request, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization;
if (!authHeader) {
res.status(401).json({ error: 'No token provided' });
return;
}
const parts = authHeader.split(' ');
if (parts.length !== 2) {
res.status(401).json({ error: `Invalid authorization header - expected "Bearer <token>"` });
return;
}
const [scheme, rawJWT] = parts;
if (!/^Bearer$/i.test(scheme)) {
res.status(401).json({ error: `Expected "Bearer" scheme, got "${scheme}"` });
return;
}
try {
const decodedJWT =
requiredAppId != null
? await verifyVincentAppUserJWT({
jwt: rawJWT,
expectedAudience: allowedAudience,
requiredAppId,
})
: await verifyVincentPlatformJWT({
jwt: rawJWT,
expectedAudience: allowedAudience,
});
if (!decodedJWT) {
res.status(401).json({ error: 'Invalid token' });
return;
}
(req as unknown as Record<string, VincentJWTData>)[userKey] = {
decodedJWT,
rawJWT,
} as VincentJWTData;
next();
} catch (e) {
res.status(401).json({ error: `Invalid token: ${(e as Error).message}` });
}
};
}