I need to authenticate in NestJS without middleware - authentication

I have url, this url needs authentication with username and password. On PHP I made it with curl_setopt(CURLOPT_USERPWD, $username . ':' . $password), I can't find any solution how to set password and username on same link on NestJS.
import { Injectable, Scope, HttpService } from '#nestjs/common';
import { ImporterService } from '../importer.service';
import { map } from 'rxjs/operators';
#Injectable({ scope: Scope.REQUEST })
export class Supplier extends ImporterService {
supplierName = 'supplierName';
fileDownload: boolean = false;
username = 'username;
password = 'password';
async parse() {
await this.checkSupplierExist(this.supplierName);
return this.httpService
.get(
'https://www.link.com/restful/export/api/products.xml?acceptedlocales=en_US&addtags=true',
)
.pipe( map(response => console.log(response)));
}
}
this response sends 401, cause it needs authentication. I cannot figure out how to set username or password. Can anyone help?

From me I have a Config service which handles http calls, looks like this:
#Injectable()
export class ConfigService {
private readonly envConfig: { [key: string]: string };
private servers: Object = {};
constructor(private httpService: HttpService) {
this.envConfig = {
PORT: process.env.PORT,
MONGODB_URI: process.env.MONGODB_URI,
MONGODB_SESSION_URI: process.env.MONGODB_SESSION_URI,
SESSION_SECRET: process.env.SESSION_SECRET
};
const externals = JSON.parse(process.env.EXTERNALS);
for (const lang in externals) {
this.servers[lang] = externals[lang];
}
}
get(key: string): string {
return this.envConfig[key];
}
getServer(lang: string, method: string, url: string, headers: Object, params?: Object, data?: Object) {
const config = { baseURL: this.servers[lang], url, headers, method, data, params };
return this.httpService.request(config).toPromise();
}
}
As you can see in the getServer method, you can add headers as well.
I hope this is what you're looking for

Related

Cannot verify JWT token

I am using NestJS and its JWT package based on jsonwebtoken. The generated token is always being invalid, and I am getting a 500 - Internal Server Error.
What might be the problem?
My login function in the AuthService:
async login(email: string, password: string, isAdmin?: boolean, isVIP?: boolean){
let user = await this.usersService.findByEmail(email);
if(!user){
throw new NotFoundException('No user with this email could be found.');
}
const isEqual = await bcrypt.compare(password, user.password);
if(!isEqual){
throw new BadRequestException('Email and password do not match');
}
const secret = 'secretkey';
const payload = {email: user.email, userId: user._id.toString()}
const token = this.jwtService.sign(payload, {secret, expiresIn: '1h'});
return [email, isAdmin, isVIP, token];
}
My verification logic in the AuthGuard
`
import { BadRequestException, CanActivate, ExecutionContext, Inject } from "#nestjs/common";
import { JwtService } from "#nestjs/jwt/dist";
import { JwtConfigService } from "src/config/jwtconfig.service";
export class JwtAuthGuard implements CanActivate {
constructor(#Inject(JwtService) private jwtService: JwtService){}
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
const authHeader = request.get('Authorization');
if (!authHeader) {
throw new BadRequestException('Not authorized');
}
const token = authHeader.split(' ')[1];
let decodedToken;
try {
decodedToken = this.jwtService.verify(token, {secret: 'secretkey'});
} catch (err) {
throw new Error('Cannot verify token.')
}
if(!decodedToken){
throw new BadRequestException('Not authenticated')
}
request.userId = decodedToken.userId;
console.log({decodedToken, token});
return request.userId;
};
}
My current JWT setup in the UsersModule imports (I have no AuthModule); I tried all the other configurations in the official docs, too.
JwtModule.register({
secret: 'secretkey',
publicKey: '...',
privateKey: '...',
secretOrKeyProvider: (
requestType: JwtSecretRequestType,
tokenOrPayload: string | Object | Buffer,
verifyOrSignOrOptions?: jwt.VerifyOptions | jwt.SignOptions
) => {
switch (requestType) {
case JwtSecretRequestType.SIGN:
return 'privateKey';
case JwtSecretRequestType.VERIFY:
return 'publicKey';
default:
return 'secretkey';
}
},
})
`
My jwtconfig.ts, which I don't think is being used:
`
import { JwtOptionsFactory, JwtModuleOptions } from '#nestjs/jwt'
export class JwtConfigService implements JwtOptionsFactory {
createJwtOptions(): JwtModuleOptions {
return {
secret: 'secretkey'
};
}
}
`
I solved the problem by switching my guard to a middleware.

No default value in username while trying to create a user in nestjs

I am new to nestjs and also to asking questions on stack overflow.
And although i am able to perfectly perform get requests i have trouble sending a post request using form data.
And although i am able to successfully send a post request using form-urlencoded and raw json i am having trouble dealing with form data.
While trying to send a post request to my db I seem to get an error which says: ER_NO_DEFAULT_FOR_FIELD: Field 'username' doesn't have a default value
even though I provide a value for it in postman.
Below is the code for my repo:
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';
import { CreateUserDTO } from './dto/create-user.dto';
#EntityRepository(User)
export class UserRepository extends Repository<User> {
getUser() {
const query = this.createQueryBuilder('user');
return query.getMany();
}
createUser(createUserDTO: CreateUserDTO) {
const {username, email } = createUserDTO;
// tslint:disable-next-line:no-console
console.log('Repo', username);
// tslint:disable-next-line:new-parens
const newuser = new User(); //edited after Natan's comment
newuser.username = username;
newuser.email = email;
return newuser.save();
}
}
This is my entity code:
#Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
username: string;
#Column()
email: string;
}
and my post request in the controller:
#Post()
createUser(
#Body() createUserDTO: CreateUserDTO,
) {
// tslint:disable-next-line:no-console
console.log('creating new user', createUserDTO);
return this.userService.createUser(createUserDTO);
}
And here is a picture of the post request in postman:
You must use () to instantiate a class in TS, like:
createUser(createUserDTO: CreateUserDTO) {
const {username, email } = createUserDTO;
// tslint:disable-next-line:no-console
console.log('Repo', username);
// tslint:disable-next-line:new-parens
const newuser = new User(); // <- HERE IS new User()
newuser.username = username;
newuser.email = email;
return newuser.save();
}

"Response is not defined" when using ngrx effects with HttpClient

I'm currently rewriting old request service to use HttpClient instead of Http. My app makes use of ngrx store and after I rewrote request service, it stopped working.
here's my request service:
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import { ToastController } from 'ionic-angular';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Config } from '../app/app.config';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Version } from '#angular/compiler';
export enum HttpStatus {
UNAUTHORIZED,
WRONGVERSION,
UNVERIFIED,
NONETWORK,
}
export interface HttpNotifierData {
status: HttpStatus
}
#Injectable()
export class HttpClientService {
private httpNotifier: ReplaySubject<HttpNotifierData>;
constructor(
public toastCtrl: ToastController,
private _http: HttpClient,
) {
this.httpNotifier = new ReplaySubject();
}
createHeaders(contentType?: string) {
var headers = new HttpHeaders();
let token = localStorage.getItem('auth_token');
let expires = localStorage.getItem('auth_expires');
let appVersion = Config.version+'';
if(token)
headers = headers.set( 'Authorization', 'Bearer ' + token);
if(expires)
headers = headers.set( 'TokenExpiration', expires);
if(appVersion)
headers = headers.set( 'App-Version', appVersion);
if(contentType === 'form')
headers = headers.set('Content-Type','application/x-www-form-urlencoded');
return headers;
}
createAppVersionHeader(headers: Headers) {
let appVersion = Config.version+'';
headers.append('App-Version', appVersion);
}
getHttpNotifier(): ReplaySubject<HttpNotifierData> {
return this.httpNotifier;
}
request(verb: string, url: string, data?: any, contentType?: string) {
let headers = this.createHeaders(contentType);
return this._http.request(verb, url, {
body: data,
headers: headers
}).catch(err => {
if (err.status == 0) {
this.httpNotifier.next({status: HttpStatus.NONETWORK});
err._body = 'Kunne ikke kontakte baksystem';
} else if (err.status == 401) {
this.httpNotifier.next({status: HttpStatus.UNAUTHORIZED});
} else if (err.status == 403) {
this.httpNotifier.next({status: HttpStatus.UNVERIFIED});
} else if (err.status == 412) {
this.httpNotifier.next({status: HttpStatus.WRONGVERSION});
} else {
// TODO: Convert API error to user friendly error
this.toastCtrl.create({
message: err._body,
duration: 3000,
showCloseButton: true,
closeButtonText: "Lukk",
cssClass: 'error',
}).present();
}
throw err;
});
}
get(url) {
let cache = '?cache=' + Math.ceil(Math.random() * 100000);
return this.request('GET', url + cache);
}
post(url, data, contentType = 'json') {
return this.request('POST', url, data, contentType);
}
put(url, data) {
return this.request('PUT', url, data);
}
delete(url) {
return this.request('DELETE', url);
}
}
my user auth service:
import { Injectable } from '#angular/core';
import { Config } from '../app/app.config';
import { HttpClientService } from "./http.service";
#Injectable()
export class UserService {
constructor(
private _http: HttpClientService
) { }
login(username: string, password: string) {
var data = "grant_type=password&username=" + username + "&password=" + password + "&deviceId=test";
return this._http.post(Config.apiUrl + 'Token', data, 'form');
}
getPin(phone: string) {
return this._http.post(Config.apiUrl + 'api/account/forgotPassword', {phoneNumber: phone})
}
}
my ngrx effect for authenticating user:
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/observable/of';
import { Injectable } from '#angular/core';
import { Effect, Actions } from '#ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { UserService } from '../services/user.service';
import * as UserActions from '../actions/user.actions';
#Injectable()
export class UserEffects {
constructor(
private actions: Actions,
private userService: UserService
) {}
#Effect()
login:Observable<any> = this.actions
.ofType(UserActions.LOGIN)
.map((action: UserActions.Login) => action.payload)
.switchMap(payload => {
return this.userService.login(payload.username, payload.password)
.map((response:any) => new UserActions.LoginSuccess(JSON.parse(response._body)))
.catch((error) => Observable.of(new UserActions.LoginFailed(error._body)))
});
#Effect()
getPin:Observable<any> = this.actions
.ofType(UserActions.GET_PIN)
.map((action: UserActions.GetPin) => action.payload)
.switchMap(payload => {
return this.userService.getPin(payload)
.map((response: any) => new UserActions.GetPinSuccess())
.catch((error) => Observable.of(new UserActions.GetPinFailed(error._body)))
});
}
when debugging, I have this error appearing in effect module:
however, in network section I can see that request is completed successfully:
what can be wrong with my service?
ok, so I figured out the solution.
effects for login should have pipe and no json parsing:
#Effect()
login:Observable<any> = this.actions
.ofType(UserActions.LOGIN)
.map((action: UserActions.Login) => action.payload)
.switchMap(payload => {
return this.userService.login(payload.username, payload.password).pipe()
.map((response:any) => new UserActions.LoginSuccess(response))
.catch((error) => Observable.of(new UserActions.LoginFailed(error._body)))
});

How write header with nestjs

how I can write headers using way nest.js?
I'm currently using this:
import { Controller, Body, Get, Post, HttpCode, HttpStatus, Req, Res } from '#nestjs/common';
import { Request, Response } from 'express';
import { AuthService } from './auth.service';
import { Usuario } from '../usuario/usuario.entity';
import { JsonWebTokenError } from 'jsonwebtoken';
import { request } from 'http';
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) { }
#Post('login')
#HttpCode(HttpStatus.OK)
async login(#Body('username') username: string, #Body('password') password: string, #Res() response: Response) {
this.authService
.validateUser(username, password)
.then((token) => {
response.setHeader('Authorization', 'Bearer ' + token);
let respuesta: any = {};
respuesta.success = true;
respuesta.token = token;
return response.send(respuesta);
});
}
}
I do not want to use response.setHeader('Authorization', 'Bearer ' + token); and return response.send(respuesta);
Thanks for your answers!
NestJS is build on top of express, so do it like in express:
async login(#Body('username') username: string, #Body('password') password: string, #Res() res: Response) {
const token = await this.authService.validateUser(username, password);
res.set('Authorization', 'Bearer ' + token);
res.send({
success: true,
token,
})
});
In latest versions you could use the #Header decorator within NestJS Core.
import { Controller, Get, Req, Header, Res } from '#nestjs/common';
import { Request, Response } from 'express';
#Controller('cookies')
export class CookiesController {
#Get('set')
// #Header('Set-Cookie', 'cookieName = 12345') // "Usin header decorator"
setCookie(#Res() response: Response): Response {
/*
* If using express approach, pass #Res as param decorator
*/
response.cookie('rememberme', '1') // Using express res object.
return response.send('Cookie has been set! :)')
}
#Get()
checkCookie(#Req() request: Request ): string {
console.log(Object.keys(request.cookies))
if(Object.keys(request.cookies).length > 0){
console.log('cookies =>', request.cookies)
return 'Cookies are set :)'
} else {
return 'Uh, oh! Cookie hasn\'t been set :\'('
}
}
}

Angular2 - canActivate not getting value from AuthService

Trying to make Login feature using angular-2 where I have used one login component, authservice, logingard with canActive.
While following example from angular2 document, I don't get value of loggedin in guard file and it asks every time for login
Posting sample code here
AuthService
export class AuthService {
loggedIn: boolean = false;
isLoggedIn() {
return this.loggedIn;
}
login(credentials) {
let user = JSON.stringify(credentials);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post(this._apiUrl, user, options)
.map(res => res.json())
.map((res) => {
this.loggedIn = true;
}
return res;
});
}}
Loggedin Guard
export class LoggedInGuard implements CanActivate {
constructor(private _auth: AuthService, private _router: Router) {}
canActivate() {
//Get problem here. Everytime this comes false
if(this._auth.isLoggedIn()) { return true; }
this._router.navigate(['login']);
}
}
login component
export class LoginComponent {
constructor(private userService: AuthService, private router: Router) {}
onSubmit(email, password) {
this.userService.login(email, password).subscribe((result) => {
if (result) {
this.router.navigate(['']);
}
});
}
}
Btw, following example of
https://medium.com/#blacksonic86/angular-2-authentication-revisited-611bf7373bf9#.723a4ssji
without localstorage