I'm trying to implement RS256 JWT tokens in nestjs backend. I followed the example provided in nestjs documentation.
In my module I register the JwtModule with my private key:
#Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: extractKey(`${process.cwd()}/keys/jwt.private.key`),
signOptions: {
expiresIn: 3600,
},
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy, HttpStrategy],
})
export class AuthModule {}
I'm able to call auth/token endpoint and get the token but when I try to access guarded endpoint I always get 401.
Below you can find my custom JwtStrategy:
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: extractKey(`${process.cwd()}/keys/jwt.public.key`),
});
}
async validate(payload: JwtPayload) {
console.log('JwtStrategy');
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
And guarded endpoint:
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
#Get('token')
async createToken(): Promise<any> {
return await this.authService.createToken();
}
#Get('data')
#UseGuards(AuthGuard())
findAll() {
console.log('Guarded endpoint');
// This route is restricted by AuthGuard
// JWT strategy
}
}
I assume that when I call the auth/data I should see in the console at least the "JwtStrategy" string that I log in the validate method. Unfortunately it never shows up. Why the validate method is never called?
Please find the codesandbox below
You have to specify RS256 as the algorithm for in both the JwtModule and the JwtStrategy:
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: publicKey,
algorithms: ['RS256'],
^^^^^^^^^^^^^^^^^^^^^^
});
and
JwtModule.register({
secretOrPrivateKey: privateKey,
signOptions: {
expiresIn: 3600,
algorithm: 'RS256',
^^^^^^^^^^^^^^^^^^^
},
}),
Not sure if it works but you can try this
#UseGuards(AuthGuard('jwt'))
above your protected route.
It's quite possible that the public key and/or private key files were not generated in RS256 format.
I'd recommend trying the following:
https://gist.github.com/ygotthilf/baa58da5c3dd1f69fae9
Related
Can anyone let me know how to create an instance of the DB using TypeORM?
I would like to make it accessible as this service does but the Connection class is deprecated..
import { Inject, Injectable } from '#nestjs/common';
import { Connection, Repository } from 'typeorm';
#Injectable()
export class DatabaseService {
constructor(#Inject('Connection') public connection: Connection) {
console.log('!!!!')
}
public async getRepository<T>(entity: any): Promise<Repository<T>> {
return this.connection.getRepository(entity);
}
}
What is the alternative now?
How should I set up the DatabaseModule? In order to make it accessible? Using DataSource???
#Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'postgres',
host: process.env.DB_HOST,
port: +configService.get('DB_PORT'),
username: configService.get('DB_USER'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'),
autoLoadEntities: true,
synchronize: true,
})
})
],
providers: [DatabaseService]
})
export class DatabaseModule {}
Thanks in advance.
Try to #InjectDataSource() instead of #InjectConnection().
From TypeORM documentation:
TypeORM's DataSource holds your database connection settings and
establishes initial database connection or connection pool depend on
RDBMS you use.
From the DataSource you'll be able to access everything you need: EntityManager, QueryRunner, EntityMetadata, repositories and other. Here's the documentation for the DataSource API
I am trying to test csrf protection in my nest application as per the nest documentation by using csurf but when I try to test using Postman its always showing invalid csrf.
I am using express platform which is default.
As per the documentation on csurf I am using express-session
I am applying csrf globally.
I try localhost:3000/csrf & get the token
then I go to localhost:3000/process in postman and add the token but get invalid csrf token
screenshot of how sending csrf in postman
Also tried sending _csrf as json { "_csrf": "----token_here-----" } but no go.
main.ts
import { ValidationPipe } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import helmet from 'helmet';
import * as session from 'express-session';
import * as csrf from 'csurf';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use([
helmet(),
session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: {},
}),
csrf(),
]);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
}),
);
await app.listen(3000);
}
bootstrap();
app.controller.ts
import { Controller, Get, Post, Req } from '#nestjs/common';
import { AppService } from './app.service';
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Get()
getHello(#Req() req): string {
return this.appService.getHello();
}
#Get('csrf')
getCsrf(#Req() request: any): string {
return request.csrfToken();
}
#Post('process')
postProcess() {
return "hello there, I am processing";
}
}
I try to use a NestJS backend with a Nginx reverse proxy.
I have coded an authentication part in my NestJS backend.
My problem is that when I used my frontend / backend in local mode, all is ok.
When I use it through Nginx, I always retrieve a 401 error.
I think it’s due to the LocalStrategy in NestJS
Here is the part in the local.strategy.ts file
import { Strategy } from 'passport-local';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { AuthService } from '../auth.service';
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
usernameField: 'userLogin',
passwordField: 'userPassword',
});
}
async validate(userLogin: string, userPassword: string): Promise<any> {
const user = await this.authService.validateUser(userLogin, userPassword);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Here is the part in the app.controller.ts file
#Public()
#UseGuards(LocalAuthGuard)
#Post('auth/login')
async login(#Request() req) {
return this.authService.login(req.user);
}
But I don’t know how to change it.
If somebody have an example it build be great.
Thanks in advance.
I've tested with curl locally on server (without nginx).
I saw my error (mysql access to test the user), it was not due to nginx configuration.
I spend the last 3 days to fix the problem , but i didnt figure out yet the issue.
Angular CLI: 6.0.8
Node: 8.11.2
OS: win32 x64
Angular: 6.0.6
multer. 1.3.1
my code at "childApi" using multer staff :
var store = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '.' + file.originalname);
}
});
var upload = multer({ storage: store , }).single('file');
router.post('/upload', function (req, res, next) {
upload(req, res, function (err) {
if (err) {
return console.log ('not working well')
}
//do all database record saving activity
return res.json({ originalname: req.file.originalname, uploadname: req.file.filename });
});
});
my code at "add-child" component using simple code :
import { Component, OnInit, Inject } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '#angular/material';
import { Child } from '../../models/child';
import { ChildService } from '../../services/child.service';
import {FileUploader } from 'ng2-file-upload';
const uri = 'http://localhost:3000/childApi/upload';
#Component({
selector: 'app-add-child',
templateUrl: './add-child.component.html',
styleUrls: ['./add-child.component.css']
})
export class AddChildComponent implements OnInit {
newChild = new Child;
uploader: FileUploader = new FileUploader({ url: uri });
attachmentList: any = [];
constructor(private childService: ChildService,
private route: ActivatedRoute,
private router: Router,
public dialogRef: MatDialogRef<AddChildComponent>,
#Inject(MAT_DIALOG_DATA) public data: any) {
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
this.attachmentList.push(JSON.parse(response));
};
}
The problem is that after I upload the file to the folder "uploads"
,I want to display my new photo on the screen.
The console give me this error :
GET unsafe:C:\fakepath\child+thinking.jpg 0 ()
If someone help its will be amazing.
Thanks...
I figure out what to do , I just put this sentences inside my code at "add-child" component using :
this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
this.newChild.user_img = JSON.parse(response).uploadname;
this.attachmentList.push(JSON.parse(response));
};
}
As I understand from your post that you have doing a model named child inside your project so if you have can I take a look on it I will be grateful because I'm doing the same task except still getting the error:
Access to XMLHttpRequest at 'http://localhost:4000/file/upload' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
core.js:1449 ERROR SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at FileUploader.UploadFileComponent.uploader.onCompleteItem (upload-file.component.ts:27)
at FileUploader.push../node_modules/ng2-file-upload/file-upload/file-uploader.class.js.FileUploader._onCompleteItem (file-uploader.class.js:199)
at XMLHttpRequest.xhr.onerror [as __zone_symbol__ON_PROPERTYerror] (file-uploader.class.js:268)`
javascript html typescript angular6 multer
I'm using Auth0 with Angular 2. I have the following login code that don't go to the home page after authentication.
To my understanding, the auth0 will not do the redirection. It sends off authenticated event, and it should create an item in localstorage then navigate to the home page.
#Injectable()
export class AuthService {
lock = new Auth0Lock(this.config.clientID, this.config.domain, {
auth: {
responseType: 'token',
}
});
constructor(private http: Http, private config: AppConfig, private router: Router) {
// Add callback for lock `authenticated` event
this.lock.on('authenticated', (authResult) => {
localStorage.setItem('id_token', authResult.idToken);
console.log(localStorage);
this.router.navigate(['home']);
});
}
you can try location.replace('/home') or location.replace('http://localhost:4200/home')