I have been working on a feature where the goal is to allow a user to login via Auth0. I am using a passport such as passport-auth0 package to implement it. I was able to get working. However, I am not able to test it. I would like to know how I can test auth/login and auth/callback controllers methods.
Moreover, I would like to understand how to mock #UseGuards(AuthGuard('auth0')) and a middleware since I have used them.
Different ways I have tried I got the following error
[Nest] 23402 - 03/30/2020, 5:45:37 PM [ExceptionHandler] Cannot set property 'authParams' of undefined
**TypeError: Cannot set property 'authParams' of undefined**
at Auth0Strategy.Strategy.authenticate (/Users/directory/node_modules/passport-auth0/lib/index.js:82:28)
at attempt (/Users/directory/node_modules/passport/lib/middleware/authenticate.js:366:16)
at authenticate (/Users/directory/node_modules/passport/lib/middleware/authenticate.js:367:7)
at /Users/directory/node_modules/#nestjs/passport/dist/auth.guard.js:84:3
at new Promise (<anonymous>)
at /Users/directory/node_modules/#nestjs/passport/dist/auth.guard.js:76:83
at MixinAuthGuard.<anonymous> (/Users/directory/node_modules/#nestjs/passport/dist/auth.guard.js:48:36)
at Generator.next (<anonymous>)
at /Users/directory/node_modules/#nestjs/passport/dist/auth.guard.js:20:71
at new Promise (<anonymous>)
✨ Done in 38.11s.
// Auth.module.ts
import { Module, NestModule, MiddlewareConsumer } from '#nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { Auth0Strategy } from './auth.strategy';
import { AuthMiddleware } from './ middlewares/auth.middleware'
#Module({
controllers: [AuthController],
providers: [
AuthService,
Auth0Strategy
],
exports: [AuthService],
})
export class AuthModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(AuthMiddleware)
.forRoutes('auth/callback');
}
}
// auth.strategy.ts
import { Injectable, Query } from '#nestjs/common';
import { PassportStrategy } from '#nestjs/passport';
import { Strategy } from 'passport-auth0';
import { AuthService, Provider } from './auth.service';
import { config } from 'dotenv';
config();
#Injectable()
export class Auth0Strategy extends PassportStrategy(Strategy, 'auth0') {
constructor(
private readonly authService:AuthService
)
{
super(
{
domain: process.env.AUTH0_DOMAIN,
clientID: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
callbackURL: process.env.AUTH0_CALLBACK_URL,
redirectUri: process.env.AUTH0_CALLBACK_URL,
audience: process.env.AUTH0_AUDIENCE,
responseType: 'code',
scope: 'openid profile email',
},
)
}
async validate(request: any, accessToken: string, refreshToken: string, profile, done: Function): Promise<any> {
try {
const jwt: string = await this.authService.validateOAuthLogin(profile, Provider.Auth0);
const user =
{
jwt
}
return done(null, user);
}
catch (err) {
return done(err, false);
}
}
}
//auth.service.ts
import { Injectable, InternalServerErrorException, HttpException } from '#nestjs/common';
import { sign } from 'jsonwebtoken';
export enum Provider {
Auth0 = 'auth0'
}
#Injectable()
export class AuthService {
private readonly JWT_SECRET_KEY = process.env.JWT_SECRET_KEY
async validateOAuthLogin(profile: object, provider: Provider): Promise<string> {
try {
const isProfileExist = Object.entries(profile).length;
if (isProfileExist === 0) {
throw new HttpException('User profile is empty please login again', 400);
}
const payload = {
profile,
provider
}
const jwt: string = sign(payload, this.JWT_SECRET_KEY, { expiresIn: '1h' });
return jwt;
}
catch (err) {
throw new InternalServerErrorException('validateOAuthLogin', err.message);
}
}
}
import { Controller, Get, UseGuards, Res, Req } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
#Controller('auth')
export class AuthController {
#Get('login')
#UseGuards(AuthGuard('auth0'))
auth0Login() {}
#Get('callback')
#UseGuards(AuthGuard('auth0'))
auth0LoginCallback(#Req() req, #Res() res) {
const jwt: string = req.user.jwt;
if (jwt) {
res.redirect(`${process.env.AUTH0_SUCCESS_REDIRECTION_URL}/${jwt}`);
} else {
res.redirect(process.env.AUTH0_FAILURE_REDIRECTION_URL);
}
}
}
// auth.controller.spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { Auth0Strategy } from '../auth.strategy';
import { AuthModule } from '../auth.module';
import { auth0SuccessRequest, fekeToken } from './auth.mock';
describe('AuthService', () => {
let strategy: Auth0Strategy;
const { request, profile, accessToken, refreshToken } = auth0SuccessRequest;
let done: Function = jest.fn();
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [AuthModule],
providers: [Auth0Strategy]
}).compile();
strategy = module.get<Auth0Strategy>(Auth0Strategy);
});
afterAll(async () => {
jest.clearAllMocks();
});
it('should validate Auth 0 data', async () => {
await strategy.validate(request, accessToken, refreshToken, profile, done)
expect(done).toBeCalledTimes(1);
});
it('should not proceed without a profile function', async () => {
const failuredAuth = await strategy.validate(request, accessToken, refreshToken, {}, done);
expect(failuredAuth).toBeFalsy();
expect(failuredAuth).toBeUndefined();
});
});
// custom-guard.ts
import { ExecutionContext, Injectable, UnauthorizedException } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
#Injectable()
export class CustomGuard extends AuthGuard('auth0') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
handleRequest(err, user, info) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}
use your CustomGuard and test with it
#Controller('auth')
export class AuthController {
#UseGuards(CustomGuard) // use you guard
auth0LoginCallback(#Req() req, #Res() res) {
}
}
Hope it will help you and it is https://docs.nestjs.com/guards documentation
you are right #harut Barseghyan. with the custom guard you shared with me I was able to activate or override guard in the test environment when I needed it.
// auth.controller.ts
import { Controller, Get, UseGuards, Res, Req } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { AuthCustomGuard } from '../auth/guards/auth.guard';
#Controller('auth')
export class AuthController {
#Get('login')
// #UseGuards(AuthGuard('auth0')). // I no longer use this guard
#UseGuards(AuthCustomGuard). // I instead use Auth0 custom guards
auth0Login() {}
#Get('callback')
// #UseGuards(AuthGuard('auth0'))
#UseGuards(AuthCustomGuard)
auth0LoginCallback(#Req() req, #Res() res) {
const jwt: string = req.user.jwt;
if (jwt) {
res.redirect(`${process.env.AUTH0_SUCCESS_REDIRECTION_URL}/${jwt}`);
} else {
res.redirect(process.env.AUTH0_FAILURE_REDIRECTION_URL);
}
}
}
Since I want to authorize the Auth0 routes, I still need Auth 0 guards. The snippet code-shared by #harut Barseghyan.
// auth.guard.ts
import { ExecutionContext, Injectable, UnauthorizedException } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
#Injectable()
export class AuthCustomGuard extends AuthGuard('auth0') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}
The fact I have a custom guard, I have the power to activate it vice versa in a testing environment
// auth.controller.spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { AuthController } from '../auth.controller';
import { INestApplication } from '#nestjs/common';
import { AuthModule } from '../auth.module';
import * as request from 'supertest';
import { AuthCustomGuard } from '../guards/auth.guard';
describe('Auth Controller', () => {
let app: INestApplication;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [AuthModule],
controllers: [AuthController],
})
.overrideGuard(AuthCustomGuard) // can you see that I override it
.useValue({ canActivate: () => true }) // true helped me to skip
.compile();
app = module.createNestApplication();
app.init()
});
it('should be visit auth login route', async () => {
return request(app.getHttpServer())
.get('/auth/login')
.expect(302)
});
it('should not redirect user to login page if auth 0 throws an error such as an invalid error request', async () => {
return request(app.getHttpServer())
.get('/auth/callback?error=invalid_request')
.expect(302)
});
afterAll(async () => {
jest.clearAllMocks();
await app.close();
});
});
Related
tell me please why appController working and itemsController no (from imported module)
I learn nestjs and i did it according to documentation. This controller working its uncomment endpoint.
import {Controller, Get} from '#nestjs/common';
import { AppService } from './app.service';
#Controller()
export class AppController {
constructor() {}
// #Get()
// getHome():string {
// return 'Hello world!';
// }
}
itemsController.ts - working if change appController.ts on this
import {Controller, Get, HttpException, HttpStatus, Param, Post, Res} from "#nestjs/common";
import {Response} from "express";
import {ItemsService} from "./items.service";
import {ItemDto} from "./dto/item.dto";
#Controller()
export class ItemsController {
constructor(private readonly itemsService: ItemsService) {}
#Get()
getAll(#Res({passthrough: true}) res: Response):string | object {
const items = this.itemsService.getAll();
if(!!items.length) {
res.status(HttpStatus.OK);
return new HttpException({
items: items
}, HttpStatus.OK).getResponse();
}
res.status(HttpStatus.INTERNAL_SERVER_ERROR);
return new HttpException({
items: 'Items length: ' + items.length,
status: HttpStatus.INTERNAL_SERVER_ERROR
}, HttpStatus.INTERNAL_SERVER_ERROR).getResponse();
}
#Post()
create(#Param() params):ItemDto {
return this.itemsService.create(params);
}
}
Test jest working:
import { Test } from '#nestjs/testing';
import { ItemsController } from './items/items.controller';
import { ItemsService } from './items/items.service';
import * as request from 'supertest';
import { INestApplication } from "#nestjs/common";
describe('ItemsModule', () => {
let itemsController: ItemsController;
let itemsService: ItemsService;
let app: INestApplication;
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
controllers: [ItemsController],
providers: [ItemsService],
}).compile();
itemsService = moduleRef.get<ItemsService>(ItemsService);
itemsController = moduleRef.get<ItemsController>(ItemsController);
app = moduleRef.createNestApplication();
await app.init();
});
describe('End-points', () => {
it('/GET Status 200', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect({
"items": [
{
id: '0',
title: '',
message: ''
}
]
});
});
it('/GET Status 500', () => {
return request(app.getHttpServer())
.get('/')
.expect(500)
.expect({
items: 'Items length: 0',
status: 500
});
});
});
});
I pushed all on github, you can see all code
After looking at your source code, you're missing the # for #Module() in your ItemsModule
I have a problem with overriding provider in nest.js application for testing.
My stats.controller.spec.ts:
import { StatsService } from './services/stats.service';
import { StatsController } from './stats.controller';
describe('StatsController', () => {
let controller: StatsController;
const mockStatsService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [StatsController],
providers: [StatsService],
})
.overrideProvider(StatsService)
.useValue(mockStatsService)
.compile();
controller = module.get<StatsController>(StatsController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
My stats.controller.ts:
import { Controller, Get } from '#nestjs/common';
import { StatsService } from './services/stats.service';
#Controller('stats')
export class StatsController {
constructor(private statsService: StatsService) {}
#Get('weekly')
getWeeklyStats() {
return this.statsService.getWeeklyStats();
}
#Get('monthly')
getMonthlyStats() {
return this.statsService.getMonthlyStats();
}
}
And my stats.service.ts:
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { Trip } from 'src/trips/trip.entity';
import { from, map } from 'rxjs';
import { DatesService } from 'src/shared/services/dates.service';
#Injectable()
export class StatsService {
constructor(
#InjectRepository(Trip) private tripRepository: Repository<Trip>,
private datesServices: DatesService,
) {}
//some code here
}
And after running test I get following errors:
Cannot find module 'src/trips/trip.entity' from 'stats/services/stats.service.ts'
I would really appreciate some help.
The error is unrelated to if you're using a custom provider or overrideProvider. Jest by default doesn't understand absolute imports by default, and you need to use the moduleNameMapper option to tell Jest how to resolve src/ imports. Usually something like
{
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/$1"
}
}
Assuming rootDir has been set to src
You can override the provider by using the below code in nest js:
import { StatsService } from './services/stats.service';
import { StatsController } from './stats.controller';
describe('StatsController', () => {
let controller: StatsController;
const mockStatsService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [StatsController],
providers: [{
provide: StatsService,
useValue: mockStatsService
}],
})
.compile();
controller = module.get<StatsController>(StatsController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
I'm trying to implement JWT into my project. I've followed the steps as outline in https://www.npmjs.com/package/#nestjs/jwt#usage
auth.module.ts
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { JwtModule } from '#nestjs/jwt';
import { AuthRepository } from './auth.repository';
#Module({
imports: [
JwtModule.register({ secret: process.env.JWT_SECRET || 'ABCDE12345' }),
TypeOrmModule.forFeature([AuthRepository]),
],
exports: [TypeOrmModule, AuthService],
providers: [AuthService],
controllers: [AuthController],
})
export class AuthModule {}
auth.service.ts
import { Injectable, NotFoundException, UnauthorizedException } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { AuthEntity } from './auth.entity';
import { LoginDTO } from './dto/login.dto';
import * as bcrypt from 'bcrypt';
import { JwtService } from '#nestjs/jwt';
import crypto from 'crypto';
import { AuthRepository } from './auth.repository';
// export interface FindWhereData {
// readonly email: string;
// readonly password: string;
// }
export interface LoginResponse {
readonly token: string;
readonly refresh_token: string;
}
#Injectable()
export class AuthService {
constructor(
#InjectRepository(AuthRepository)
private authRepository: AuthRepository,
private jwtService: JwtService
) {}
/**
* Login user service
*
* #param doc
*/
public async login(doc: LoginDTO): Promise<LoginResponse> {
// verify user email
const user = await this.authRepository.findOne({ email: doc.email });
if (!user) {
throw new NotFoundException('Could not find user');
}
// verify password
const passwordsMatch = await this.passwordsAreEqual(doc.password, user.password);
if (!passwordsMatch) {
throw new UnauthorizedException('Incorrect login credentials');
}
// generate JWT
const token = await this.jwtService.signAsync({ id: user.id });
// create the refresh token
const refreshToken = crypto.randomBytes(256).toString('hex');
// store the refresh token
return {
token: token,
refresh_token: refreshToken,
};
}
/**
* Generate a hashed password
*
* #param password
*/
public async hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt();
return await bcrypt.hash(password, salt);
}
/**
* Compare password against an encrypted string
*
* #param password
* #param encryptedPassword
*/
public async passwordsAreEqual(password: string, encryptedPassword: string): Promise<boolean> {
return await bcrypt.compare(password, encryptedPassword);
}
/**
* Find a record by column attribute and value
*
* #param queryObject
*
*/
public async findWhere(queryObject): Promise<AuthEntity> {
const authEntity = await this.authRepository.findOne({ where: queryObject });
if (!authEntity) {
return null;
}
return authEntity;
}
public async findOne(id: string): Promise<AuthEntity> {
return this.authRepository.findOne(id);
}
}
auth.repository.ts
import { EntityRepository, Repository } from "typeorm";
import { AuthEntity } from "./auth.entity";
#EntityRepository(AuthEntity)
export class AuthRepository extends Repository<AuthEntity> {}
app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RouterModule } from 'nest-router';
import { routes } from './routes';
import { ConfigModule } from '#nestjs/config';
import configuration from './config/configuration';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Connection } from 'typeorm';
import { AuthModule } from './auth/auth.module';
#Module({
imports: [
RouterModule.forRoutes(routes),
ConfigModule.forRoot({
load: [configuration],
}),
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.POSTGRES_HOST || 'localhost',
port: 5432,
username: process.env.POSTGRES_USERNAME || 'postgres',
password: process.env.POSTGRES_PASSWORD || 'password',
database: process.env.POSTGRES_DATABASE || 'service-auth',
autoLoadEntities: true,
synchronize: true,
}),
AuthModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
constructor(private readonly connection: Connection) {
console.log('connection status: ' + connection.isConnected);
}
}
auth.service.spec.ts
import { JwtModule, JwtService } from '#nestjs/jwt';
import { Test, TestingModule } from '#nestjs/testing';
import { AuthEntity } from './auth.entity';
import { AuthRepository } from './auth.repository';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let authService: AuthService;
let authRepository: AuthRepository;
const mockAuthRepository = () => ({
login: jest.fn(),
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AuthService,
// JwtModule,
{
provide: getRepositoryToken(AuthRepository),
useFactory: mockAuthRepository,
},
{
provide: JwtService,
useValue: {
signAsync: jest.fn(() => 'token'),
}
}
]
}).compile();
authService = await module.get<AuthService>(AuthService);
authRepository = await module.get<AuthRepository>(AuthRepository);
});
/**
* Test that the service is defined
*/
it('should be defined', () => {
expect(authService).toBeDefined();
});
});
When I run npm run test I get the following error message:
FAIL src/auth/auth.service.spec.ts
● AuthService › should be defined
Nest can't resolve dependencies of the AuthService (AuthRepository, ?). Please make sure that the argument JwtService at index [1] is available in the RootTestModule context.
Potential solutions:
- If JwtService is a provider, is it part of the current RootTestModule?
- If JwtService is exported from a separate #Module, is that module imported within RootTestModule?
#Module({
imports: [ /* the Module containing JwtService */ ]
})
I know the error is probably pretty clear to seasoned Node/Nest developer but I cannot figure out what the RootTestModule is and how to get JwtModule imported.
I believe I have followed the setup correctly but adding this JwtModule to the AuthService is causing the service to be undefined in my unit tests.
Repo
https://github.com/marcuschristiansen/nestjs-auth
You should be adding a custom provider for the JwtService so that you can mock it. A custom provider could look like
{
provide: JwtService,
useValue: {
signAsync: jest.fn(() => 'token'),
}
}
To tell Nest to inject an object that has a signAsync() method that when called returns the string 'token' so that it will always be the same in your tests.
This object goes in the providers array, just like the AuthRepository mock
The documentation is kinda thin here so I ran into a problem. I try to use Guards to secure Controller or it's Actions, so I gonna ask for the role of authenticated requests (by JWT). In my auth.guard.ts I ask for "request.user" but it's empty, so I can't check the users role. I don't know how to define "request.user". Here is my auth module and it's imports.
auth.controller.ts
import { Controller, Get, UseGuards } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
import { AuthService } from './auth.service';
import { RolesGuard } from './auth.guard';
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
#Get('token')
async createToken(): Promise<any> {
return await this.authService.signIn();
}
#Get('data')
#UseGuards(RolesGuard)
findAll() {
return { message: 'authed!' };
}
}
roles.guard.ts
Here user.request is empty, because I never define it. The documentation doesn't show how or where.
import { Injectable, CanActivate, ExecutionContext } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user; // it's undefined
const hasRole = () =>
user.roles.some(role => !!roles.find(item => item === role));
return user && user.roles && hasRole();
}
}
auth.module.ts
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';
import { UserModule } from './../user/user.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { PassportModule } from '#nestjs/passport';
import { JwtModule } from '#nestjs/jwt';
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: 'secretKey',
signOptions: {
expiresIn: 3600,
},
}),
UserModule,
],
providers: [AuthService, HttpStrategy],
controllers: [AuthController],
})
export class AuthModule {}
auth.service.ts
import { Injectable } from '#nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '#nestjs/jwt';
#Injectable()
export class AuthService {
constructor(
private readonly userService: UserService,
private readonly jwtService: JwtService,
) {}
async signIn(): Promise<object> {
// In the real-world app you shouldn't expose this method publicly
// instead, return a token once you verify user credentials
const user: any = { email: 'user#email.com' };
const token: string = this.jwtService.sign(user);
return { token };
}
async validateUser(payload: any): Promise<any> {
// Validate if token passed along with HTTP request
// is associated with any registered account in the database
return await this.userService.findOneByEmail(payload.email);
}
}
jwt.strategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: any) {
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Documentation: https://docs.nestjs.com/guards
Thanks for any help.
Additionally to your RolesGuard you need to use an AuthGuard.
Standard
You can use the standard AuthGuard implementation which attaches the user object to the request. It throws a 401 error, when the user is unauthenticated.
#UseGuards(AuthGuard('jwt'))
Extension
If you need to write your own guard because you need different behavior, extend the original AuthGuard and override the methods you need to change (handleRequest in the example):
#Injectable()
export class MyAuthGuard extends AuthGuard('jwt') {
handleRequest(err, user, info: Error) {
// don't throw 401 error when unauthenticated
return user;
}
}
Why do this?
If you look at the source code of the AuthGuard you can see that it attaches the user to the request as a callback to the passport method. If you don't want to use/extend the AuthGuard, you will have to implement/copy the relevant parts.
const user = await passportFn(
type || this.options.defaultStrategy,
options,
// This is the callback passed to passport. handleRequest returns the user.
(err, info, user) => this.handleRequest(err, info, user)
);
// Then the user object is attached to the request
// under the default property 'user' which you can change by configuration.
request[options.property || defaultOptions.property] = user;
You can attach multiple guards together (#UseGuards(AuthGuard('jwt'), RolesGuard)) to pass the context between them. Then you will have access 'req.user' object inside 'RolesGuard'.
After I got the selected answer working (thank you), I found this option as well that you can add to the constructor that essentially does the same thing.
http://www.passportjs.org/docs/authorize/
Association in Verify Callback
One downside to the approach described above is that it requires two
instances of the same strategy and supporting routes.
To avoid this, set the strategy's passReqToCallback option to true.
With this option enabled, req will be passed as the first argument to
the verify callback.
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: AuthService) {
super({
passReqToCallback: true
})
}
// rest of the strategy (validate)
}
Does it work if you use req.authInfo?
As long as you don't provide a custom callback to passport.authenticate method, the user data should be attached to the request object like this.
req.authInfo should be the object you returned in your validate method
I have the following problem with aurelia-auth, here is common login snippet that I use:
login() {
return this.authService.login(this.email, this.password)
.then(response => {
console.log("Login response" + JSON.stringify(response));
})
.catch(err => {
this.loginError = err.response;
});
};
When I'm trying to login, I see desired console output, but also there is a message "login route : /login" from authorizeStep.js:38
which states that I'm actually not authenticated
My auth-config:
var config = {
baseUrl: '',
loginUrl:'http://localhost:8888/rest-auth/login/',
signupUrl: 'http://localhost:8888/rest-auth/registration/',
loginRedirect: '#/contests',
logoutRedirect: '/',
tokenName: 'key',
authHeader: 'Authorization',
authToken: 'Token',
storage: 'sessionstorage'
}
export default config;
app.js:
import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';
import AppRouterConfig from 'router-config';
import HttpClientConfig from 'aurelia-auth/app.httpClient.config';
import {FetchConfig} from 'aurelia-auth';
#inject(Router, HttpClientConfig, FetchConfig, AppRouterConfig)
export class App {
constructor(router, httpClientConfig, fetchConfig, appRouterConfig {
this.router = router;
this.httpClientConfig = httpClientConfig;
this.appRouterConfig = appRouterConfig;
this.fetchConfig = fetchConfig;
}
activate() {
this.httpClientConfig.configure();
this.appRouterConfig.configure();
this.fetchConfig.configure();
}
}
Any help would be appreciated.