not receiving "Refresh Token" even in the first consent - Google API - oauth-2.0

I'm being redirected to the Google Consent for the first time and asked if I allow this application to manage Gmail account and stuff. And when I'm redirected back, refresh token is null.
+token:"ya29.Gls1BTQIRIuCW2dnzIpQlciOZNpidhjfsoidjfsomethingsm"
+refreshToken: null
+expiresIn: 3600
I know Refresh Token comes null on subsequent requests. But this was the first request I made.
Is there something I need to do on the console side.

Solved it. I forgot to set access_type to offline
$client->setAccessType('offline');
In my case I was using Larave/Socialite
Socialite::driver('google')->with(['access_type'=>'offline'])->redirect();
Ref: https://developers.google.com/identity/protocols/OAuth2WebServer

Related

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

Satellizer Twitter (oAuth 1.0a) popup does not close

I'm having a good time with Satellizer, except in one case - the Twitter oAuth 1.0a flow. The popup does not close after successfully authenticating a user.
My configuration is;
$authProvider.twitter({
url: '<my server endpoint to get request token (POST)>',
redirectUri: '<my server endpoint to perform oAuth login (GET)>'
});
I have set the callback URI for my Twitter app to be the same as redirectUri (and I also pass it when getting a request token from Twitter).
The flow that I see is this (basically, I get to Step 10 in the oAuth 1.0 flow and then the popup does not close):
User clicks the "Sign in with Twitter" button
The popup appears and an empty POST call is made - my server returns the request token
The user clicks "Authorize Application"
My server receives a GET request for the oAuth login (not a POST as the documentation says I should)
My server correctly authenticates and returns the Bearer token.
And then nothing - it all stops. I suspect because I am responding to a GET not a POST but I can't figure out what is causing the GET.
Any help would be greatly appreciated!
Ben
Apologies everyone - this is my fault. Per my comment above, once I set the redirectUri properly and used just the /auth/provider method it all worked.
Quite simply, on the second call the parameters come through (correctly) in the body. Once I realised that, extracted them, authenticated, and then returned, it all worked like a charm.

Myob - AccountRight Live Api v2 Skip login screen

I am using accountright Live api v2 by MYOB. I want to get access token without going to login screen. When I send a CURL request to obtain access token i am redirected to myob login screen, how to skip that? The request I am sending is to url:
'https://secure.myob.com/oauth2/v2/authorize'
and params sent are:
Array
(
[client_id] => xxxxxxxxxxxxxxxxxxxxxxxx
[client_secret] => xxxxxxxxxxxxxxxxxxxxx
[scope] => CompanyFile
[code] => XXXXXXXXXXXXXX
[redirect_uri] => http://myappcodeonmydomain.com
[grant_type] => authorization_code
)
After your initial request to the API to get the access token, you should also be provided with a refresh token. Access tokens expire after a period of time, and need to be refreshed.
From the Refreshing an Access Token section in the Authentication Documentation:
Access tokens have a limited life span and when you receive one you'll
also receive an Expiry Time for it and a Refresh Token. Once your
access token expires it can no longer be used to access the API. So
you'll need to trigger a refresh. You do this by POSTing the following
parameters:
'client_id' // your API Key
'client_secret' // your API Secret
'refresh_token' // your refresh token
'grant_type' // this should say refresh_token
To this url: https://secure.myob.com/oauth2/v1/authorize
Note: while the data is formatted into a URL Query String you do not
pass the information via the URL (that would be a GET request), you
must pass the query string in the body and POST this to
https://secure.myob.com/oauth2/v1/authorize
As an example, I store my access and refresh tokens in a database, along with an expected expiry time 10 minutes in the future. If a request is going to be made after that time, I call the refresh procedure to update the access token, and am able to proceed on my merry way without needing to show the login prompt each time.
You do need to have it shown at least once to find out which user is logging in, and the GUID of the Company File to connect to.
If you are talking about the first time auth, then there is no way to do it. You have to redirect the user to the login page by returning the url.
If you are talking about refresh the token, then it's easy.
I'm not sure how you implement the API connection. I'm using the myob ruby sdk.
The ruby sdk is so easy to use and it will do all those auth operations for you.
:)

The access token acquired won't update the scopes value

I'm using this site https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx to do Authorization Code Grant Flow with the goal of reading my office 365 calendars using this type of flow. The problem is that when I request for an oauth token the response is not updating the "scope" variable. I'm requesting the oauth token using this POST call "https://login.microsoftonline.com/common/oauth2/token" and passing in the body my grant_type, redirect_uri, client_id, client_secret, code, resource. The response is 200OK but for scope it only reads -> "'scope': 'Contacts.Read'" when it should also have Calendars.Read as well. In manage.windowsazure.com for the app that has the same client_id I'm passing in has the read calendars checked as well as the read contacts checked. When I first got my authorization code by typing this into the browser "login.microsoftonline.com/common/oauth2/authorize" I only had "Contacts Read" checked. But now every time I type that into my browser it skips the page where I accept my app to look at my calendars and contacts page. When I login with someone else's computer and get the auth code and request the token it updates their scope to both contacts and calendar and works fine. For me I'm getting a new Auth code in the url but it skips the page where I could accept my app to look at my contacts AND calendars. I'm getting a new authorization each time. I tried clearing my browsing data but It still wouldn't work.
You need the user to logon again so they can consent to the new scope. Try adding prompt=consent to your logon URL.
This works much nicer in the v2 app model, which does dynamic scopes.

Google OAuth access token expiration in MVC app?

I wrote an MVC app using Google Oauth2 as instructed here:
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web_applications
I have an issue with access token expiration. When access token expires, I get the exception when calling Google API: "The access token has expired but we can't refresh it"
The initial authentication is two iterations mechanism:
first iteration AuthorizeAsync returns result with empty Credential, and populated RedirectUri:
So, the authorization url created is this:
https://accounts.google.com/o/oauth2/auth?access_type=offline&response_type=code&client_id=MYCLIENTID&redirect_uri=http:%2F%2Flocalhost%2FHomepage%2FAuthCallback%2FIndexAsync&scope=https:%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar https:%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&state=http:%2F%2Flocalhost%2FHomepage%2F95419199
Note that access_type=offline is present. So I should get the refresh token back as well (doesn't happen).
second iteration - AuthorizeAsync returns result with populated Credential and empty RedirectUri:
Question1 - is RefreshToken supposed to be null at this moment?
The result is remembered, since it's defined as static.
Next request that comes in - the Calendar action that requires result.Credential to call Google Calendar API:
Question2 - if access token expires by that moment (for testing I just set ExpiresInSeconds = 0), I call RefreshTokenAsync method, but it always returns false! Why? What am I missing here?
And what would be the right way to handle when RefreshTokenAsync returns false?
Current RedirectResult(result.RedirectUri) command will fail since result.RedirectUri is null.
Oh, I finally got it :)
For those who interested - refresh token is only issued once, when you get that Consent screen, where you have to click Yes.
So, in order to get refresh token, go to your account setting, Account Permissions: https://security.google.com/settings/security/permissions
and revoke access for the project you configured in Google Developers Console: https://console.developers.google.com/project
Now, put a breakpoint on the next line after you call AuthorizeAsync, restart your application in Debug mode, get that consent screen asking for permissions, click Accept.
The app will return to VS and will stop on your break point.
Now, record somewhere the result.Credential.Token.RefreshToken value, it's an encrypted string.
I placed my in web.config appsetting for simplicity.
Now, I just assign that value back to result.Credential.Token.RefreshToken = refreshToken;
and every time, when access token expires, it will automatically refresh it.
Like here when I call GmailService request.Execute(...) passing the credential object that contains the token, the token will be refreshed.

Resources