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);
}
}
}