Windows Live Id Authentication using Messenger Connect for Windows Phone

Windows Live Id Authentication using Messenger Connect for Windows Phone

If you saw my post on BuildMobile.com you would have seen that I used the “token” response_type when initially specifying the login url. This works well for getting a short lived access token but the wl.offline_access scope is effectively ignored – the expiry time comes back as 3600. This is completely useless for a Windows Phone application where you don’t want to have to reprompt the user every time they run the application. Luckily, despite the failings in the current implementation, there is a work around which involves a few more steps and uses the “code” response_type.

I’m not going to step through the entire process, instead, here is the code that you should be able to use – it’s based on my post Using Windows Live ID in a WP7 Appon BuildMobile.com so should be easy enough to follow.

Notes:
– You need to replace both <your_client_id> and <your_client_secret> with the corresponding values for your application
– In a production application you should not have the client id or client secret in plain text in your application – ideally this should be held on a server and only exposed to the client app over ssl and never persisted in the client app. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Windows;
using System.Windows.Navigation;

namespace WLTest
{
    public partial class MainPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }

        private void AuthenticateClick(object sender, RoutedEventArgs e)
        {
            var uriParams = new Dictionary<string, string>()
                                {
                                    {“client_id”, “<your_client_id>”},
                                    {“response_type”, “code”},
                                    {“scope”, “wl.signin,wl.basic,wl.offline_access”},
                                    {“redirect_uri”, “https://oauth.live.com/desktop”},
                                    {“display”, “touch”}
                                };
            StringBuilder urlBuilder = new StringBuilder();
            foreach (var current in uriParams)
            {
                if (urlBuilder.Length > 0)
                {
                    urlBuilder.Append(“&”);
                }
                var encoded = HttpUtility.UrlEncode(current.Value);
                urlBuilder.AppendFormat(“{0}={1}”, current.Key, encoded);
            }
            var loginUrl = “https://oauth.live.com/authorize?” + urlBuilder.ToString();

            AuthenticationBrowser.Navigate(new Uri(loginUrl));
            AuthenticationBrowser.Visibility = Visibility.Visible;

        }

        public string AccessToken { get; set; }
        public string RefreshToken { get; set; }

        private void BrowserNavigated(object sender, NavigationEventArgs e)
        {
            if (e.Uri.AbsoluteUri.ToLower().Contains(“https://oauth.live.com/desktop”))
            {
                var query = (from pair in e.Uri.Query.Trim(‘?’).Split(‘&’)
                             let bits = pair.Split(‘=’)
                             where bits.Length == 2
                             select new KeyValuePair<string, string>(bits[0], bits[1])).ToArray();

                var code =
                    query.Where(kvp => kvp.Key == “code”).Select(kvp => HttpUtility.UrlDecode(kvp.Value)).FirstOrDefault
                        ();
                if (string.IsNullOrEmpty(code))
                {
                    var error =
                        query.Where(kvp => kvp.Key == “error”).Select(kvp => HttpUtility.UrlDecode(kvp.Value)).
                            FirstOrDefault();
                    var error_desc =
                        query.Where(kvp => kvp.Key == “error_description”).Select(
                            kvp => HttpUtility.UrlDecode(kvp.Value)).FirstOrDefault();
                    MessageBox.Show(“Error: ” + error + “n” + error_desc);
                    AuthenticationBrowser.Visibility = System.Windows.Visibility.Collapsed;
                    return;
                }

                var uriParams = new Dictionary<string, string>()
                                    {
                                        {“client_id”, “<your_client_id>”},
                                        {“client_secret”, “<your_client_secret>”},
                                        {“redirect_uri”, “https://oauth.live.com/desktop”},
                                        {“code”, HttpUtility.UrlEncode(code)},
                                        {“grant_type”, “authorization_code”}
                                    };
                StringBuilder urlBuilder = new StringBuilder();
                foreach (var current in uriParams)
                {
                    if (urlBuilder.Length > 0)
                    {
                        urlBuilder.Append(“&”);
                    }
                    var encoded = HttpUtility.UrlEncode(current.Value);
                    urlBuilder.AppendFormat(“{0}={1}”, current.Key, encoded);
                }
                var tokenUri = “https://oauth.live.com/token?” + urlBuilder.ToString();

                var request = HttpWebRequest.CreateHttp(tokenUri);
                request.BeginGetResponse(result =>
                                             {
                                                 var req = result.AsyncState as HttpWebRequest;
                                                 using (var resp = req.EndGetResponse(result))

                                                 using (var strm = resp.GetResponseStream())
                                                 {
                                                     var serializer =
                                                         new DataContractJsonSerializer(
                                                             typeof (WindowsLiveAuthorizationCode));
                                                     var authorization =
                                                         serializer.ReadObject(strm) as WindowsLiveAuthorizationCode;
                                                     AccessToken = authorization.AccessToken;
                                                     RefreshToken = authorization.RefreshToken;

                                                     this.Dispatcher.BeginInvoke(() => MessageBox.Show(
                                                         “Access granted”));
                                                     RequestUserProfile();
                                                 }
                                             }, request);

                AuthenticationBrowser.Visibility = System.Windows.Visibility.Collapsed;
            }
          
        }

 

        private void RequestUserProfile()
        {
            var profileUrl = string.Format(“https://apis.live.net/v5.0/me?access_token={0}”,
                                           HttpUtility.UrlEncode(AccessToken));
            var request = HttpWebRequest.Create(new Uri(profileUrl));
            request.Method = “GET”;
            request.BeginGetResponse(result =>
                                         {
                                             try
                                             {
                                                 var resp = (result.AsyncState as HttpWebRequest).EndGetResponse(result);
                                                 using (var strm = resp.GetResponseStream())
                                                 {
                                                     var serializer =
                                                         new DataContractJsonSerializer(typeof (WindowsLiveProfile));
                                                     var profile =
                                                         serializer.ReadObject(strm) as WindowsLiveProfile;
                                                     this.Dispatcher.BeginInvoke((Action<WindowsLiveProfile>) ((user) => {
                                                                            this.UserIdText.Text = user.Id;
                                                                            this.UserNameText.Text = user.Name;
                                                                                                                   }),
                                                                                 profile);
                                                 }
                                             }
                                             catch (Exception ex)
                                             {
                                                 this.Dispatcher.BeginInvoke(() =>
                                                                             MessageBox.Show(“Unable to attain profile information”));
                                             }
                                         }, request);
        }

        [DataContract]
        public class WindowsLiveProfile
        {
            [DataMember(Name = “id”)]
            public string Id { get; set; }

            [DataMember(Name = “name”)]
            public string Name { get; set; }
        }

        [DataContract]
        public class WindowsLiveAuthorizationCode
        {
            [DataMember(Name = “access_token”)]
            public string AccessToken { get; set; }

            [DataMember(Name = “refresh_token”)]
            public string RefreshToken { get; set; }

            [DataMember(Name = “scope”)]
            public string Scope { get; set; }

            [DataMember(Name = “token_type”)]
            public string TokenType { get; set; }

            [DataMember(Name = “expires_in”)]
            public string ExpiresIn { get; set; }
        }

        private void RefreshTokenClick(object sender, RoutedEventArgs e)
        {

            var uriParams = new Dictionary<string, string>()
                                {
                                    {“client_id”, “<your_client_id>”},
                                    {“client_secret”, “<your_client_secret>”},
                                    {“redirect_uri”, “https://oauth.live.com/desktop”},
                                    {“refresh_token”, RefreshToken},
                                    {“grant_type”, “refresh_token”}
                                };
            StringBuilder urlBuilder = new StringBuilder();
            foreach (var current in uriParams)
            {
                if (urlBuilder.Length > 0)
                {
                    urlBuilder.Append(“&”);
                }
                var encoded = HttpUtility.UrlEncode(current.Value);
                urlBuilder.AppendFormat(“{0}={1}”, current.Key, encoded);
            }
            var tokenUri = “https://oauth.live.com/token?” + urlBuilder.ToString();

            var request = HttpWebRequest.CreateHttp(tokenUri);
            request.BeginGetResponse(result =>
                                         {
                                             var req = result.AsyncState as HttpWebRequest;
                                             using (var resp = req.EndGetResponse(result))

                                             using (var strm = resp.GetResponseStream())
                                             {
                                                 var serializer =
                                                     new DataContractJsonSerializer(
                                                         typeof (WindowsLiveAuthorizationCode));
                                                 var authorization =
                                                     serializer.ReadObject(strm) as WindowsLiveAuthorizationCode;
                                                 AccessToken = authorization.AccessToken;
                                                 RefreshToken = authorization.RefreshToken;

                                                 this.Dispatcher.BeginInvoke(() => MessageBox.Show(
                                                     “Token refreshed”));
                                             }
                                         }, request);
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *