I have applied authentication in NestJS middlewares and decoding all the information from user token by the third party API.
Now I have got the information in my middleware, how can I send that information to controllers and services?
It is normal for middlewares to add information to the request object (eg. adding a user object).
For a clean way to extract information from the request object and inject it into the controller you can make a custom route decorator
For example, extracting the user:
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
And then in your controller
#Get()
async findOne(#User() user: UserEntity) {
console.log(user);
}
From there you can just ensure that your service methods receive the User as a regular method parameter
Related
I have implemented user session with redis and passport, works fine when I use it on a monolith
But I don't know how to implement it on a microservices, I want only put a guard in the api gateway and it send a request to validate user session to auth microservice
This is my guard to validate user session:
#Injectable()
export class CookieAuthGuard implements CanActivate {
async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
return request.isAuthenticated();
}
}
I don't know how to validate it on my provider to call it in my api gateway
And I don't know how to put my login into the provider too, because i have a guard for that:
#Injectable()
export class LogInWithCredentialsGuard extends AuthGuard('local') {
async canActivate(context: ExecutionContext): Promise<boolean> {
await super.canActivate(context);
const request = context.switchToHttp().getRequest();
await super.logIn(request);
return true;
}
}
Any idea to implement validation of session working on the api gateway, and how to put login into provider?
Thanks!
I have this route here:
#UseGuards(LocalAuthGuard)
#Post('login')
async login(
#Request() req,
#Body(new LoginUserValidationPipe()) body: LoginUserDto,
) {
return this.authService.issueJWT(req.user);
}
I am doing right now the error handling. This route expects an object with two properties: email and password. The scenario that I am thinking is when a user sends the request without the email property, having only the password. But it fails. I did use the class-validator package to handle the errors and validation, but the request never gets there. I think the Guards already pick up that something is wrong and throw an error, but I didn't want that. My local strategy is as follows:
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
constructor(private authService: AuthService) {
super({
usernameField: 'email',
});
}
async validate(email: string, password: string): Promise<UserDto> {
const user = await this.authService.validateUser(email, password);
if (!user) {
throw new NotFoundException();
}
return user;
}
}
Does anyone know how can I access the request before the Guards? I tried creating another Guard and putting it before this one, but it didn't work.
Guards are always ran before other enhancers as it is stated in the docs. The only way to run a guard before another guard is to put it at a higher priority (either at a handler level above [e.g. original guard is route handler level so new guard is at controller level]) or to put it before the guard in the #UseGuards(). The other option you have would be to run a middleware to validate your body here.
i'm making google-auth site, and i made custom user-decorator and it can't return user.
#UseGuards(AuthGuard('jwt'))
#Get('profile')
getProfile(#UserDecorator() user: User) {
return user;
}
this is my controller's code
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const UserDecorator = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
console.log(request)
return request.user;
},
);
this is my custom user decorator.
my controller's function supposed to return user's info using by JWT (parsing)
but this function return's 401 error , so when i delete
#UseGuards(AuthGuard('jwt'))
and my custom decorator 's console.log(request) returns....->>
this kind of something strange object.
i checked with f12 button, and jwt token was exists.
If when you remove:
#UseGuards(AuthGuard('jwt'))
you don't receive the 401 error again, it means that you haven't done the login before you call the API.
I have a NestJS backend, secured by JWT.
I would like to know what is the best way to store the actual user or the best way to pass it to my services?
I have a JwtAuthGuard
#Injectable()
export class JwtAuthGuard extends AuthGuard( 'jwt' ) {
canActivate(context: ExecutionContext) {
return super.canActivate( context );
}
handleRequest(err, user, info) {
if ( err || !user ) {
throw err || new UnauthorizedException();
}
return user;
}
}
My actual user id is in user var in handleRequest but I don't know where to "stock" it to be able to reach it in some modules.
Does anyone can help me ?
Thanks
The JWT itself is where you store the user id (or any identifying details of the user).
If you create the JWT payload with the user id ({ id: 123, ... }) the passport will set the user member to the request object.
Important: Don't store sensitive data in the JWT.
#AuthGuard( 'jwt' )
#Get('profile')
getUserId(#Request() req: any) {
return req.user.id;
}
You can pass the req.user.id to services as needed.
See: https://docs.nestjs.com/techniques/authentication#implement-protected-route-and-jwt-strategy-guards
One last thing:
If you like to have types for the request object you can do something like this
import { Request as HttpRequest } from 'express';
interface UserJwtPayload {
id: string,
}
type AuthRequest = HttpRequest & { user: UserJwtPayload }
I am building web application using NodeJS for the server-side and Angular 2 for the client-side.
In the application I'm using ADFS to authenticate users.
The user browses to the website and automatically redirected to the ADFS authentication server. After the user completes the authentication, he redirects back to my application and I get the user data from the ADFS server.
I used passport-saml package to implement the authentication and it works fine.
The user is now stored at req.user.
Now I need to use user's data on the client side.
After a little research, I found that passing user's data from server to client can be as simple as :
router.get('/user/current', AuthMiddleware.requireLogin, (req: express.Request, res: express.Response) => {
return res.json(req.user);
});
This works as well.
Now for the client-side:
I've created a service to fetch the authenticated user :
#Injectable()
export class AuthService {
private authUrl = 'http://localhost/api/user/current';
private currentUser: User;
constructor(private http: Http) {
this.getUser().subscribe(user => {
this.currentUser = user;
});
}
getUser(): Observable<User> {
return this.http.get(this.authUrl)
.map((res: Response) => res.json())
.catch(error => Observable.throw(error.json().error || 'Server Error'));
}
isAuthenticated(): boolean {
return !!this.currentUser;
}
}
So the getUser method returns an Observable with my user and I can use it in my client-side.
But my question is :
Should I inject the AuthService to each component which uses the authenticated user?
And if so, should I call getUser each time and wait for the Observable to return user's data, or should I use public parameter for the authenticated user?
(for example making the currentUser parameter public in the AuthService and then just use authService.currentUser?)
You don't need to inject the AuthService into each component. What you want to do instead is guard the various routes in your application from activation unless a user has been authenticated. You must implement an AuthGuard that will have the AuthService injected.
Check out https://angular.io/docs/ts/latest/guide/router.html (search the page for "GUARD THE ADMIN FEATURE") for more information.