Phase 2 + 3 complete
This commit is contained in:
parent
9a3fc97a34
commit
6d24f3c112
25 changed files with 3275 additions and 98 deletions
82
server/src/middleware/auth.ts
Normal file
82
server/src/middleware/auth.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { Request, Response, NextFunction } from 'express';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import jwksClient from 'jwks-rsa';
|
||||
|
||||
const OIDC_ISSUER = process.env.OIDC_ISSUER || 'http://localhost:9000/application/o/kaboot/';
|
||||
const OIDC_JWKS_URI = process.env.OIDC_JWKS_URI || 'http://localhost:9000/application/o/kaboot/jwks/';
|
||||
const OIDC_INTERNAL_JWKS_URI = process.env.OIDC_INTERNAL_JWKS_URI || OIDC_JWKS_URI;
|
||||
|
||||
const client = jwksClient({
|
||||
jwksUri: OIDC_INTERNAL_JWKS_URI,
|
||||
cache: true,
|
||||
cacheMaxAge: 600000,
|
||||
rateLimit: true,
|
||||
jwksRequestsPerMinute: 10,
|
||||
});
|
||||
|
||||
function getSigningKey(header: jwt.JwtHeader, callback: jwt.SigningKeyCallback): void {
|
||||
if (!header.kid) {
|
||||
callback(new Error('No kid in token header'));
|
||||
return;
|
||||
}
|
||||
client.getSigningKey(header.kid, (err, key) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
const signingKey = key?.getPublicKey();
|
||||
callback(null, signingKey);
|
||||
});
|
||||
}
|
||||
|
||||
export interface AuthenticatedUser {
|
||||
sub: string;
|
||||
preferred_username: string;
|
||||
email?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface AuthenticatedRequest extends Request {
|
||||
user?: AuthenticatedUser;
|
||||
}
|
||||
|
||||
export function requireAuth(
|
||||
req: AuthenticatedRequest,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): void {
|
||||
const authHeader = req.headers.authorization;
|
||||
|
||||
if (!authHeader?.startsWith('Bearer ')) {
|
||||
res.status(401).json({ error: 'Missing or invalid authorization header' });
|
||||
return;
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
|
||||
jwt.verify(
|
||||
token,
|
||||
getSigningKey,
|
||||
{
|
||||
issuer: OIDC_ISSUER,
|
||||
algorithms: ['RS256'],
|
||||
},
|
||||
(err, decoded) => {
|
||||
if (err) {
|
||||
console.error('Token verification failed:', err.message);
|
||||
res.status(401).json({ error: 'Invalid token', details: err.message });
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = decoded as jwt.JwtPayload;
|
||||
req.user = {
|
||||
sub: payload.sub!,
|
||||
preferred_username: payload.preferred_username || payload.sub!,
|
||||
email: payload.email,
|
||||
name: payload.name,
|
||||
};
|
||||
|
||||
next();
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue