apply security audit
This commit is contained in:
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class TokenService {
|
||||
email: payload.email,
|
||||
authentikSub: payload.authentikSub,
|
||||
groups: payload.groups ?? [],
|
||||
role: payload.role,
|
||||
},
|
||||
environment.jwt.secret,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user