0

I am using Azure's MobileServiceClient sdk to authenticate with my server. With the upgrades to 4.x version I am also using Xamarin.Auth to authenticate users with Google and Facebook. When the response comes back from Google I am getting a refresh token. I then call the mobile service sdk like so:

   var accessToken = account.Properties["access_token"];
                var idToken = account.Properties["id_token"];

                var zumoPayload = new JObject();
                zumoPayload["access_token"] = accessToken;
                zumoPayload["id_token"] = idToken;

                var user = await client.LoginAsync(MobileServiceAuthenticationProvider.Google, zumoPayload, );

This work perfectly fine. What does not work is the call to client.RefreshUserAsync(). That is throwing a 403 every time saying the refresh token is either expired or no longer valid even when I call that method right after I logged in. I do not see many examples at all using the MobileServiceClient 4.x sdk and none of them have examples of how to use the refresh token.

I have tried sending that upin the zumo payload as well but it does not work. I have tried invalidating my user on Google (I am getting the refresh token back), tried logging in through the browser and going to auth/me but the refresh token is not there. Any help would be great!

rleffler
  • 430
  • 6
  • 15

1 Answers1

1

AFAIK, you could leverage the Xamarin.Auth SDK to independently contact the identity provider and retrieve the access token on your mobile client side, then you need to login with your backend (azure mobile app) along with the token for retrieving the authenticationToken, then you could leverage the authenticationToken to access the resources under your mobile app.

Since you are using Client-managed authentication, for refreshing the new access_token, you need to do it on your mobile client side. I checked Xamarin.Auth and found that there is no method for requesting an access token. You need to refer to Refreshing an access token and implement this feature by yourself. I followed OAuth2Authenticator.cs and created a extension method for requesting an access token as follows:

public static class OAuth2AuthenticatorExtensions
{
    public static Task RefreshAccessTokenAsync(this OAuth2Authenticator authenticator, Account account)
    {
        var dics = new Dictionary<string, string>
        {
            {"refresh_token",account.Properties["refresh_token"]},
            {"client_id", authenticator.ClientId},
            {"grant_type", "refresh_token"}
        };
        if (!string.IsNullOrEmpty(authenticator.ClientSecret))
        {
            dics["client_secret"] = authenticator.ClientSecret;
        }
        return authenticator.RequestAccessTokenAsync(dics).ContinueWith(task =>
        {
            if (task.IsFaulted)
            {
                //todo:
            }
            else
            {
                authenticator.OnRetrievedAccountProperties(task.Result);
            }
        });
    }
}

Additionally, if you leverage Server-managed authentication with Microsoft.Azure.Mobile.Client, then you could leverage RefreshUserAsync for refreshing the access token, at this point your previous access_token, clientId are stored on azure, and your mobile app backend would directly communicate with Google's OAuth 2.0 endpoint and request a new access token for you and update the token store on Azure. For more details about token store within App Service, you could follow here.

Bruce Chen
  • 18,207
  • 2
  • 21
  • 35
  • thanks for the help. Two questions: 1) Does that mean I can use that access token to login behind the scenes for a new auth token? 2) RefreshUserAsync() only works for server managed auth? Thanks! – rleffler Sep 06 '17 at 19:45
  • For question 1, you could use the new access token for updating the logged userinfo behind your mobile backend and retrieve the new authenticationToken. For question 2, in order to request an new access token, you need to provide the `refresh_token`, the refresh_token was stored on your mobile client side when using client managed auth, and when call "/.auth/me" you could see the mobile backend only return the access_token not the refresh_token for client managed auth. – Bruce Chen Sep 07 '17 at 02:02
  • How do I provide the refresh_token? I have added that to the zumoPayload but it does nothing. I tried logging in via browser with /.auth/login/google?access_type=offline_access and that saves the refresh token and RefreshUserAsync() works. It seems to me that the 4.x Library is just missing an overload for params to add to the query string for offline access? – rleffler Sep 08 '17 at 02:39
  • AFAIK, the SDK supports `LoginAsync(this IMobileServiceClient client, string provider, IDictionary parameters)` and this method uses the server-flow. I did not find any extension methods for login with token object along with extra parameters that are sent as query string parameters to login endpoint. – Bruce Chen Sep 08 '17 at 03:17
  • Per my understanding, since you are using client-flow and you directly communicate with your provider, and the refresh token and refresh token are received by your client side, you could modify your `zumoPayload` object and try to add a new property `refresh_token` for login, then access `/.auth/me` to check whether your access_token has been stored on app service token store . Otherwise, I assumed that the processing for refreshing an access token need to be done on your client side. – Bruce Chen Sep 08 '17 at 03:20
  • Yes it looks like they must be done on the client side currently. I added refresh_token to the zumoPayload object and it did not update. – rleffler Sep 08 '17 at 03:36