Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose ExecutionContext inside validate function #8

Closed
Sturgelose opened this issue May 17, 2018 · 4 comments
Closed

Expose ExecutionContext inside validate function #8

Sturgelose opened this issue May 17, 2018 · 4 comments

Comments

@Sturgelose
Copy link

As user I'd like to use the ExecutionContext to take decisions when doing authn/authz with Passport.

Initially I tried to use multiple guards,

This could be easily done exposing the execution context to this or somehow passing it to Passport to it makes it available in the validate() function.
Otherwise, maybe I could be able to override the newly created canActivate function, precreated by the mixin and add my custom logic underneath....

@Sturgelose
Copy link
Author

@kamilmysliwiec just saw your related issue :)
I found out that we can pass a parameter to Passport to expose the ExecutionContext :)

Using super({ passReqToCallback: true }); in the class, enables to see the request (it's a parameter from PassportJS). From there, we can read parameters from the URL, queries, and many other things :)

@Injectable()
export class BearerStrategy extends PassportStrategy(Strategy) {
  constructor(
    private readonly authService: AuthService,
    private readonly tokenService: AccessTokenService,
  ) {
    // passReqToCallback allows to have the request in the validate() function
    super({ passReqToCallback: true });
  }

  /**
   * Function to check that a given token is valid
   * @param request
   * @param token Token to be validated
   * @param done Callback when finished
   * @returns {Promise<any>}
   */
  async validate(request: IncomingMessage, token: string, done) {
    // Fetch a user by a token
    const user = await this.authService.validateToken(token);

    // No matching user found or Token Expired
    if (!user) {
      return done(new UnauthorizedException(), false);
    }

    const allowAccess = await this.authService.validateACL(user.id, request);
    allowAccess ? done(null, user) : done(new UnauthorizedException(), false);
  }
}

@Sturgelose
Copy link
Author

Hi, another update. Seems the only context exposed is the HTTP one. In order to use reflectors, this would need the original context. So still, this wouldn't be possible to be fixed with the solution I found. The best solution would be to expose by default the whole context in the validate function, instead of the incoming message

@Sturgelose
Copy link
Author

Ok, after some more research, it's not possible to add the nestjs context into the passportjs context. The reason is that passport expects a request object, nothing else.

Finally I used a different approach: use the nestjs/passport module to do authentication. This module sets the user value back in the response object in the context.
Then in a second guard, I do authorization, using the precalculated user data in the previous guard.

This now works as expected ;)

@kamilmysliwiec
Copy link
Member

kamilmysliwiec commented Jun 23, 2018

Use the nestjs/passport module to do authentication. This module sets the user value back in the response object in the context. Then in a second guard, I do authorization, using the precalculated user data in the previous guard.

This ^ solution sounds like the best possible one 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants