passport-oauth2 icon indicating copy to clipboard operation
passport-oauth2 copied to clipboard

Is there a way to maintain query params from the initial request?

Open christopher-francisco opened this issue 6 years ago • 9 comments

I have this route:

router.get('/auth', passport.authenticate('oauth2'));

When I visit /auth?redirect_to=myInitialEncodedURL, I get redirected to the oauth endpoint, without the redirect_to parameter:

/oauth/auth?response_type=code&redirect_uri=encodedURLFor`auth/callback`&client_id=my-clientId

But there's no redirect_to parameter. Is there any way this can be done?

christopher-francisco avatar Feb 08 '18 17:02 christopher-francisco

Here is my solution, achieved with subclassing

class MyStrategy extends OauthStrategy {
  authenticate(req: Request, options) {
    // tslint:disable-next-line:no-string-literal
    const callbackURL = options.callbackURL || this['_callbackURL']
    options.callbackURL = addReturnTo(req, callbackURL)
    return super.authenticate(req, options)
  }
}

itajaja avatar Mar 28 '18 00:03 itajaja

To have a dynamic redirectUri via the options I had to change the following in strategy.js

if (callbackURL) { params.redirect_uri = callbackURL; }

to

if (options.redirectUri) {
  params.redirect_uri = options.redirectUri;
} else if (callbackURL) {
  params.redirect_uri = callbackURL;
}

and pass in the redirectUri with query parameters in the passport.authenticate() call, which I was doing anyways.

If it's worth making a pr I'd be happy to

alkerway avatar Jun 26 '18 16:06 alkerway

I've been looking for a solution for this for a month. I was trying to use the passReqToCallback option but it wasn't working.

dgolant avatar Jul 08 '18 15:07 dgolant

@dgolant you can use state. here is how I do:

app.get(`/auth`, (req, res, next) => {
      const { returnTo } = req.query
      const state = returnTo
        ? new Buffer(JSON.stringify({ returnTo })).toString('base64')
        : undefined

      const authenticator = passport.authenticate('google', { scope: [], state })

      authenticator(req, res, next)
    })
    app.get(
      `/auth/callback`,
      passport.authenticate('google', { failureRedirect: '/-/login' }),
      (req, res) => {
        try {
          const { state } = req.query
          const { returnTo } = JSON.parse(new Buffer(state, 'base64').toString())
          if (typeof returnTo === 'string' && returnTo.startsWith('/')) {
            return res.redirect(returnTo)
          }
        } catch {
          // just redirect normally below
        }
        res.redirect('/')
      },
    )

itajaja avatar Jul 09 '18 16:07 itajaja

@itajaja provided an awesome solution. i just wanted to mention that the new Buffer() constructor is deprecated, so instead you should use Buffer.from().

aoberoi avatar Sep 18 '18 23:09 aoberoi

@itajaja , Do I need to enable sessions (express-session) in your solution? Because every time i try to access state in the callback i get undefined.

albertonzn avatar Oct 25 '20 19:10 albertonzn

@albertonzn as far as I recall, you don't. there must be some other minor issue going on on your side

itajaja avatar Oct 26 '20 07:10 itajaja

@itajaja , thanks for you reply. It was a minor bug on my side. Everything is working now.

albertonzn avatar Oct 26 '20 12:10 albertonzn

Is there any update on this issue to keep query params from initial request? Cause so far all proposed solutions are work around. What is the reason to remove the query params from the request?

apiel avatar Nov 16 '21 09:11 apiel