Not getting refresh token with google oauth2 - oauth-2.0

I have the set the scope to 'https://mail.google.com/' and the extra params like 'access-type=offline' and 'approval-prompt=force' are also set.
After the process is complete, I'm not getting the refresh token. I only get the access_token, expires_in and token_type fields.
I even revoked the access to the app from the account I used to test and tried multiple times. Still got the same result.

The syntax of the parameters must use underscores as a separator instead of the hyphens you use, so use access_type=offline and approval_prompt=force.
Note that you'll only get a refresh token on the first attempt to connect an application or after revoking access as you already seem to suggest.

Related

Using nodemailer & Google OAuth to send email, working for 7 days, but get invalid grant

I've been working to setup Oauth communication for an auto-emailing node.js web app using nodemailer. (I don't wish to use gmail's Less Secure Apps setting).
I've taken steps to get the client id, secret, and refresh token from the oauth playground, and have set up the web app to use a stored refresh token to request new access tokens when it first loads.
It is able to send emails (for about 7 days), then I get error invalid status code 400 on client side, and/or invalid grant on server side.
Going back to google playground and getting another refresh token, then updating it in environment variables, solves this for another week. But I'd like to solve this indefinitely.
I read somewhere "A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of 'Testing' is issued a refresh token expiring in 7 days"... so last week I switched the app to "In Production" (at console.cloud.google.com) and tried having it verified with google. This week, the same issue has recurred suggesting that wasn't the right fix, or that it wasn't yet verified with google.
I don't know if this was done correctly, nor do I know if this is the true solution to this expiring/revoked refresh token, or invalid grant.
I've also come across these explanations:
The user has revoked your app's access.
The refresh token has not been used for six months.
The user changed passwords and the refresh token contains Gmail scopes.
The user account has exceeded a maximum number of granted (live) refresh tokens.
The client has reached a limit of 50 refresh tokens per account if it's not a service account.
(I didn't make ANY changes during the week, so...not sure why these would have changed)
Is the issue the refresh token?
Or the status of the application?
Would it be dns/cname/cloudflare server issues?
For those who have the same issue in the future:
It turned out that google verification wasn't necessary.
It seems like the refresh token expiring after a week or 7 days was due to the placement of the oauth2Client.setCredentials() function call and accessToken variable.
Calling setCredentials() and obtaining the access token INSIDE the SendEmail() function (at runtime, just before sending email, rather than at application start/spinup time) seemed like it enabled the code to more dynamically generate the tokens it needed. After 12 days, it still seems like its working so I'd call this a success.
My guess at why it wasn't working before was because setting credentials outside of a function meant that code only ran once on server/application startup. It would then store the obtained access token in a const.
The access token would eventually expire, and even if called again/later inside of a function to obtain a new access token, it would be unable to change the value of a const property/variable, and so the call would inevitably fail after a week when it failed to renew.
Hope this helps anyone else having a similar issue.
My apologies for the run-on sentences.
There are a lot of causes for invalid grant it sounds to me like your refresh token is expiring.
If your project on google developer console is still in testing, has not been moved to published and has not gone though the google application verification process then refresh tokens have a max two week life span after which they will expire which may explain your invalid grant. The thing is there is no official word from google that this is happening its just what a lot of developers are seeing these days.
Another one is with gmail scopes if the user changes their password this will also cause the refresh token to expire.

Sign In With Apple refresh token validation only access token returned

I'm using the AppleAuth npm package in my server to submit token requests to Apple's servers during the sign in with Apple process. (This is based off the sample server code provided with the sign_in_with_apple package in pub.dev) I have no issues submitting the authorization code to get my first access and refresh tokens.
However, when trying to test how my app would get a new refresh token, when I submit a POST request to https://appleid.apple.com/auth/token with the grant_type set to refresh_token the response I get is different than from having the grant_type set to authorization_code.
I looked at the source code of the package, and for its AppleAuth(myConfig).refreshToken(myRefreshToken) (<- pseudo code lol) the only difference in the POST payload is:
{
grant_type: 'refresh_token', // instead of grant_type: 'authorization_code'
refresh_token: refreshToken, // instead of code: authorizationCode
... // other params
}
While the initial request with authorization code returns both an access token and a refresh token, for some reason the refresh token request is only returning the access token. I really don't think it's the package causing the error, nor can I see how my code would be the source either, since the above code is the only difference.
I tried passing the access token that it returns in a new refresh token request in order to test that I can get new refresh tokens whenever necessary in the future, but it returns a 400 status error.
Am I missing something here? Is there a reason the refresh token request returns no new refresh token? Or am I missing something entirely about how the process/flow is supposed to work? I am trying to do this for the "check the refresh token once daily to confirm the user is still in good standing with Apple's servers" part of the process.
I've really been stuck on what to do at this point. I can save the identity_token.sub field in my database to check whether my user is signed in, but of course I want to make sure my user's apple ID is still valid with apple, and that they haven't revoked access. Could it be that because I tried to get a new refresh_token too soon Apple only returned the access_token?
Oh also, the app itself is a Flutter app and I am testing all of this on my iPhone 11 so it's not an Android/Web flow.
Whether you get a new 'rolling / rotating' refresh token in a refresh token grant response is generally vendor specific:
You may get a new refresh token occasionally but not always
The primary purpose of this message is to get a new access token, not a new refresh token
In terms of token handling, the client should update its tokens similarly to the saveTokens method in this sample of mine.
I've not used Sign In with Apple but I suspect proceeding as follows would be the simplest solution:
Keep access tokens short lived: no more than 60 minutes
This forces a frequent token refresh, which by default is very quick
If the user's Apple Id is revoked I would expect this to return an invalid_grant response

oauthplayground invalid grant, trying to get refresh token google oauth

I got the temporary access token, serverAuthCode, web client id and its secret, i am trying to get refresh token from oathplayground but i am getting invalid grant error. I have rechecked the tokens many times but still getting same error. Here are the screenshots :
What can i do to get the refresh tokens ? For more information, i am using react-native-google-sign-in library, from this library, i got the 1. access_token, ServerAuthCode. From Google Developers console, i got the 1.Web Client Id 2.Client Secret , I am using these credentials inside the react native app and i am getting the tokens successfully, but the problem is sometimes they work and most of the times i get "invalid credentials" error when i try to use the access token, it is because the access token is expired, that's why i need the refresh token. If you have any idea why i am not able to get refresh token or how to get refresh token using another method, please let me know.
I understood what i was doing wrong, i was using the serverAuthCode that was not new, it should be the latest one + the first time when you allowed the app for permissions, and it will work only first time, after you have exchanged it for a refresh token, it will not work again and will always give you grant_error. So after getting the refresh token you can get a new refreshed access token. I was using react-native-google-sign-in and was in need of refreshed token, read below to know more about the same.
For React-native-google-sign-in :
The access token you will receive from GoogleSignin.getTokens(); will only last for about an hour, to get a new access_token we need to send serverAuthCode to https://oauth2.googleapis.com/token with fields : client_id, client_secret, code(this is serverAuthCode), grant_type(its value should be authorization_code), redirect_uri(can set it from developers console). Remember to only use the serverAuthCode that you get on your first attempt when you just allowed your app for the permissions FIRST TIME otherwise you will get grant_error every time. After getting the refresh_token, we need to get the new access_token using refresh token that we just got, so now just replace the value of grant_type from authorization_code to refresh_token and also replace the value of code field to refresh_token , fill its value and send a post request to the same url, you will get a fresh access_tokenthat will be valid for 1 hour.

Google OAuth's access token's expiry timezone

I recently switched to the Google+ Sign in OAuth2 hybrid approach.
When the request code is exchanged for the access token, the expiry time and created time is sent back along with the access token in seconds.
I need to know the sent timezone is. I need this to make comparison with my server's time and be able to deduce if access token has actually expired.
What's the timezone or how do I determine it?
The token bundle sent back does not include an actual expiration time, but it does contain the number of seconds for the expected life of the token. If a time is being attached to it, it is being attached by the local library.
That said - you can't necessarily trust this number. There are a number of reasons why the token may have been revoked or is treated as no longer valid. So while you can use it as an estimate of when you'll need to get a new one - you should also handle the case where you use a token and you get an authentication error, forcing you to refresh the token and try again.
My bad.
I just went through the Google PHP APi client library. Only to realize the created field was set within the library (on my server) in Google_Auth_OAuth2's authenticate method.
So it is safe to use $client->isAccessTokenExpired() instead to try to do one's computation. Works with local time (I guess :))
Thank you.

Revoking OAuth Access Token Results in 404 Not Found

I'm working on an application that integrates with GitHub and am having issues "logging out" a user that was previously authenticated. When I attempt to revoke the authorization token for the user, I get a 404 Not Found response from the API.
According to the documentation, it looks like I should just be able to make a DELETE request to https://api.github.com/authorizations/[authTokenId]. I have tried a couple of different things including:
Ensuring the Authorization header is set with the current auth token
Ensuring the UserAgent header is set with what I use for the rest of the API calls
Nothing seems to result in anything but a 404 though. I have validated that the token is valid and has that the Id matches with what is expected (id property from the authorization response and from the "check an authorization" response as well). Anyone have another thought on something I could be missing?
Looks like currently you need to include a basic authentication header (including a base64 encoded string of your username/password).
Not ideal for my purposes since I want to revoke the token when a user "logs out" of my application and I don't want to store their username/password. I've sent GitHub support an email about it to see if they have any other ideas.
Update 6/12/2013
GitHub support has stated that the above is expected at this juncture, but they are considering updating to allow revoking an authorization using the authorization as the means of authentication.
For now I'm going to require the user to enter their username/password a second time to revoke the authorization.

Resources