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.)
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:
Authorize using this page. (Don't disconnect the authorized client)
Upgrade your authorization using this page, which includes the calendar scope as an example and which has the same client.
Now, if you look in your issued authorizations subtokens page, you will notice that there are two entries corresponding to each client.
Revoke from the second page by refreshing and clicking the disconnect button.
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.
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?
Related
We are wondering someone could answer the following question about the deprecation of scopes. Currently during the OAuth process for YouTube registration, we are asking for the following scopes (as well as offline access) using the https://accounts.google.com/o/oauth2/v2/auth endpoint :
youtube
plus.login
youtube.readonly
youtube.upload
youtubepartner
youtubepartner-channel-audit
youtube.force-ssl
With the announcement of the G+ deprecation, during the YouTube Oauth flow, we replaced :
plus.login
with :
userinfo.profile
Our questions are :
What is the expected behavior of our refresh tokens for refreshing access tokens offline for the existing accounts that have been OAuth-ed before we made the above scope change ? Do we expect these to fail on March 7, or would they continue to be able to refresh and just have no access to any endpoints that required the scope ? We want to make sure we understand what information we need to relay to customers about this change with respect to our current YouTube implementation.
What is the expected behavior of our refresh tokens for refreshing access tokens offline for the existing accounts that have been OAuth-ed before we made the above scope change?
If you make changes to your scopes then you should do a force prompt to request authorization of your users again. This way they will see userinfo.profile now and you will have new refresh tokens that you can use containing the correct consents.
Do we expect these to fail on March 7, or would they continue to be able to refresh and just have no access to any endpoints that required the scope?
Any refresh token you have now should continue to work just fine. However any requests that you make against anything that would have used plus.login will fail as you do not have access to that anymore.
Bearer token does not get invalidated. Even if a new bearer token is issued for the same user, the old token is still valid and can be used to access to API resources.
How can we restrict(or make a workaround) for this.
I have an angular application and my ASP.NET Web API also lives in the same domain and it uses Token based authentication which is very similar to the scaffold template boilerplate code from Visual Studio for Web API with Individual Authentication. Authentication is against Windows AD and slight changes are made for that in the GrantResourceOwnerCredentials of OAuthAuthorizationServerProvider implementation.
Issues, I believe, are:
1) A bearer token once generated does not get invalidated even if the credentials are changed.
2) A bearer token issued for a username will still be valid even if a new token for the same username is created. In this case, both the tokens are valid.
3) If anyone authorizes from one machine, the token can stay in that machine for a long period and hence any other user can use the site and automatically get authorized. There will be code written for clearing the token from angular code during log off. But, what if the user does not log off.
4) Giving a short life span for tokens makes sense. However this application is an internal application which is authenticated against Windows AD. So, the users would like the login to stay as it is and not log off and login again every half an hour of idle time or so.
What I would like to achieve is:
1) At the very least, ff a user is logged in, the access token previously generated for the same user needs to be invalid. We will need to have a DB table(maybe called UserToken) and manually store and check it for achieving this. If this is achieved, at the very least, a user logging in another machine will have the access token rejected once he logs in back to his original machine.
(User can login with any valid AD account as this project is having authentication type none and it is authenticated against the AD from a login form).
I am not sure what all other things should be considered.
Any thoughts/suggestions are welcome.
(I tried to look a bit at refresh tokens but since it is a client application, not sure where I can save the refresh token and use in an effective way.)
Check this How to limit user to only one access token in ASP.NET Identity
and regarding refresh token, you need to save it either in local storage or in cookies.
I am using Authorisation Code Flow in my web application. I would like to get a refresh token for the web app itself but also an offline token that I will save in the database so I can use it later on for an offline task.
However I am struggling with that. I cannot use grant-type password because I don’t want to ask the user again to enter his/her credentials and also authorisation code is only one-time use so I cannot integrate it with the current flow.
Is there any other way to generate an offline token from a different token? I have tried using grant type refresh-token with scope offline_access but that didn’t work.
After keep working with Keycloak for several months, the answer is simple: it is not possible.
Offline token is effectively a refresh token with no expiration time so you can get one or the other but never both as part of the same request/response.
From a user point of view, we created a new page to request this token using password grant-type and offline scope. User need to re-enter his password but it seems ok from a security point of view. This approach works for us given the requirements to get this token as it is an unusual task.
You can also generate offline tokens using service account, check keycloak documentation on service account.
Following discussion will help you to understand different scenarios generating and using offline tokens
I've seen this issue in a lot of questions, but so far, none seem to apply to my situation.
The problem we are having is we are getting an "invalid_grant" error when we attempt to get an access token. This only happens to some accounts, but when it does happen, in every case I looked at, the refresh token worked before, and now has stopped working. This is happening far to frequently for it to be customers revoking access (seems to be nearly 20% of the channels we manage in the last couple weeks have been invalidated).
As a note, we have a backend process that uploads the videos to our customer's YouTube channels.
We use OAuth2 to get a refresh token, here are the parameters we send...
scope = "https://www.googleapis.com/auth/youtube",
client_id = "",
response_type = "code",
access_type = "offline",
approval_prompt = "force",
redirect_uri = "http://www.us.com/OAuth/YouTube"
NOTE: for client_id we use the email address that is in the Google API manager (or was, I just looked and it is no longer there). We used to use the client ID from this page, but that caused us problems as well. Did this change? Should we be using the client ID from this page now?
We exchange the code that is returned for a refresh and access token and store the refresh token in our database.
The backend process exchanges the refresh token for an access token and this is where we seem to be getting the "invalid_grant" error.
Guaranteed only a single access token for the channel is in use at any time (25 limit doesn't apply). We don't store the access token, we get a fresh one every time we process a channel.
Any ideas what might be happening? Something to look for? See note above about client ID. This might have something to do with it, but I'm hesitant to try it since using the "Client ID" from the API manager caused problems before.
Guaranteed only a single access token for the channel is in use at any time (25 limit doesn't apply). We don't store the access token, we get a fresh one every time we process a channel.
This statement is incorrect: Access tokens can be used as many times as you need while they are still good (for an hour).
Answer:
"invalid_grant" basically means that your refresh token no longer works. The only solution to the problem is to request access again and get a new one. The question should be why is it expiring in the first place.
Assuming that the user did not revoke access, and that the refresh token has been used to request a new access token within the last six months. This is probably an issue with it being over written.
When a user authenticates your application you are given a refresh token. This refresh token is associated to the client id of your application and the user who has just authenticated. If said user then authenticates your application again you will get another refresh token. Again this refresh token is associated to the user and your projects client id. Both of these refresh tokens will work. Your user can keep doing this up to 25 (Note I think the changed it recently to 50 but I haven't tested it with all APIs yet) once they have hit this magic number the first refresh token will expired and if you try and use it you will get an invalid grant.
The only solution is then to just request authentication again. It is important to always save the most recent refresh token that your user has granted your application. In the event (like me) you have an application that is stored on a number of servers all requiring authentication. Your going to have to tell them not to refresh it to many times or they will have to go back and reauthenticate the first one that they expired.
If this is happening with ALL of your requests. You can also check that you server is sync with (NTP) and that you are sending the payload of your request in the post field. Not attached to the authentication end point like a HTTP GET (been there done that).
Here are the possible reasons why a token stops working and becomes invalid:
The user has revoked access.
The token has not been used for six months.
The user changed passwords and the token contains Gmail scopes.
The user account has exceeded a certain number of token requests.
As you can see, it's not recommended that you request a fresh one every time you process a channel. As also mentioned in Token expiration:
If you need to authorize multiple programs, machines, or devices, one workaround is to limit the number of clients that you authorize per user account to 15 or 20. If you are a Google Apps admin, you can create additional admin users and use them to authorize some of the clients.
With regards to the use of client_ID, it is usually needed to call the sign-in API as mentioned in Creating a Google API Console project and client ID.
And lastly, this Google Groups discussion - OAuth 2.0 400 - error:invalid_grant and ideas? might also help.
Description:
I have a problem with the OAuth service "randomly" not returning the "expires" value.
The application uses Server-Side Authentication with simple WebRequests and Redirects (no SDKs) and is fully conform with the documentation.
We store the "expires" value in our own database and we use this information to prompt the user to re-authenticate when the accesstoken has expired (or will expire soon).
We do not automate or batch the renewal of accesstokens in any way. Accesstokens are only refreshed through the Server-Side authentication, ie the process is always user-initiated.
Now we have noticed that when we try to refresh some (but not all) of these expired tokens like this, the OAuth service does not return an expires value for step 4 even though the user reconfirms that he does indeed wishes to give us permission to access his facebook account. The accesstoken is returned just fine.
Other tokens do not face this problem. The problem seems to occur randomly but might be related to some users granting manage_pages permission and others not. This is however speculation and I currently cannot test this.
The problem can be "fixed" by the user manually going to his app settings and deleting our app from them. When the Server-Side authentication is performed next, the OAuth response contains the expires value as expected and so will any subsequent calls to authorize that user.
Questions:
What is or can be the cause for this (undocumented) behavior?
How can we fix the affected tokens?
How can we prevent this from happening?
Thank you in advance,
This is apparently a known bug. (See CBroe's comment)