import jwt from 'jsonwebtoken'; import environment from '../config/environment'; import logger from '../utils/logger'; import { JwtPayload, RefreshTokenPayload } from '../types/auth.types'; class TokenService { /** * Generate JWT access token */ generateToken(payload: JwtPayload): string { try { const token = jwt.sign( { userId: payload.userId, email: payload.email, authentikSub: payload.authentikSub, groups: payload.groups ?? [], role: payload.role, }, environment.jwt.secret, { expiresIn: environment.jwt.expiresIn as any, } ); logger.info('Generated JWT token', { userId: payload.userId }); return token; } catch (error) { logger.error('Failed to generate JWT token', { error }); throw new Error('Token generation failed'); } } /** * Verify and decode JWT token */ verifyToken(token: string): JwtPayload { try { const decoded = jwt.verify( token, environment.jwt.secret ) as JwtPayload; logger.debug('JWT token verified', { userId: decoded.userId }); return decoded; } catch (error) { if (error instanceof jwt.TokenExpiredError) { logger.warn('JWT token expired'); throw new Error('Token expired'); } else if (error instanceof jwt.JsonWebTokenError) { logger.warn('Invalid JWT token', { error: error.message }); throw new Error('Invalid token'); } else { logger.error('Failed to verify JWT token', { error }); throw new Error('Token verification failed'); } } } /** * Generate refresh token (longer lived) */ generateRefreshToken(payload: RefreshTokenPayload): string { try { const token = jwt.sign( { userId: payload.userId, email: payload.email, }, environment.jwt.secret, { expiresIn: '7d', // Refresh tokens valid for 7 days } ); logger.info('Generated refresh token', { userId: payload.userId }); return token; } catch (error) { logger.error('Failed to generate refresh token', { error }); throw new Error('Refresh token generation failed'); } } /** * Verify refresh token */ verifyRefreshToken(token: string): RefreshTokenPayload { try { const decoded = jwt.verify( token, environment.jwt.secret ) as RefreshTokenPayload; logger.debug('Refresh token verified', { userId: decoded.userId }); return decoded; } catch (error) { if (error instanceof jwt.TokenExpiredError) { logger.warn('Refresh token expired'); throw new Error('Refresh token expired'); } else if (error instanceof jwt.JsonWebTokenError) { logger.warn('Invalid refresh token', { error: error.message }); throw new Error('Invalid refresh token'); } else { logger.error('Failed to verify refresh token', { error }); throw new Error('Refresh token verification failed'); } } } /** * Decode token without verification (for debugging) */ decodeToken(token: string): JwtPayload | null { try { const decoded = jwt.decode(token) as JwtPayload; return decoded; } catch (error) { logger.error('Failed to decode token', { error }); return null; } } } export default new TokenService();