0

I'm creating an app that access the Microsoft Cloud API to get health data. It uses OAuth to log in when you hit the Sign In Button

 private void signinButton_Click(object sender, RoutedEventArgs e)
    {
        UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_authorize.srf");
        var query = new StringBuilder();

        query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
        query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));

        query.AppendFormat("&scope={0}", Uri.EscapeDataString(Scopes));
        query.Append("&response_type=code");

        uri.Query = query.ToString();

        this.webView.Visibility = Visibility.Visible;
        this.webView.Navigate(uri.Uri);
    }

This brings up a webView with the page to log in using Microsoft credentials. Once completed, it leads to this:

 private async void WebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
    {
        //
        // When the web view navigates to our redirect URI, extract the authorization code from
        // the URI and use it to fetch our access token. If no authorization code is present,
        // we're completing a sign-out flow.
        //
        if (args.Uri.LocalPath.StartsWith("/oauth20_desktop.srf", StringComparison.OrdinalIgnoreCase))
        {
            WwwFormUrlDecoder decoder = new WwwFormUrlDecoder(args.Uri.Query);

            var code = decoder.FirstOrDefault((entry) => entry.Name.Equals("code", StringComparison.OrdinalIgnoreCase));

            var error = decoder.FirstOrDefault((entry) => entry.Name.Equals("error", StringComparison.OrdinalIgnoreCase));
            var errorDesc = decoder.FirstOrDefault((entry) => entry.Name.Equals("error_description", StringComparison.OrdinalIgnoreCase));

            // Check the code to see if this is sign-in or sign-out
            if (code != null)
            {
                // Hide the browser again, no matter what happened...
                sender.Visibility = Visibility.Collapsed;

                if (error != null)
                {
                    this.responseText.Text = string.Format("{0}\r\n{1}", error.Value, errorDesc.Value);
                    return;
                }

                var tokenError = await this.GetToken(code.Value, false);

                if (string.IsNullOrEmpty(tokenError))
                {
                    this.responseText.Text = "Successful sign-in!";
                    this.signoutButton.IsEnabled = true;
                    this.signinButton.IsEnabled = false;
                    this.getProfileButton.IsEnabled = true;
                    this.getDevicesButton.IsEnabled = true;
                    this.getActivitiesButton.IsEnabled = true;
                    this.getDailySummaryButton.IsEnabled = true;
                    this.getHourlySummaryButton.IsEnabled = true;
                }
                else
                {
                    this.responseText.Text = tokenError;
                }
            }
            else
            {
                this.responseText.Text = "Successful sign-out!";

                this.signoutButton.IsEnabled = false;
                this.signinButton.IsEnabled = true;
                this.getProfileButton.IsEnabled = false;
                this.getDevicesButton.IsEnabled = false;
                this.getActivitiesButton.IsEnabled = false;
                this.getDailySummaryButton.IsEnabled = true;
                this.getHourlySummaryButton.IsEnabled = false;
            }
        }
    }

    private async Task<string> GetToken(string code, bool isRefresh)
    {
        UriBuilder uri = new UriBuilder("https://login.live.com/oauth20_token.srf");
        var query = new StringBuilder();

        query.AppendFormat("redirect_uri={0}", Uri.EscapeDataString(RedirectUri));
        query.AppendFormat("&client_id={0}", Uri.EscapeDataString(ClientId));
        query.AppendFormat("&client_secret={0}", Uri.EscapeDataString(ClientSecret));

        if (isRefresh)
        {
            query.AppendFormat("&refresh_token={0}", Uri.EscapeDataString(code));
            query.Append("&grant_type=refresh_token");
        }
        else
        {
            query.AppendFormat("&code={0}", Uri.EscapeDataString(code));
            query.Append("&grant_type=authorization_code");
        }

        uri.Query = query.ToString();

        var request = WebRequest.Create(uri.Uri);

        try
        {
            using (var response = await request.GetResponseAsync())
            {
                using (var stream = response.GetResponseStream())
                {
                    using (var streamReader = new StreamReader(stream))
                    {
                        var responseString = streamReader.ReadToEnd();
                        var jsonResponse = JObject.Parse(responseString);
                        this.creds.AccessToken = (string)jsonResponse["access_token"];
                        this.creds.ExpiresIn = (long)jsonResponse["expires_in"];
                        this.creds.RefreshToken = (string)jsonResponse["refresh_token"];
                        string error = (string)jsonResponse["error"];

                        return error;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

I don't want users to have to accept the permissions every time the app is launched. Is there a way to save credentials locally so that it automatically authenticates on launch? Thanks!

robbiestells
  • 265
  • 2
  • 18
  • is this a windows app or a web application.. if it's web.. why don't you store it a session variable as long as the session has not timed out and check it's value in the `Page_Load` event.. initializing the Session variable in the global.asax OnSession_Start event.. please tell us what type of app this is winforms or webforms – MethodMan Feb 12 '16 at 18:53
  • Sorry thanks for clarifying. It's a UWP app. – robbiestells Feb 12 '16 at 18:54

2 Answers2

1

You can use

Windows.Storage.ApplicationData.Current.LocalSettings

This process good described by this answer Best Way to keep Settings for a WinRT App?

The code in link identity to UWP

Community
  • 1
  • 1
Andrii Krupka
  • 4,276
  • 3
  • 20
  • 41
0

Store the needed oauth parts in the credential locker API. Never store these kind of information in the normal settings API.

On start read the oauth information and use the refreshtoken to get a new access token.

More Information here. https://msdn.microsoft.com/en-us/library/windows/apps/mt270189.aspx

Marco Scheel
  • 180
  • 9