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

Optionally avoid parsing callbackURL #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dbitting
Copy link

@dbitting dbitting commented Jun 6, 2013

Certain Google+ OAuth flows make use of a callbackURL of postmessage, which is really just a string token. It should not be treated as a URL. This change introduces a new config property that can be included in the call to authenticate: parseCallbackURL. If this is present and has a value of false, then the value of callbackURL will be included AS IS into the OAuth request.

Usage looks something like this:

    passport.authenticate('google', 
        { callbackURL: 'postmessage',
          parseCallbackURL: false }),

Please review/incorporate as desired.

Thanks,
--Doug

…se should not be parsed as if they were actual URLs. This change provides a way to avoid the URL parsing by checking for a "parseCallbackURL" configuration option. By default this option is true, which maintains backward compatibility.
@jaredhanson
Copy link
Owner

Can you point me to some documentation on this so I can understand it better?

@dbitting
Copy link
Author

dbitting commented Jun 6, 2013

This specifically supports the Google+ signin where you will be passing the one-time code from client to web server. See here: https://developers.google.com/+/web/signin/server-side-flow#step_4_add_the_sign-in_button_to_your_page

I'm beginning to wonder if there doesn't need to be a separate strategy for Google+ signin: while the existing profile retrieval works, the recommended API endpoint for Google+ signin is different, and returns a slightly different data structure.

Of course, this is all pretty new to me, so I'm feeling my way around these things. :)

@jaredhanson
Copy link
Owner

Thanks, that is interesting. I'm going to investigate this some more, and experiment with handling some of the flow on the client.

At first read, if you are doing the client-side flow, those shouldn't actually be redirecting to a new location, and thus the server would never see this value. If you are mixing client and server-side flows, I'd recommend using different callback URLs for them.

@jaredhanson
Copy link
Owner

After investigating this further, the postmessage flow that Google supports is entire a client-side. If you use this flow, the browser won't be redirected to your servers callback URL. Rather, client-side JavaScript is used to intercept the token.

I'm closing this down. If I'm overlooking any server-side involvement in this flow, I'd tend to think it should be a separate strategy.

@jaredhanson jaredhanson closed this Aug 2, 2013
@dbitting
Copy link
Author

dbitting commented Aug 4, 2013

I may be misunderstanding what you mean by "entire[ly] client-side." In my flow, the browser initiates the OAuth flow via the G+ APIs and a callbackURL of postmessage. The browser receives back a one-time code that is passed to the server, like so:

Client:
$http.get('/auth/google/callback', { params : { code : authResult.code } })

Server:

   var GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;
...
        passport.use(new GoogleStrategy({
            clientID: ...,
            clientSecret: ...,
            callbackURL: "postmessage"
...
        app.get('/auth/google/callback', 
            passport.authenticate('google', { failureRedirect: 'http://...', parseCallbackURL: false }),
...

This code presumes the presence of my change so that postmessage isn't parsed, but assumed just to be a string token to be passed along. After this, the server can now interact with G+ to the extent allowed by the scope(s) indicated via the original client request.

Perhaps that better illustrates what's going on and helps determine if a separate strategy is warranted.

@jaredhanson
Copy link
Owner

I'm not 100% sure on all the ways to use this, but this was my impression:

If you want to initiate this "postmessage" flow (which typically uses a popup window), you start that process via JavaScript on the client side. Since "postmessage" isn't a URL, Google will never redirect back to it. Rather, they load a page that uses cross-document messaging to pass a token (and possible code) to the parent window (the one that opened the popup).

Because there's no server involved here anywhere, there's no reason to add special handling for this case to this strategy.

Now, I agree that you may want to post the code to the server. However, I don't think you should be posting that to the callback route, since that is intended for redirect-based flows, which this is not. Rather, post it to some API endpoint that handles things however your app requires.

I may be missing something here though. What happens in your "callback" route after you post to it via ajax? Most of these routes will typically end up establishing a session and redirecting. But, presumably, none of that is needed if you are just doing Ajax requests after a login popup.

@dbitting
Copy link
Author

dbitting commented Aug 4, 2013

Your assessment seems about right. In my case, I'm not redirecting. I'm establishing a passport session, performing a bit of user-specific processing making use of the G+ session afforded by the one-time code (i.e., the server is interacting with G+), and returning some information back to the client based on that processing. It's entirely possible that I'm using the wrong tool for the job. :)

@jaredhanson
Copy link
Owner

Don't get me wrong, I think its great that your using this!

What I'm not clear on, though, is why callbackURL: 'postmessage' needs to be set as an option in this case? Couldn't you just set it to a normal URL, knowing that it'll never actually be redirected to?

Also, what interaction do you do with G+ on the server in this case? I'm assuming its the typical "exchange" portion of the OAuth flow, ie, submit the code and get a token? When you do this, does the redirect_uri parameter need to be set to "postmessage"? What if it is just a "dummy" URL?

Thanks for answering my questions!

@dbitting
Copy link
Author

dbitting commented Aug 4, 2013

My recollection is that postmessage is required on both the client and the server side of this flow, or it fails to work. It would appear to be significant to Google.

The interaction between the server and G+ is illustrated above; it's completely controlled by passport and makes use of the code from the client side. Beyond that, in the callback provided to passport, I'm simply retrieving some user details (user id, email, etc.) for use within the server.

@jaredhanson
Copy link
Owner

OK, thanks for the info. Re-opening as a reminder for myself to revisit this.

@jaredhanson jaredhanson reopened this Aug 5, 2013
@losttime
Copy link

I would benefit from this change as well. I'll start working on a pull request when I get a chance.

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

Successfully merging this pull request may close these issues.

4 participants