Google API invalid_grant - bad request error - node.js

I'm trying to get access token by calling https://www.googleapis.com/oauth2/v4/token with
grant_type: 'refresh_token',
client_id: GOOGLE_OAUTH_CLIENT_ID,
client_secret: GOOGLE_OAUTH_CLIENT_SECRET,
refresh_token: refreshToken
I'm sure the clientId/secret are correct.
Since for some refresh tokens - I do get access token, for others I do get notification that the token is revoked, but in some cases I'm getting a
error: '400 - {"error":"invalid_grant","error_description":"Bad Request"}'
Since for some cases I do receive success/token revoked, I assume it eliminates NTP issue.
Any ideas what else could be wrong and where to look?

It may be that you have an invalid access token. This could be due to many causes,such as the user's account has been deactivated since the token was created or token being revoked or expired, Ensure that you are always using the newest refresh token.
Time is critical with regards to tokens, Ensure that you are in with Google NTP server. If necessary, sync your time with Google NTP. Also an incorrect/ incomplete refresh token will also result in an invalid grant. In order to request a refresh token you must first have requested offline access. Access tokens work for one hour, however it is a good idea to refresh them when there is five minutes left to avoid any issues with clock stew.
Requesting an access token every time you need to access the api may also result in invalid grant, for flooding the auth server. Google has made changes if a user changes their password refresh token that grants access to some scopes will be revoked. Here is a StackOverflow answer and a blog post that I found which explain some of the reasons this error can occur.
Also you may try changing from the https://www.googleapis.com/oauth2/v4/token URI to https://oauth2.googleapis.com/token. The previous URI should continue to work, but the later URI is the new default. See this github

Related

I've been working with the Google API. Sometimes my refresh token refreshes and other times it fails and causes a 'RefreshError.' Why? How to fix?

Error:
google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', {'error': 'invalid_grant', 'error_description': 'Token has been expired or revoked.'})
However, another app I use, with a different account, never runs into any issues. I use the same Python OAuth Quickstart for both.
Token has been expired or revoked.
Basically means just that either the user has revoked your access or google has. Users can remove your access directly in their google account when ever they want to.
Google expired tokens
If you are using a gmail scope, and the user changes their password. Your refresh token will probably be revoked.
If your app is still in testing and the refresh token is more then seven days old the users consent will be removed and the refresh tokens will be revoked.
If the refresh token has not been used in more then six months the refresh token will be revoked.
If the user authroizes you app you get a refresh token, if the do it again you get another refresh token. both will work. You can have up to 50 outstanding refresh tokens for a user. If you request again then the first one will be expired. Ensure you are always storing the most recent refresh token.
no matter what the cause your application should be configured in a way as to request authorization from them again if the refresh token has expired.

get access token with access token?

From what I understand so far about access token is that in Code flow, Client could get access token with either authorization code or refresh token.
But.. can it get new access token with access token it holds before the token's expired?
I read RFC6749(1.1 ~ 1.4, 4.1, 4.2, 5 sections only for the sake of time) and I couldn't find such that
"access token must get issued by only explicit resource owner's grant or refresh token"
So I've been thinking..
How about issuing access token with access token.
What's wrong with this?
I'm almost noob to OAuth and learned it with only internet so I might totally misunderstand something D:
please enlighten me.. thanks!
You cant use an access token to get a new access token. Access tokens are self contained bearer tokens which grant you access to some data. (denoted by scope) For security reasons access tokens have a limited life time. Once it has expired you can not longer use it.
Consider if someone with a malicious intent got a hold of your access token. They can then use this to access the data, but only for a limited amount of time. Once the access token expired they would no longer be able to access that data.
refreshing access
The first step of the auth process gives you an authorization code, this is a one time code extremely short lived probably five minutes and can only be used once. When you exchange this you will get an access token and a refresh token if you requested offline access.
Refresh tokens can be used to get a new access token. You can use it to get access at a later date without requesting access of the user again. To get a new access token though you need to have the client and i and client secret that were used to create the access token in the first place, and in some cases you need to have access to the server that the redirect uri is residing. This way if the same a malicious person got access to their refresh token they cant use it to get a new access token unless they have your , client id, client secrete and server access.
You may find this interesting Understanding oauth2 with curl
TLDR
To be able to revoke access. Refresh token is used for that.
Here is my understanding. Access token are not retained by the auth server that issued them. They are very large in size and there may be a great number of them in a general case, one per scope or a set of scopes. Refresh tokens are short opaque strings and are retained by the auth server. They can be invalidated by the auth server to revoke authentication if a user's system has been found compromised. If an attacker obtained access/refresh token and used them from a different IP, for example. In this case the auth server will set a flag against the retained refresh token and will not refresh an access token without re-authentication.

Can someone explain about the Time-outs and validation of Azure AD Application access and refresh_token(s)?

Can we use the same access token to request another app resource or validate Token. What happens after 3599 seconds to an access_token? can we still use it?
How many times we can use the same refresh token? (Is there any way to restrict to one time if possible)
How to check if the existing access_token and refresh_token were valid ones or not?
Please help.
PAVANSAI C
Can we use the same access token to request another app resource or validate Token. What happens after 3599 seconds to an access_token?
can we still use it?
When you acquire an access token, it is only meant to be used against certain resources (you specify them when you request a token). You can't use that token for any other resources. Generally an access token is valid for an hour (3600 seconds) but that's configurable at Azure AD level. Once this time period expires, you can't use that token anymore as using it will throw an error.
How many times we can use the same refresh token? (Is there any way to restrict to one time if possible)
Similar to access token, there's also an absolute expiration for refresh token (it is usually 14 days). When you use a refresh token to get a new access token, you also get a new refresh token. You should be using the new refresh token instead of an old one.
How to check if the existing access_token and refresh_token were valid ones or not?
A successful response to an access token request will include the number of seconds the returned access token is valid for (expires_in), as well as the time at which the access token will expire (expires_on). Use these to keep track of whether the access token is still valid or not.
Note: You should consider using client libraries such as MSAL, which will do this automatically. Your code only needs to ask for a new token token, and the library will take care of figuring out if the last token received is still valid, or if a new one is needed.
Another possibly way to test it is try to use the access_token/refresh_token in an operation and catch the exception. Try to parse the exception to figure out what's wrong with the token. For example, if an access token has expired and you use it you will get an error telling you exactly that. That would be an indication for you to get a new access token using the refresh token. (This approach relies on the resource provider (i.e. the API) to return a message that clearly indicates that the token is expired, which is not always the case.)

Google API invalid request after access token expires

This is the comment that led me to ask this question.
I've got a server side Node.js app, using googleapis package. Users log in with their Google accounts, and I store tokens in their session. The credentials I get are as follows
{ access_token: '<AN ACCESS TOKEN>',
token_type: 'Bearer',
id_token: '<A LONG ID TOKEN>',
expiry_date: <A TIMESTAMP> } // why do some places say there's an expires_in instead of this
There's no refresh_token because the users have already logged in for the first time and clicked accept, and I didn't store the refresh token (looks like I should've).
So, when the expiry_date is reached, if the user tries to make a request for us to save something to their google drive, I get an error message:
{ [Error: invalid_request] code: 400 } // ...no further details
My 2-part question:
I assume I'm getting that error message because the access_token in my OAuth client object is expired (because the call works fine before the token expires). Is this correct? Why is the error message not more detailed?
In the linked answer at the top, the solution is to force the accept prompt again, get the refresh token, and store it permanently, and use it to get a new access token when it expires. Why is this a better option than just checking if the token is expired, and having a user reauthenticate when we want to make a call to the API? Which is the "correct" way to ensure that my logged in users can always make the drive API call to save their documents?
Right, the 400 response is because of the expired access token. I'm not sure why Google doesn't give more detail, but it's common for services to use the 400 status code to indicate some kind of credentials problem. The definition of the status code indicates that it's a client issue.
Both approaches will work and they each have advantages and disadvantages. The client-side re-authentication method you're suggesting has the advantage of making the implementation simpler, since you don't have to store the refresh token and don't have to implement the refresh process. The downside is that forcing the user to re-authenticate every hour is less user-friendly. At the least they will be redirected away from your app, and they may have to explicitly log in or re-authorize as well. You'll just have to look at the trade-offs and pick what works best for your use case.

How to get a new Google oauth access token from refresh token in passportjs

there seems to be some conflicting advice on how to get an access token from a refresh token:
This SO answer says passportjs doesn't get involved with refreshing the access token and it should be done via cron job:
Refresh token in Passport.js
This SO answer says "No need for any cron jobs...when the user requests data from the API using an access token that has expired, this should trigger your framework to fail, renew, then retry."
OAuth 2.0 - When should an access token be renewed with refresh token?
What's the simplest way to ensure we're always giving Google a valid access token? Right now, we're just storing the refresh token in the database and never using it, which forces users through the "allow / deny permissions" flow every time their access token expires.
There are a few approaches. One is to just detect when the access token fails (with 401 I believe) and then refresh it and re-use it. However, most of the APIs that yield access tokens also tell you their expiry time, so you can just remember that and, when you’re about to use, if it’s less than say 10 min before expiry time, refresh then. If all else fails you could use the tokeninfo endpoint when you get a new access token, to find out its lifetime.

Resources