Aurelia auth login issue - javascript

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.

Related

Why endpoints not working from imported NESTJS module

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

Not getting the okta groups in angular oktasignin widget

I am trying to get the users group in the okta auth response.
In okta authorization server I set up the claims and scope correctly.
but in angular Okta-sign-in widget I am getting all the users properties except the users group . Any help will be greatly appreciated. Thanks in advance.
import { Component, OnInit } from "#angular/core";
import { Router, NavigationStart } from "#angular/router";
import { environment } from "#env";
import { OktaAuthService } from "#okta/okta-angular";
import * as OktaSignIn from "#okta/okta-signin-widget";
#Component({
selector: "app-login",
templateUrl: "./login.component.html",
styleUrls: ["./login.component.scss"]
})
export class LoginComponent implements OnInit {
signIn;
widget = new OktaSignIn({
baseUrl: environment.OKTA_ISSUER,
authParams: {
responseType: 'id_token',
responseMode: 'okta_post_message',
pkce: true,
scopes: ['groups']
},
logo:'assets/images/resmac_newlogo.png'
});
constructor(oktaAuth: OktaAuthService, public router: Router) {
this.signIn = oktaAuth;
}
ngOnInit() {
this.widget.renderEl(
{
el: "#okta-signin-container"
},
res => {
//alert(JSON.stringify(res));
if (res.status === "SUCCESS") {
this.signIn.loginRedirect("corporate/home", {
sessionToken: res.session.token
});
// this.widget.hide();
}
},
err => {
throw err;
}
);
}
}
User Details in angular

Nest can't resolve dependencies of the AuthService (AuthRepository, ?)

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

How to test Auth 0 implemented with passport strategy with Nestjs

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();
});
});

not redirecting to NotAuthorized Page - Angular 2

I have the following app.routes.ts
import {ModuleWithProviders} from '#angular/core';
import {Routes, RouterModule} from '#angular/router';
import { HomeComponent } from '../app/components/home/home.component';
import { LoginComponent } from '../app/components/login/login.component';
import { LoggedInGuard } from '../app/logged-in.guard';
import { CategoriesComponent} from '../app/components/categories/categories.component';
import { LogoutComponent } from '../app/components/logout/logout.component';
import { RegisterComponent} from '../app/components/register/register.component';
import { NotAuthorizedComponent} from '../app/components/not-authorized/not-authorized.component';
const appRoutes: Routes = [
{path: '', component: HomeComponent, pathMatch: 'full', canActivate: [LoggedInGuard]},
{path: 'login', component: LoginComponent},
{path: 'register', component: RegisterComponent},
{path: 'notAuthorized', component: NotAuthorizedComponent},
{path: 'categories', component: CategoriesComponent, canActivate: [LoggedInGuard]},
{path: 'logout', component: LogoutComponent, canActivate: [LoggedInGuard]},
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
and then I have a categories.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import {Observable} from 'rxjs/Observable';
import {Categories} from '../Categories';
import {Router} from '#angular/router';
#Injectable()
export class CategoriesService {
apiUrl: string;
categories: Categories[] = [];
constructor(private _http:Http, private router:Router) {
this.apiUrl = 'http://localhost:50424/api/';
}
getCategories() {
let headers = new Headers();
headers.append('Content-type', 'application/json');
let authToken = localStorage.getItem('auth_token');
headers.append('Authorization', `Bearer ${authToken}`);
return this._http.get(this.apiUrl+ 'Categories/Get', { headers: headers, withCredentials: true })
.map(this.extractObject)
.catch(this.handleError);
}
private extractObject(res: Response): Categories {
let categories = res.json();
return categories || { };
}
private handleError (error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
if (error.status === 401 || error.status === 403) {
console.log('We have an unathorized request');
//handle authorization errors
this.router.navigate(['notAuthorized']);
}
return Observable.throw(errMsg);
}
}
which is basically getting some categories from an API. All works well, however I want to limit this for only authorized users. So when throwing a server error 401 or 403, I want to redirect the user to a NonAuthorized page. My code is getting to the
console.log('We have an unathorized request');
correctly, however it is not doing the redirection, and staying on the same page. What I can do to redirect the user to another "NonAuthorized" page?
Thanks for your help and time!
As discussed in the comments, the problem is a scope issue, since this.router is not known in the scope of the passed this.handleError. Therefore the signature needs to be changed to private handleError(error: any, router: Router) and the corresponding call in the subscription will be .catch(error => this.handleError(error, this.router))

Categories

Resources