All files / libs/kernel/auth/core/src/lib/strategies jwt.strategy.ts

100% Statements 66/66
55.55% Branches 5/9
100% Functions 2/2
100% Lines 66/66

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 671x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 1x 1x 23x 23x 23x 23x 23x 23x 23x 23x 15x 15x 23x 3x 3x 3x 23x 23x 12x 12x 12x 12x 12x 23x 23x 23x 1x  
import { PassportStrategy } from '@nestjs/passport';
import { passportJwtSecret } from 'jwks-rsa';
import { ExtractJwt, Strategy } from 'passport-jwt';
 
import { type AuthenticatedContext } from '@amalia/kernel/auth/types';
 
import { InjectAuthConfig, type AuthConfig } from '../config/auth.config';
import { AuthenticatedContextFactory } from '../factories';
import { ImpersonateUserUseCase, type JwtPayload } from '../use-cases';
 
declare module 'express' {
  interface Request {
    user?: AuthenticatedContext;
  }
}
 
/**
 * Jwt strategy is used to validate provided jwt tokens against Auth0.
 */
export class JwtStrategy extends PassportStrategy(Strategy) {
  public constructor(
    @InjectAuthConfig() authConfig: Pick<AuthConfig, 'audience' | 'baseUrl' | 'issuerUrl'>,
    private readonly authenticatedContextFactory: AuthenticatedContextFactory,
    private readonly impersonateUserUseCase: ImpersonateUserUseCase,
  ) {
    super({
      secretOrKeyProvider: passportJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `${authConfig.baseUrl}/.well-known/jwks.json`,
      }),
 
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      audience: authConfig.audience,
      issuer: authConfig.issuerUrl,
      algorithms: ['RS256'],
    });
  }
 
  public async validate(payload: JwtPayload): Promise<AuthenticatedContext> {
    const {
      loggedUser,
      impersonator,
      canImpersonateAsSuperAdmin,
      companyIdsThatUserCanImpersonate,
      impersonatorEmail,
      amaliaRoles,
    } = await this.impersonateUserUseCase.execute({ payload });
 
    return this.authenticatedContextFactory.makeAuthenticatedContext(loggedUser, {
      ...(impersonator && {
        impersonation: {
          impersonator,
        },
      }),
      ...(canImpersonateAsSuperAdmin && {
        meta: {
          amaliaImpersonatorEmail: impersonatorEmail,
          amaliaRoles,
          companyIdsThatUserCanImpersonate,
        },
      }),
    });
  }
}