i have some passport problem with NestJS
i used passport with NestJS to make Guard extent from AuthGuard
source: https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts
but every time auth an error occurs
please support me
109 messages · Page 1 of 1 (latest)
i have some passport problem with NestJS
i used passport with NestJS to make Guard extent from AuthGuard
source: https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts
but every time auth an error occurs
please support me
Why are you using passport on a microservice?
for authentication of JWT
@vagrant summit this is my current resource, I'm devloping the JWT part https://github.com/SangVoM/boilerplate-microserve-nestjs
But why? Shouldn't your microservice be behind a tunnel the only you can access so if the request is authenticated at the gateway it should be fine for the microservice?
I just ask it to authenticate at the api_gateway
it will be ok to validate at input
What kind of suggestion are you looking for?
I don't understand from where does passport.authenticate get its info?
Info as in the info variable, or just the information it uses in general?
info variable
Third parameter of the callback. I'd have to dig through passport's code to tell you exactly how it gets too the
Is this info the user's info ?
No, that should be the user parameter, IIRC
So what is it i'm getting undefined there and giving error.
Where are you getting undefined?
Again, I'd have to dig through passport's code to remember what info is supposed to be. Are you getting an error at all, or is the value just undefined she you want to know why?
Yes, please. Thanks
That wasn't a yes or no question
I'm getting the above error because no one can help me so I'm looking for a suggestion
if you could see my code and give me the answer that would be great
What error. The unauthorized error?
This is still in your microservice, right?
yes
Can you show your jwt strategy?
here men'
What transport are you using for your microservice? More than likely, what is becoming the req object doesn't have a headers property and thus passport can't read the authorization header to get the jwt for verification.
That's why I said authentication should be done at the gateway rather than in the microservice itself
What transport are you using for your microservice => I use Redis
Yeah pretty sure redis requests don't have headers
More than likely, what is becoming the req object doesn't have a headers property and thus passport can't read the authorization header to get the jwt for verification. => I don't know if I misunderstood the question but my request still has header
Is that inside the gateway or the microservice? How are you checking the request?
All of that looks like express's request object, which wouldn't exist inside the microservice
That's why I said authentication should be done at the gateway rather than in the microservice itself => i'm validating it on the outermost layer
request at api_gateway =>. redis => app_service and returned api_gateway as proof that my channels pay data and right at JwtStrategy I get user login information
Okay so you are authenticating at the gateway? That's good.
Is that inside the gateway or the microservice? How are you checking the request? => it's inside of gateway, i'm checking its log when requesting 1 JWT at gateway's JWTGuand
Can you show me your JwtGuard? It's just a simple extends AuthGuard('jwt') right?
RPCAuthGuard custom from https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts
If you're doing this inside your gateway, then why are you switching to rpc?
it's just naming RPCAuthGuard it's no different from Auth.guard and I'm applying the mechanism of RPC
You're doing authentication in your gateway, right?
Yes, your check my source code from me: https://github.com/SangVoM/boilerplate-microserve-nestjs
please wait update authenticate
@vagrant summit i'm updated
can your run docker in local and check it authentication in gateway
How would I hit your server? I don't see any endpoints, just @RpcMethod()s
{ "jsonrpc": "2.0", "id": 1, "method": "user.register", "params": { "username": "sangvm", "email": "sang.vo@smartdev.com", "password": "123123123", "passwordConfirm": "123123123" }
Where do you define that endpoint?
on method
Maybe I wasn't clear: where do you define the POST /rpc/v1 endpoint in your server?
can you open file main.ts I open one path in here. It read on file application.yml
and NestJS give me a function connectMicroservice to do it
Okay. I see
That wasn't what I meant by "do subscription in the gateway"
I meant you should be doing it on an http route handler you have control of
Because what your doing now, it doesn't matter if it's in the "gateway" application or some server called "puppies", the authentication is being done in the microservice portion of the request, not the HTTP portion
Passport being an express middleware was really only designed for HTTP.
If you can wait for a bit, I'm sure I can finagle some sort of solution where authentication can be done with passport and JSON rpc with your example, but I still think that it should be handled by an http route handler you have control over
If you can wait for a bit, I'm sure I can finagle some sort of solution where authentication can be done with passport and JSON rpc with your example => Yes can you give me example with it
I still think that it should be handled by an http route handler you have control over => I will update it if there is no other solution or next version
If yes, can you contribute to me? 🙏
@vagrant summit do you need me to send you .env to check it.
All I ended up having to do was add this method to your JWTGuard
getRequest(context: ExecutionContext) {
return context.switchToRpc().getContext().req;
}
This way, req.headers is populated for passport, because it reads off of the request object that Nest knows to pass to it. Normally, this is context.switchToHttp().getRequest(), but you have to do some custom work to make it fine in your JSONRPC context
I think it's the same have you tested it?
return context.switchToRpc().getContext().req; same context.switchToRpc().getContext()['req'];
That would be the same, yes
handleRequest(err, user, info, context: ExecutionContext, status): TUser { if (err || !user || !context.switchToRpc() || !info || !status) { throw err || new UnauthorizedException(); } return user; }
both things get req and generate error, in my log it says error at
Did you actually add the getRequest
I tried your getRequest put in the code and test
Well, it worked for me when I just used that added method
Can you show me screen code?
Are you trying this medthod ?
{ "jsonrpc": "2.0", "id": 1, "method": "user.get_info_user", "params": {} }
I did and it works so long as there's an authorization header
not works from me 🥲
import { CodeErrorRpcException, JsonRpcContext } from "../microservice/rpc";
import { ExecutionContext, HttpStatus, Injectable } from "@nestjs/common";
import { RPCAuthGuard } from "./rpc-auth.guard";
import { LoggerService } from "../logger/logger.service";
import { HttpStatusMessage } from "../message/http-status.message";
@Injectable()
export class JWTGuard extends RPCAuthGuard("jwt") {
private unauthorizedError = new CodeErrorRpcException(
HttpStatusMessage.UNAUTHORIZED,
HttpStatus.UNAUTHORIZED
);
canActivate(context: ExecutionContext) {
try {
LoggerService.log("#JWTGuard.canActivate", JWTGuard.name);
const authData = context
.switchToRpc()
.getContext<JsonRpcContext>()
.getMetadataByKey("Authorization");
if (!authData) {
LoggerService.error(
"#JWTGuard.canActivate",
this.unauthorizedError.stack,
JWTGuard.name
);
throw this.unauthorizedError;
}
return super.canActivate(context);
} catch (e) {
throw this.unauthorizedError;
}
}
getRequest(context: ExecutionContext) {
return context.switchToRpc().getContext().req;
}
}
getRequest in JWTGuand for what I don't see any function calling it here ?
Getting a 500 might actually be correct here. Microservices work differently when it comes to errors. You need to catch the error that's been serialized by the microservice and deserialize it in the http gateway
The AuthGuard class calls it. This sub class overrides the original to customize how the sub class functions
So in the RPCAuthGuand class, did you edit anything to call getRequest in the parent class ?
No, it should already extend the AuthGuard right?
No, current extend the RPCAuthGuard.
Your RPCAuthGuard calls that method
I tried this code not works and JWTGuard extends RPCAuthGuard('jwt')
I don't quite understand this question
Not a question. It was a statement
if it works can you push to the code work from your side
Well, "works" in that I get a 500 back and a proper log that says what the error is. To get a 403/401 bank you need to deserialize the error, as I already mentioned. I'll make a fork and pull tomorrow most likely
maybe you will need it.
I will debug and see if there is any related information I will send you
Request:
xh :3001/rpc/v1 jsonrpc="2.0" id="1" method="user.get_info_user" Authorization:"Bearer some.token.json"
Log/error (expected)
LOG: false JsonWebTokenError: invalid token
at Object.module.exports [as verify] (~/node_modules/.pnpm/jsonwebtoken@9.0.0/node_modules/jsonwebtoken/verify.js:82:17)
at Function.module.exports [as JwtVerifier] (~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/verify_jwt.js:4:16)
at ~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/strategy.js:104:25
at JwtStrategy._secretOrKeyProvider (~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/strategy.js:40:13)
at JwtStrategy.authenticate (~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/strategy.js:99:10)
at attempt (~/node_modules/.pnpm/passport@0.6.0/node_modules/passport/lib/middleware/authenticate.js:369:16)
at authenticate (~/node_modules/.pnpm/passport@0.6.0/node_modules/passport/lib/middleware/authenticate.js:370:7)
at ~/src/common/guard/rpc-auth.guard.ts:118:9
at new Promise (<anonymous>)
at ~/src/common/guard/rpc-auth.guard.ts:106:5
[ERROR][12/29/2022, 9:10:52 AM] [RpcExceptionsHandler] Unauthorized +13ms
UnauthorizedException: Unauthorized
at JWTGuard.handleRequest (~/src/common/guard/rpc-auth.guard.ts:91:22)
at ~/src/common/guard/rpc-auth.guard.ts:60:16
at ~/src/common/guard/rpc-auth.guard.ts:110:26
at allFailed (~/node_modules/.pnpm/passport@0.6.0/node_modules/passport/lib/middleware/authenticate.js:110:18)
at attempt (~/node_modules/.pnpm/passport@0.6.0/node_modules/passport/lib/middleware/authenticate.js:183:28)
at JwtStrategy.strategy.fail (~/node_modules/.pnpm/passport@0.6.0/node_modules/passport/lib/middleware/authenticate.js:305:9)
at ~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/strategy.js:106:33
at Object.module.exports [as verify] (~/node_modules/.pnpm/jsonwebtoken@9.0.0/node_modules/jsonwebtoken/verify.js:82:12)
at Function.module.exports [as JwtVerifier] (~/node_modules/.pnpm/passport-jwt@4.0.1/node_modules/passport-jwt/lib/verify_jwt.js:4:16)
When I actually went through and created a method to generate a token, then used that token on the get_info_user it worked (besides waiting for a response cause I'm only running one of your servers). I'll have to clean up the diffs because prettier is running automatically and cleaning a lot of your code to its standards so give me a bit. Just wanted to show what the request looks like and what's happening
Yes thanks, i'm not finding the cause of it either, even though i got the user info
this is the log i sent you, i'm having problem in RPCAuthGuard it can't return user info and got error in handleRequest
For me, the error came from an invalid jwt
obviously get the user information but why is the error message Invalid token ? 🤔
If you send something like jwt then it's correct, because the current code can't decode something like jwt
I found a solution for it thanks to your suggestion
handleRequest(err, user, info, context: ExecutionContext) { if (err || info || !user) { throw err || info || this.unauthorizedError; } handleRpcRequest(user, UserShowDto, UserInfo, context.switchToRpc()); return user; }
it's the same as the getRequest you suggested