jeudi 1 juin 2017

Using Microsoft account login in your UWP applications (Desktop and Xbox One) [XAML,C#]

After having used the google account and facebook account login in UWP apps I must say that the Microsoft account login was much easier to implement !  The only tricky part is when you wish to login on your Xbox One.

My example will be strongly base off the work MS has already done and published in  Github, the main elements that my sample code will add is a service and a event that is fired when we receive the Oauth token.

First I wanted to create a service, so I create an interface as follows:
    public interface IMicrosoftService
    {
        event Action<string> MsTokenReceived;
        Task LogIntoMicrosoftService();
    }

I have create the MsTokenReceived event as it will allow me to pass the information that I have received my token and thus can continue to try and log the user.

First we create our class:   (MicrosoftService.cs)

public class MicrosoftService : IMicrosoftService

then 




// To obtain Microsoft account tokens, you must register your application online
        // Then, you must associate the app with the store.
        const string MicrosoftAccountProviderId = "https://login.microsoft.com";
        const string ConsumerAuthority = "consumers";
        const string AccountScopeRequested = "wl.basic";
        const string AccountClientId = "your cliend id";
        const string StoredAccountToken = "NameOfWhereYouStoreAccountToekn";

You will find or create your AccountClientId here https://apps.dev.microsoft.com/#/appList







Click on Add App, fill in the necessary information, add a platform (here under platform I have added a Native Application)



and click Save.

Now back to our app, in our class MicrosoftService.cs, we will add the method:

 public event Action<string> MsTokenReceived;

 public Task LogIntoMicrosoftService()
 {
     // The AccountCommandsRequested event triggers before the Accounts settings pane is displayed 
     AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested += OnAccountCommandsRequested;
     // show the pane
AccountsSettingsPane.Show(); return Task.CompletedTask; }


Again this is exactly what you will find in the windows sample, except for when you want to run your application on an Xbox.

  // This event handler is called when the Account settings pane is to be launched.
  private async void OnAccountCommandsRequested(
            AccountsSettingsPane sender,
            AccountsSettingsPaneCommandsRequestedEventArgs e)
        {
            // In order to make async calls within this callback, the deferral object is needed
            AccountsSettingsPaneEventDeferral deferral = e.GetDeferral();

            if (App.DeviceType == Helper.DeviceTypeEnum.Xbox)
            {
                await GetAccountProviderForXboxLogin();
            }
            else
            {
                await AddWebAccountProvider(e);
            }
            deferral.Complete();
        }

This is a simple copy and paste of the code from the MS sample.
      private async Task AddWebAccountProvider(AccountsSettingsPaneCommandsRequestedEventArgs e)
        {
            // FindAccountProviderAsync returns the WebAccountProvider of an installed plugin
            // The Provider and Authority specifies the specific plugin
            // This scenario only supports Microsoft accounts.

            // The Microsoft account provider is always present in Windows 10 devices, as is the Azure AD plugin.
            // If a non-installed plugin or incorect identity is specified, FindAccountProviderAsync will return null   
            WebAccountProvider provider = await WebAuthenticationCoreManager.FindAccountProviderAsync(MicrosoftAccountProviderId, MicrosoftAccountProviderId);

            WebAccountProviderCommand providerCommand = new WebAccountProviderCommand(provider, WebAccountProviderCommandInvoked);
            e.WebAccountProviderCommands.Add(providerCommand);
        }


        private async void WebAccountProviderCommandInvoked(WebAccountProviderCommand command)
        {
            // ClientID is ignored by MSA
            await RequestTokenAndSaveAccount(command.WebAccountProvider, AccountScopeRequested, AccountClientId);
        }


        private async Task RequestTokenAndSaveAccount(WebAccountProvider Provider, String Scope, String ClientID)
        {
            try
            {
                WebTokenRequest webTokenRequest = new WebTokenRequest(Provider, Scope, ClientID);

                // If the user selected a specific account, RequestTokenAsync will return a token for that account.
                // The user may be prompted for credentials or to authorize using that account with your app
                // If the user selected a provider, the user will be prompted for credentials to login to a new account
                WebTokenRequestResult webTokenRequestResult = await WebAuthenticationCoreManager.RequestTokenAsync(webTokenRequest);

                // If a token was successfully returned, then store the WebAccount Id into local app data
                // This Id can be used to retrieve the account whenever needed. To later get a token with that account
                // First retrieve the account with FindAccountAsync, and include that webaccount 
                // as a parameter to RequestTokenAsync or RequestTokenSilentlyAsync
                if (webTokenRequestResult.ResponseStatus == WebTokenRequestStatus.Success)
                {
                    ApplicationData.Current.LocalSettings.Values.Remove(StoredAccountToken);

                    ApplicationData.Current.LocalSettings.Values[StoredAccountToken] = webTokenRequestResult.ResponseData[0].Token;

                    MsTokenReceived?.Invoke(webTokenRequestResult.ResponseData[0].Token);
                }
            }
            catch (Exception ex)
            {
                App.ReportErrorInternalOnly(ex);
            }
        }

the only added code is this:

MsTokenReceived?.Invoke(webTokenRequestResult.ResponseData[0].Token);

which allows me to send the information back to the app that we have received the Oauth token, here I send back a string that is the Oauth token but you can send back whatever you wish.

For the Xbox we must find the default provider with only the ClientId:

        private async Task GetAccountProviderForXboxLogin()
        {
            //get the default provider by using only the Account Id
            var defaultProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(MicrosoftAccountProviderId);

            //get the token
            await RequestTokenAndSaveAccount(defaultProvider, AccountScopeRequested, AccountClientId);
        }


Now we just need to instantiate our class call the LogIntoMicrosoftService method for the IMicrosoftService and wait for the MsTokenReceived event to be fire for the login to have worked

private void Load()
{
       SimpleIoc.Default.GetInstance<IMicrosoftService>().LogIntoMicrosoftService();
       SimpleIoc.Default.GetInstance<IMicrosoftService>().MsTokenReceived += OnMsTokenReceived;
}
 
private void OnMsTokenReceived(string token)
{
      var AccessToken = token;
      SimpleIoc.Default.GetInstance<IMicrosoftService>().MsTokenReceived -= OnMsTokenReceived;
      ValidateMSLogin();
}


Happy Coding!

mardi 14 mars 2017

Using GraphQL in your Windows Application part II - using mutations [UWP,NET,GraphQL]

In this article we are going to see how we can do a Mutation in GraphQL in your .NET app, you will be able to find more documentation about mutations here: http://graphql.org/learn/queries/

We will be using the same endpoints and example as in the previous article:
Using GraphQL in your Windows Application part I [UWP,NET,GraphQL]

Just like the previous article related to querying GraphQL, you will need a text file that will hold a JSON mutation query as follow:

mutation($input: FavBookInput!){
  favoriteBook(input:$input){
    status
    clientMutationId
  }
}

Next we will need to create a Class what will hold the variables that we will pass in our query:

namespace GraphQL.QlFiles.M
{
    public class QueryAddToFavBooksMutationModel
        {
        public BookInput input { get; set; }
    }
    public class BookInput
    {
        public string bookXid { get; set; }
    }
}

Here are the string const that we will be using:

 public const string GrapgQL_PARAM_Query_and_Variables_To_CALL = "query={0}&variables={1}";
 public const string GRAPHQL_URL_BASE = "https://graphql.api.abcde.com/";
 public const string MyMutationQueryCallFile = "ms-appx:///QlFiles/M/AddToFavBooks.txt";

Doing a mutation on GraphQL is very much like doing a classic GET HTTP GraphQL query but you also need to pass variable in the query.  You will need to intenciante the QueryAddToFavBooksMutationModel class with the correct value so that you can add the correct book to your favorites.  Next you will convert the class to JSON and pass this it to your query as follows:

 private async void GraphQLMutationQuery()
        {
            //prepartion the variables that will be sent for the get query
            var myMutation = new QueryAddToFavBooksMutationModel()
            {
                input = new BookInput()
                {
                    bookXid = "ABC"
                }
            };

            //getting ou file
            var queryParams = await FileIOReaderHelper.ReadFromDefaultFileAsync(MyMutationQueryCallFile);

            //serializing our class to json so that we can send it in the GET call.
            string Variables = JsonConvert.Serialize(myMutation);

            var paramsToCall = String.Format(GrapgQL_PARAM_Query_and_Variables_To_CALL,
                            WebUtility.UrlEncode(queryParams),
                            WebUtility.UrlEncode(Variables)
                        );

            //creating our query
            var urlQuery = String.Format("{0}?{1}", GRAPHQL_URL_BASE, paramsToCall);

            //now you can do your http call 
            var response = await HttpClient.SendAsync(urlQuery);
        }





NAd there you have it you can now do mutations on GraphQL. This could be greatly improved, however for our example this gets the job done.

Happy coding.

jeudi 2 mars 2017

Using GraphQL in your Windows Application part I [UWP,NET,GraphQL]

init()

In this article we are going to see how can query a GraphQL endpoint, in the next article we are going to see how you could do a Mutation.

Here is a quick overview of what GrapgQL is http://graphql.org/ 

FYI: GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.

Now lets say that we have this end point https://grapql.api.MyWebsite.com

Also lets say that on this endpoint I can query it as follow:


fragment BookFields on Book {
  xid
  title
  author
  thumbnails
  year
}

{
  views {
    sections {
      edges {
        node {
          name
          title
          components {
            edges {
              node {
                __typename
                ...BookFields
              }
            }
          }
        }
      }
    }
  }
}


And lets say that the endpoint will respond with the following json payload:

{
  "data": {
    "views": {
       "sections": {
          "edges": [
            {
              "node": {
                "name": "HarryPotter_books",
                "title": "Harry Potter Books",
                "components": {
                  "edges": [
                    {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Philosopher's Stone",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1997
                        }
                     
                    },
                    {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Chamber of Secrets",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1998
                        }
                    },
     {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Prisoner of Azkaban",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 1999
                        }
                    },
     {
                      "node": {
                        "__typename": "Books",
                        "xid": "A1",
                        "author": "J. K. Rowling",
                        "title": "Harry Potter : The Goblet of Fire",
                        "thumbnails": "https://ABC.net/x240-nEZ.jpg",                        
                        "year": 2000
                       }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
}

Now we convert this JSON to C# classes:


public class NodeItem
{
    public string __typename { get; set; }
    public string xid { get; set; }
    public string author { get; set; }
    public string title { get; set; }
    public string thumbnails { get; set; }
    public int year { get; set; }
}

public class EdgeItem
{
    public NodeItem node { get; set; }
}

public class Components
{
    public List<EdgeItem> edges { get; set; }
}

public class Node
{
    public string name { get; set; }
    public string title { get; set; }
    public Components components { get; set; }
}

public class Edge
{
    public Node node { get; set; }
}

public class Sections
{
    public List<Edge> edges { get; set; }
}

public class Views
{
    public Sections sections { get; set; }
}

public class Data
{
    public Views views { get; set; }
}

public class RootObject
{
    public Data data { get; set; }
}


Ok now that we can create a blank UWP app, add 2 folders one for the models and one for the GraqhQL txt file.  In my solution the folders are called Model and QlFiles.  In QlFiles we will add a txt file called MyQuery.txt that will hold our query.

Next we will need to read this json text file using :

await StorageFile.GetFileFromApplicationUriAsync(appUri);
and 
await FileIO.ReadTextAsync(anjFile);

And now we just need to format our get query and we can do the HTTP call.


public sealed partial class MainPage : Page
{
        public const string GrapgQL_PARAM_To_CALL = "query={0}";
        public const string GRAPHQL_URL_BASE = "https://graphql.api.abcde.com/";
        public const string MyQueryCallFile = "ms-appx:///QlFiles/MyQuery.txt";

        public MainPage()
        {
            this.InitializeComponent();
            Loaded += MainPage_Loaded;
        }

        private async void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            //Fetching the json from the txt file
var queryParams = await FileIOReaderHelper.ReadFromDefaultFileAsync(MyQueryCallFile);
            
            //merging the parms for the query
var paramsToCall = String.Format(GrapgQL_PARAM_To_CALL,
                                             WebUtility.UrlEncode(queryParams));
            //Creating the query to call
var urlQuery = String.Format("{0}?{1}",
                                         GRAPHQL_URL_BASE,        
                                         paramsToCall);

            //doing the http call 
            var response = await HttpClient.SendAsync(urlQuery);
            var responseJson = await response.Content.ReadAsStringAsync();

            //you can deserialize with the RootObject class you created
            var responseObject = JsonService.DeserializeObject<RootObject>(responseJson);

        }

        public static class FileIOReaderHelper
        {
            //Read the content from Json file 
            public static async Task<string> ReadFromDefaultFileAsync(string fileName)
            {
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    throw new ArgumentNullException(nameof(fileName));
                }

                Uri appUri = new Uri(fileName);

                IStorageFile anjFile = await StorageFile.GetFileFromApplicationUriAsync(appUri);

                string txtFile = await FileIO.ReadTextAsync(anjFile);

                return txtFile;

            }
        }
}


As of today as you can see using GraphQL in you .NET application is a bit hash and not developer friendly.  If by any chance you have a cleaner way of doing it don't hesitate to comment!

Happy coding!



dimanche 1 janvier 2017

Using .NET WebAuthenticationBroker for Google Login in your Windows 10 application [UWP,C#,GOOGLE]

I was fighting with my Google login on my UWP app and thus thought that it would be great if I just copied and pasted my code here so that it might help others.

Long story short, I did not want to use the google SDK to log into my app so I ended up using WebAuthenticationBroker.AuthenticateAsync.   For the WebAuthenticationBroker you need a startUrl and a endUrl which you can find here:
var googleUrl = new System.Text.StringBuilder();
            googleUrl.Append("https://accounts.google.com/o/oauth2/auth?client_id=");
            googleUrl.Append(Uri.EscapeDataString(ClientID));
            googleUrl.Append("&scope=");
            googleUrl.Append(Uri.EscapeDataString("https://www.googleapis.com/auth/plus.profile.emails.read"));
            googleUrl.Append("&redirect_uri=");
            googleUrl.Append(Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob"));
            googleUrl.Append("&response_type=code");


string endURL = "https://accounts.google.com/o/oauth2/approval?";


One small problem, was that when using WebAuthenticationBroker on UWP you don't get an access token but a authorization code which doesn't really help you,  because you cant authenticate with an authorization code, I needed an access token.

What we need to do next is a POST call on  https://accounts.google.com/o/oauth2/token
with my client id, client secret and authorization code and a few other parameters, here is the full list:
 var pairs = new Dictionary<string, string>();
                    pairs.Add("code", authorizationCode);
                    pairs.Add("client_id", ClientID);
                    pairs.Add("client_secret", ClientSecret);
                    pairs.Add("grant_type", "authorization_code");
                    pairs.Add("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");

We encode the content:
var formContent = new HttpFormUrlEncodedContent(pairs);

Next we do our POST call:
await client.PostAsync(new Uri("https://accounts.google.com/o/oauth2/token"), formContent);

And Voila you have your auth token =)
string response = await httpResponseMessage.Content.ReadAsStringAsync();

Full code here:
Warning to people that like sexy code this will hurt you eyes:

 public async Task<string> LogIntoGoogleClean()
 {
            var googleUrl = new System.Text.StringBuilder();
            googleUrl.Append("https://accounts.google.com/o/oauth2/auth?client_id=");
            googleUrl.Append(Uri.EscapeDataString(ClientID));
            googleUrl.Append("&scope=");
            googleUrl.Append(Uri.EscapeDataString("https://www.googleapis.com/auth/plus.profile.emails.read"));
            googleUrl.Append("&redirect_uri=");
            googleUrl.Append(Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob"));
            googleUrl.Append("&response_type=code");

            //approval
            string endURL = "https://accounts.google.com/o/oauth2/approval?";

            Uri startUri = new Uri(googleUrl.ToString());
            Uri endUri = new Uri(endURL);

            try
            {
                // Using WebAuthenticationBroker
                WebAuthenticationResult webAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, startUri, endUri);

                //Checking to see if we haev succeded
                if (webAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
                {
                    Debug.WriteLine("ResponseData: " + webAuthenticationResult.ResponseData);

                    //getting just the autorizationCode to continue and get the token 
                    var authorizationCode = webAuthenticationResult.ResponseData.Substring(13);

                    //lets get crazy and get the access token so that i can really login
                    var pairs = new Dictionary<string, string>();
                    pairs.Add("code", authorizationCode);
                    pairs.Add("client_id", ClientID);
                    pairs.Add("client_secret", ClientSecret);
                    pairs.Add("grant_type", "authorization_code");
                    pairs.Add("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");


                    var formContent = new HttpFormUrlEncodedContent(pairs);

                    //please dont hate me but this is dirty
                    var client = new HttpClient();
                    var httpResponseMessage =
                        await client.PostAsync(new Uri("https://accounts.google.com/o/oauth2/token"), formContent);
                    string response = await httpResponseMessage.Content.ReadAsStringAsync();

                    //but at least I got it to work :P
                    GoogleAccessToken token = JsonConvert.DeserializeObject<GoogleAccessToken>(response);

                    //return access token
                    return token.access_token;
                }
                else
                    return webAuthenticationResult.ResponseStatus.ToString();
            }
            catch (Exception Error)
            {
                //report the issue
App.RepportError(Error); } return "error"; }

Happy Coding!