1

I'm upgrading accounts to use the new plus.login scope, so I tested adding a user with just userinfo scope and then re-logging in with plus.login added. The result was that a new entry in the authorized access panel was introduced, and the access token returned from the latter call only had userinfo permission. I tested this by making a verified token call as well as trying to list people.

Is this expected behaviour, and if so, should I be revoking the old token beforehand? I see it's possible with a /revoke action. Server side removal of Oauth token

Update: Relevant Gist. This is using Ruby's Omniauth gem. I'm not actually sure how a user can ever see more than 1 entry in the authorized access panel, yet in this circumstance I could see 2. And after testing various scenarios yesterday, I had about 6 entries all belonging to the same app! Note that I didn't change the client ID at any time and in fact only have one client ID.

I'm hoping the situation I described can be replicated by others; it's simply a matter of hacking the Google-side URL to remove the plus.login scope, and then logging in again while preserving the URL as is.

Update (2): I also discovered this gotcha: "You should not request userinfo.profile or plus.me in combination with this scope as they are implicitly included and would create a confusing permissions dialog for your user." In fact, it's more than just a UX permissions issue; it seems Google won't actually store the "plus.me" scope against the user, so it means it will always show the OAuth permissions dialog even if users have already given permissions (I think because it does a simple equality check and notices plus.me is requested, but is not stored against the user).

Update (3): The bug about using the wrong login was caused by my code doing something like user.login || user.signup without updating the token data on a login. So now it updates the access token and the refresh token after every login. (I still don't follow why there needs to be more than one token per client-user combo.)

Community
  • 1
  • 1
mahemoff
  • 44,526
  • 36
  • 160
  • 222

2 Answers2

3

Perhaps you aren't revoking the token for your previously authenticated client before issuing a new one?

You can test that revoking after upgrading a scope works with the following JavaScript demos:

  1. Authorize using this page. (Don't disconnect the authorized client)
  2. Upgrade your authorization using this page, which includes the calendar scope as an example and which has the same client.
  3. Now, if you look in your issued authorizations subtokens page, you will notice that there are two entries corresponding to each client.
  4. Revoke from the second page by refreshing and clicking the disconnect button.
  5. Return to your issued authorizations subtokens page. Both sets of issued authorized subtokens now are gone.

I tested this further and made changes to the project, adding the drive scope. After adding the scope to the API client project and authorizing an additional client, revoking any of the tokens will revoke all of the authorized clients from that project.

If you are upgrading existing authorized credentials from another client, the older token should be revoked at the time you upgrade your existing token to avoid having instances of credentials that don't work as expected.

However, as you can see from the demo, revoking tokens from the same API client will revoke additionally issued auth tokens so you do not need to worry about revoking previously issued tokens.

The best reason for revoking older tokens (e.g. your refresh token with the userinfo.email scope) is that you could later be trying to make an API call for a new scope using that token, even though that token hasn't been upgraded to include the additional scopes and could introduce strange bugs.

A final note: hopefully users will become more used to looking at their issued authorization tokens from the Manage apps page on Google+ which does a better job of de-duplicating instances of connected applications.

class
  • 8,621
  • 29
  • 30
  • Thanks, this demo basically replicates most of what I was confused about, ie there being a second entry as I thought the upgrade would simply overwrite it, but I see it's expected behaviour. (Though I'm still not sure why the wrong token was coming back; I'll re-test that.) I still have the same practical question about what's the best practice for upgrading existing tokens, as I would ideally want just the one token (even if I can accurately make calls with the right token each time, it's unnecessary). So I guess my server should revoke "all other tokens" when the upgraded token comes back? – mahemoff Mar 15 '13 at 15:36
  • Additional notes added to the answer because I ran out of space in the comment. – class Mar 15 '13 at 15:42
  • Thanks, that's very useful to confirm the others should be revoked. So it sounds like you're suggesting that when user clicks login button, my server should first attempt to revoke any existing token and only request the new one when it receives a successful response from Google's server. In other words, a server-to-server round trip takes place between the user's request and the app's server's redirect-to-Google response. – mahemoff Mar 15 '13 at 15:57
  • "the others should be revoked" This is for old clients only and should be done to avoid having refresh tokens that don't behave how you expect. However, revoking a token from the same client (e.g. you add a service to the APIs console to update your requested scopes and your clientid/secret stay the same) after getting an additional token will revoke your new token as shown in the demo. – class Mar 15 '13 at 16:34
  • Thanks for these details, I also asked a follow-up question about the Manage apps page. http://stackoverflow.com/questions/15444692/removing-applications-from-google-manage-apps-page – mahemoff Mar 16 '13 at 01:49
2

That does not sound like the right behavior. Can you get the access token from the later call and plug it into https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=TOKEN_GOES_HERE - that will show the scopes that it is authorised for.

Which platform were you implementing on as well? If you have a snippet that might help!

Update: Tried adding plus.login after authenticating previously, and I got a new consent dialogue, so it all looked pretty smooth there. May be a client specific issue?

Ian Barber
  • 19,765
  • 3
  • 58
  • 58
  • I did check the token; that's what I meant by verifying and it came back with the original scope that was requested (without plus.login). Added a Gist link with the code as requested. – mahemoff Mar 15 '13 at 12:32
  • With the update, what happened after that? Did you see 2 entries in the access panel (https://t.co/BIv3RN67MK), and what scope comes back when you all /tokeninfo. – mahemoff Mar 15 '13 at 12:33