my HelloModule:
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { HelloService } from './hello.service';
import { HelloController } from './hello.controller';
import { AuthGuard } from '../guards/auth.guard';
@Module({
controllers: [HelloController],
providers: [
HelloService,
{
provide: APP_GUARD,
useExisting: AuthGuard,
},
AuthGuard,
],
})
export class HelloModule {}
my e2e test:
import { INestApplication } from '@nestjs/common';
import { TestingModule, Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AuthGuard } from '../src/guards/auth.guard';
import { AuthGuardMock } from './authguard.mock';
import { HelloModule } from '../src/hello/hello.module';
describe('app e2e via HelloController', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [HelloModule],
})
.overrideProvider(AuthGuard)
.useClass(AuthGuardMock)
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('GET request to /hello returns Hello!', () => {
try {
return request(app.getHttpServer())
.get('/hello')
.set('authorization', 'Bearer abc123')
.expect(200)
.expect('Hello!');
} catch (err) {
console.log(err);
throw err;
}
});
afterAll(async () => {
await app.close();
});
});
my AuthGuard class:
import {
Injectable,
CanActivate,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { JwtRsaVerifier } from 'aws-jwt-verify';
import { validateCognitoJwtFields } from 'aws-jwt-verify/cognito-verifier';
import { getJWTFromRequest } from '../utils/utils';
@Injectable()
export class AuthGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
console.log('canActivate from auth guard');
const request = context.switchToHttp().getRequest();
const jwt = getJWTFromRequest(request);
return await this.validateJwtFields(jwt);
}
async validateJwtFields(jwt: string): Promise<boolean> {
// if (process.env.NODE_ENV === 'test') {
// return Promise.resolve(true);
// }
console.log('validateJwtFields:');
const verifier = JwtRsaVerifier.create([
{
issuer: `https://cognito-idp.us-east-1.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`,
audience: null, // audience (~clientId) is checked instead, by the Cognito specific checks below
customJwtCheck: ({ payload }) =>
validateCognitoJwtFields(payload, {
tokenUse: 'access', // set to "id" or "access" (or null if both are fine)
clientId: `${process.env.COGNITO_CLIENT_ID}`, // provide the client id, or an array of client ids (or null if you do not want to check client id)
}),
},
//TODO: change below when adding Okta or other IDP
{
issuer: 'https://example.com/my/other/idp',
audience: 'myaudience',
},
]);
try {
await verifier.verify(jwt);
return true;
} catch (err) {
console.log(err);
throw new UnauthorizedException('Invalid authentication token');
}
}
}
my authGuardMock:
import { CanActivate, ExecutionContext } from '@nestjs/common';
import { getJWTFromRequest } from '../src/utils/utils';
export class AuthGuardMock implements CanActivate {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
canActivate = jest.fn(async (context: ExecutionContext) => {
console.log('AuthGuardMock - canActivate');
const request = context.switchToHttp().getRequest();
const jwt = getJWTFromRequest(request);
console.log('AuthGuardMock - after getJWTFromRequest');
return true;
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
validateJwtFields = jest.fn((jwt: string) => Promise.resolve(true));
}