GithubHelp home page GithubHelp logo

Comments (31)

csidell-earny avatar csidell-earny commented on April 20, 2024 9

While that does work it skips the validation and sanitization the original function does. You're able to achieve the same by overriding the authenticate function and it retains all original behavior of the strategy.

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
    authenticate(req, options: any): any {
        super.authenticate(req, Object.assign(options, {
            hd: '<HD_PARAM>'
        });
    }
}

Edit: You can achieve similar results by calling super.authorizationParams, however if anyone stumbled upon custom_params or custom parameters this would be the way it'd work across providers (potentially).

from passport.

artificialhoney avatar artificialhoney commented on April 20, 2024 6

@iveselin just try with:

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  // ...
  // WILL be passed to authenticate()
  authorizationParams(options: any): any {
    return Object.assign(options, {
      hd: '<HD_PARAM>'
    });
  }
}

The problem is, that non-standard params passed through constructor super() call are ignored, which normally should work (https://github.com/jaredhanson/passport-google-oauth2/blob/master/lib/strategy.js#L159). Just use authorizationParams as in the example above.

from passport.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024 6

https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts#L82

We pass AuthModuleOptions to the authenticate() function, so you should be able to put them here:

PassportModule.register({
      approval_prompt: 'force',
      access_type: 'offline',
})

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024 2

@csidell-earny I tried your PR with my app. Identical code with only swapping in/out your version of @nestjs/passport works with current version, fails as follows.

I can't make this repo public, but if it matters, I could see if I can strip it down. But it looks like it has to do with the fact that I'm also using Passport sessions, a la stuff like this in my main.ts:

app.use(session(...

app.use(passport.session())
Error: Failed to serialize user into session
[0]     at pass (/home/john/code/dwserver5/node_modules/passport/lib/authenticator.js:281:19)
[0]     at Authenticator.serializeUser (/home/john/code/dwserver5/node_modules/passport/lib/authenticator.js:299:5)
[0]     at SessionManager.logIn (/home/john/code/dwserver5/node_modules/passport/lib/sessionmanager.js:14:8)
[0]     at IncomingMessage.req.login.req.logIn (/home/john/code/passport-1/node_modules/passport/lib/http/request.js:50:33)
[0]     at Promise (/home/john/code/passport-1/dist/auth.guard.js:58:64)
[0]     at new Promise (<anonymous>)
[0]     at GoogleLoginGuard.<anonymous> (/home/john/code/passport-1/dist/auth.guard.js:58:23)
[0]     at Generator.next (<anonymous>)
[0]     at /home/john/code/passport-1/dist/auth.guard.js:19:71
[0]     at new Promise (<anonymous>)

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024 2

Here ya go
https://github.com/johnbiundo/nestpasspr94

from passport.

TrejGun avatar TrejGun commented on April 20, 2024 2

According to Facebook docs for api 2.4 (current is 3.2)

Fewer default fields for faster performance: To help improve performance on mobile network connections, we've reduced the number of fields that the API returns by default. You should now use the ?fields=field1,field2syntax to declare all the fields you want the API to return.

https://developers.facebook.com/blog/post/2015/07/08/graph-api-v2.4/

This means even if I use profileFields in Strategy constructor

      profileFields: ["id", "email", "name"],

I still have to pass additional params to authorize function like this

passport.use(new FacebookStrategy({
          clientID: "CLIENT_ID",
          clientSecret: "CLIENT_SECRET",
          callbackURL: "http://www.example.com/auth/facebook/callback"
          passReqToCallback : true,
          profileFields: ["id", "emails", "name"] 
    })
);

app.get("/connect/facebook", passport.authorize("facebook", { scope : ["email"] }));

Thanks to @csidell-earny his workaround works fine for me

  authenticate(req: Request, options?: Record<string, any>): void {
    super.authenticate(req, Object.assign(options, {
      scope: ["email"]
    }));
  }

from passport.

prateekkathal avatar prateekkathal commented on April 20, 2024 1

Ahhh, got you now. That might be tricky. You could theoretically extend the guard and strip options properties depending on the provider in the constructor.

I am not sure why we need a separate method just as @kamilmysliwiec said. The above suggestion makes perfect sense to me.

I have Google, Twitter & Facebook working altogether with separate Strategy & Guards. An authenticate method with customParameters seems un-necessary to me as well. All I am doing is passing different options to constructor of the new strategies.

Also, just to be clear, according to passport-google-oauth2's strategy.js,

approval_prompt: 'force',  // should be "approvalPrompt" - strategy.js#L183
access_type: 'offline', // should be "accessType" - strategy.js#L138

CC: @johnbiundo

from passport.

iveselin avatar iveselin commented on April 20, 2024

Having the same issue with hd param for google, can you show the usage of a workaround?

UPDATE:
According to this, you have to provide specific options to passport.authenticate(), any idea how one could do that with auth guard?

from passport.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024

The problem is, that non-standard params passed through constructor super() call are ignored, which normally should work

Can someone point me at the line of code that strips those options in @nestjs/passport? I looked at this PR https://github.com/nestjs/passport/pull/94/files and I actually don't see any reason why we should define an extra property (customParameters)

from passport.

Sieabah avatar Sieabah commented on April 20, 2024

@kamilmysliwiec It's not that @nestjs/passport strips them it's that some providers don't take in those options on the constructor.

It may be specific to Google's passport but they never take the options that are passed into the constructor, so it forces us to override the authenticate function to be able to handle Google. Here is the offending line.
https://github.com/mstade/passport-google-oauth2/blob/master/lib/oauth2.js#L58

Edit:

Additionally the core OAuth2 strategy does not merge the options from the constructor https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L130

from passport.

csidell-earny avatar csidell-earny commented on April 20, 2024

Which works for a single auth provider but if you wanted to support Microsoft and Google and they have a collision in auth params you'd run into issues.

How would you support multiple passport providers? Assuming using auth0 isn't available.

Is the correct solution to create a passport module per auth provider? How would you correctly set up the AuthGuard in this instance?

from passport.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024

Ahhh, got you now. That might be tricky. You could theoretically extend the guard and strip options properties depending on the provider in the constructor.

from passport.

csidell-earny avatar csidell-earny commented on April 20, 2024

Or provide them with a parameter in the strategy of the provider?

That's why I added the PR, so it can be done closest to where it is actually necessary.

from passport.

csidell-earny avatar csidell-earny commented on April 20, 2024

@kamilmysliwiec Should the strategy just override the authenticate function instead? I'm not sure how the auth guard would specifically solve this problem. An example with our projects would have multiple ways to authenticate with google/microsoft/facebook but sign our own jwt's with our own info. So we never use the google/microsoft/facebook auth guards as that's just for signup and login.

We have it working by just overriding the authenticate function but that requires specifically to be careful that @nestjs/passport doesn't change how authenticate is called (not that it would) whereas passing in a customParameters would allow this project to manage the plumbing and simplify the consumer strategies

from passport.

Sieabah avatar Sieabah commented on April 20, 2024

Odd... Yeah I might need a minimum repo to debug that one. I don't see why it'd affect sessions.

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

That will take some work. Let me see if I can figure out how to do it...

from passport.

Sieabah avatar Sieabah commented on April 20, 2024

I'd imagine you could just create a skeleton project with the cli and just copy over some hardcoded auth stuff. Don't need to integrate with everything.

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

Yeah. It's integrated with a client side Angular app. A few tricky things to unwind. The app actually manages the authentication UI (Google Auth Popup, etc.) from the client side instead of a regular redirect. Shouldn't be too bad. I hope. 😄

from passport.

Sieabah avatar Sieabah commented on April 20, 2024

@johnbiundo Using your repo and swapping out for my library I can't get it to fail as you've explained.

As far as I can tell from your repo it works, I get the serialized user just fine.

I did have to remove a null reference to the usersModule in your AuthModule though. (Nothing else references it)

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

@Sieabah I may not have a chance to try this again for a week or two. Currently on jury duty.

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

@Sieabah

OK, I had a chance to try this again. Still getting the same error. Here's what I do:

  1. Yeah, you're right about the extraneous UsersModule reference. Removed that.
  2. Clone your repo, npm install, npm run build.
  3. Clone my repo in a sibling folder.
  4. npm install ../passport -- this installs your lib. I can see it in my project under node_modules/@nestjs/passport with your code
  5. npm run start on my project, attempt Google login; after submitting the Google login page --> get the failure shown above.

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

I updated my repo with those changes, and it also removed default install of @nestjs/passport, and includes the callback URL that should work for localhost.

from passport.

Sieabah avatar Sieabah commented on April 20, 2024

Alright I'll take another look this weekend.

from passport.

ruslanguns avatar ruslanguns commented on April 20, 2024

thank you @johnbiundo you saved my day!

from passport.

johnbiundo avatar johnbiundo commented on April 20, 2024

@ruslanguns Great! Glad it helped!

from passport.

xyide avatar xyide commented on April 20, 2024

... you have to provide specific options to passport.authenticate(), any idea how one could do that with auth guard?

I'm late to the party and not sure if this is something that has been supported with newer versions since you asked the question, but to provide specific options to the the passport authenticate function via an auth guard, you would extend the auth guard and specify the options in the constructor.

For example, I had to create an auth guard for Facebook that would make sure that auth_type=rerequest is always specified in the parameters when authenticating, so my guard looks like this:

export class FacebookAuthGuard extends AuthGuard('facebook') {
  constructor(private configService: ConfigService) {
    super({
      authType: 'rerequest',
    });
  }
}

With that, authTpe is always processed by passport's Strategy.prototype.authorizationParams prototype function and passed along to the authenticate function.

from passport.

sebastiangug avatar sebastiangug commented on April 20, 2024

Just want to say I'm at the end of 5 hours of debugging tracking this down. insane!

Can we at least document this behaviour for the future?

from passport.

Almaju avatar Almaju commented on April 20, 2024

I could do it like that:

@Module({
	imports: [
		PassportModule.register({
			accessType: 'offline',
			prompt: 'consent',
		}),
	],
	controllers: [...],
})
export class AuthModule {}

from passport.

knownasilya avatar knownasilya commented on April 20, 2024

Same happens for me when using the local strategy:

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: 'email', passwordField: 'password' });
  }

  async validate(username: string, password: string): Promise<any> {
    let email = username;
    const user = await this.authService.validateUser(email, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

The passport strategy mixin class seems to get no arguments in the constructor

Screen Shot 2020-08-26 at 1 00 03 PM

So the options never get set:

Screen Shot 2020-08-26 at 1 03 37 PM

Maybe related to https://stackoverflow.com/a/36204599/483616?

from passport.

knownasilya avatar knownasilya commented on April 20, 2024

Ok, for me it looks like some sort of build cache. Basically stopping and restarting the watch wasn't enough, I had to run yarn build and that nuked dist and it worked after. The code in dist was correct though, so not sure what was going on.

from passport.

Romstar avatar Romstar commented on April 20, 2024

https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts#L82

We pass AuthModuleOptions to the authenticate() function, so you should be able to put them here:

PassportModule.register({
      approval_prompt: 'force',
      access_type: 'offline',
})

thanks for this, I can't believe this issue still exists.

from passport.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.