2
votes

I am trying to use Azure Active Directory to perform login functions on my uwp app. This happens successfully however I cannot get it to refresh the token when it expires and always receive the error "Refresh failed with a 403 Forbidden error. The refresh token was revoked or expired." and so I have to bring up the login window again. I am using the version 2.1.0 and the following code to authenticate:

private async Task<bool> AuthenticateAsync(bool forceRelogon = false)
    {
        //string message;
        bool success = false;

        // Use the PasswordVault to securely store and access credentials.
        PasswordVault vault = new PasswordVault();
        PasswordCredential credential = null;

        //Set the Auth provider
        MobileServiceAuthenticationProvider provider = MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory;
        MobileServiceUser user = null;

        try
        {
            // Try to get an existing credential from the vault.
            var credentials = vault.FindAllByResource(provider.ToString());
            credential = credentials.FirstOrDefault();
        }
        catch (Exception ex)
        {
            // When there is no matching resource an error occurs, which we ignore.
            Debug.WriteLine(ex);
        }

        if (credential != null && !forceRelogon)
        {
            // Create a user from the stored credentials.
            user = new MobileServiceUser(credential.UserName);
            credential.RetrievePassword();
            user.MobileServiceAuthenticationToken = credential.Password;

            // Set the user from the stored credentials.
            App.MobileService.CurrentUser = user;
            //message = string.Format($"Cached credentials for user - {user.UserId}");

            // Consider adding a check to determine if the token is 
            // expired, as shown in this post: http://aka.ms/jww5vp.
            if (RedemptionApp.ExtensionMethods.TokenExtension.IsTokenExpired(App.MobileService))
            {
                try
                {
                    await App.MobileService.RefreshUserAsync();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }
            }

            success = true;
        }
        else
        {
            try
            {
                // Login with the identity provider.
                user = await App.MobileService
                    .LoginAsync(provider);

                // Create and store the user credentials.
                if (credential != null)
                vault.Remove(credential);

                credential = new PasswordCredential(provider.ToString(),
                    user.UserId, user.MobileServiceAuthenticationToken);
                vault.Add(credential);

                success = true;
                //message = string.Format($"You are now logged in - {user.UserId}");
            }
            catch (MobileServiceInvalidOperationException)
            {
                //message = "You must log in. Login Required";
            }
        }

        //var dialog = new MessageDialog(message);
        //dialog.Commands.Add(new UICommand("OK"));
        //await dialog.ShowAsync();

        return success;
    }

Can anyone see something wrong with what I am doing, or need to do anything within the AAD service provider?

2

2 Answers

1
votes

You might be able to get more accurate information by taking a look at the server-side application logs. Token refresh failure details will be logged there automatically. More details on application logs can be found here: https://azure.microsoft.com/en-us/documentation/articles/web-sites-enable-diagnostic-log/. I recommend setting the trace level to Informational or Verbose.

Also, if you haven't done this already, Azure AD requires a bit of extra configuration to enable refresh tokens. Specifically, you need to configure a "client secret" and enable the OpenID Connect hybrid flow. More details can be found in this blog post: https://cgillum.tech/2016/03/07/app-service-token-store/ (scroll down to the Refreshing Tokens section and see where it describes the process for AAD).

0
votes

Besides what has been said about mobile app configuration, I can spot this.

You have:

// Login with the identity provider.
user = await App.MobileService.LoginAsync(provider);

It should be:

user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,    
          new Dictionary<string, string>() {{ "response_type", "code id_token" }});

Maybe this will help: https://azure.microsoft.com/en-us/blog/mobile-apps-easy-authentication-refresh-token-support/