apply security audit

This commit is contained in:
Matthias Hochmeister
2026-03-11 13:51:01 +01:00
parent 93a87a7ae9
commit 3c9b7d3446
19 changed files with 247 additions and 341 deletions

View File

@@ -1,9 +1,23 @@
import axios, { AxiosError } from 'axios';
import * as jose from 'jose';
import authentikConfig from '../config/authentik';
import logger from '../utils/logger';
import { TokenResponse, UserInfo } from '../types/auth.types';
class AuthentikService {
private jwks: ReturnType<typeof jose.createRemoteJWKSet> | null = null;
private getJwks(): ReturnType<typeof jose.createRemoteJWKSet> {
if (!this.jwks) {
// Derive JWKS URI from the issuer URL
// Issuer: https://auth.example.com/application/o/myapp/
// JWKS: https://auth.example.com/application/o/myapp/jwks/
const jwksUri = new URL('jwks/', authentikConfig.issuer.endsWith('/') ? authentikConfig.issuer : authentikConfig.issuer + '/');
this.jwks = jose.createRemoteJWKSet(jwksUri);
}
return this.jwks;
}
/**
* Exchange authorization code for access and ID tokens
*/
@@ -61,48 +75,26 @@ class AuthentikService {
}
/**
* Verify and decode ID token (basic validation)
* Note: For production, use a proper JWT verification library like jose or jsonwebtoken
* Verify and decode ID token using JWKS
*/
verifyIdToken(idToken: string): any {
async verifyIdToken(idToken: string): Promise<jose.JWTPayload> {
try {
// Split the token into parts
const parts = idToken.split('.');
if (parts.length !== 3) {
throw new Error('Invalid ID token format');
}
const { payload } = await jose.jwtVerify(idToken, this.getJwks(), {
issuer: authentikConfig.issuer,
});
// Decode the payload (Base64URL)
const payload = JSON.parse(
Buffer.from(parts[1], 'base64url').toString('utf-8')
);
// Basic validation
if (!payload.sub || !payload.email) {
throw new Error('Invalid ID token payload');
throw new Error('Invalid ID token payload: missing sub or email');
}
// Check expiration
if (payload.exp && payload.exp * 1000 < Date.now()) {
throw new Error('ID token has expired');
}
// Check issuer
if (payload.iss && !payload.iss.includes(authentikConfig.issuer)) {
logger.warn('ID token issuer mismatch', {
expected: authentikConfig.issuer,
received: payload.iss,
});
}
logger.info('ID token verified successfully', {
logger.info('ID token verified successfully via JWKS', {
sub: payload.sub,
email: payload.email,
});
return payload;
} catch (error) {
logger.error('Failed to verify ID token', { error });
logger.error('Failed to verify ID token via JWKS', { error });
throw new Error('Invalid ID token');
}
}