//-----------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.AspNet.Clients {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Web;
using DotNetOpenAuth.Messaging;
///
/// The facebook client.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Facebook", Justification = "Brand name")]
public sealed class FacebookClient : OAuth2Client {
#region Constants and Fields
///
/// The authorization endpoint.
///
private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";
///
/// The token endpoint.
///
private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";
///
/// The _app id.
///
private readonly string appId;
///
/// The _app secret.
///
private readonly string appSecret;
#endregion
#region Constructors and Destructors
///
/// Initializes a new instance of the class.
///
///
/// The app id.
///
///
/// The app secret.
///
public FacebookClient(string appId, string appSecret)
: base("facebook") {
Requires.NotNullOrEmpty(appId, "appId");
Requires.NotNullOrEmpty(appSecret, "appSecret");
this.appId = appId;
this.appSecret = appSecret;
}
#endregion
#region Methods
///
/// The get service login url.
///
///
/// The return url.
///
/// An absolute URI.
protected override Uri GetServiceLoginUrl(Uri returnUrl) {
// Note: Facebook doesn't like us to url-encode the redirect_uri value
var builder = new UriBuilder(AuthorizationEndpoint);
builder.AppendQueryArgs(
new Dictionary {
{ "client_id", this.appId },
{ "redirect_uri", returnUrl.AbsoluteUri }
});
return builder.Uri;
}
///
/// The get user data.
///
///
/// The access token.
///
/// A dictionary of profile data.
protected override IDictionary GetUserData(string accessToken) {
FacebookGraphData graphData;
var request =
WebRequest.Create(
"https://graph.facebook.com/me?access_token=" + MessagingUtilities.EscapeUriDataStringRfc3986(accessToken));
using (var response = request.GetResponse()) {
using (var responseStream = response.GetResponseStream()) {
graphData = JsonHelper.Deserialize(responseStream);
}
}
// this dictionary must contains
var userData = new Dictionary();
userData.AddItemIfNotEmpty("id", graphData.Id);
userData.AddItemIfNotEmpty("username", graphData.Email);
userData.AddItemIfNotEmpty("name", graphData.Name);
userData.AddItemIfNotEmpty("link", graphData.Link == null ? null : graphData.Link.AbsoluteUri);
userData.AddItemIfNotEmpty("gender", graphData.Gender);
userData.AddItemIfNotEmpty("birthday", graphData.Birthday);
return userData;
}
///
/// Obtains an access token given an authorization code and callback URL.
///
///
/// The return url.
///
///
/// The authorization code.
///
///
/// The access token.
///
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) {
// Note: Facebook doesn't like us to url-encode the redirect_uri value
var builder = new UriBuilder(TokenEndpoint);
builder.AppendQueryArgs(
new Dictionary {
{ "client_id", this.appId },
{ "redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri) },
{ "client_secret", this.appSecret },
{ "code", authorizationCode },
});
using (WebClient client = new WebClient()) {
string data = client.DownloadString(builder.Uri);
if (string.IsNullOrEmpty(data)) {
return null;
}
var parsedQueryString = HttpUtility.ParseQueryString(data);
return parsedQueryString["access_token"];
}
}
///
/// Converts any % encoded values in the URL to uppercase.
///
/// The URL string to normalize
/// The normalized url
/// NormalizeHexEncoding("Login.aspx?ReturnUrl=%2fAccount%2fManage.aspx") returns "Login.aspx?ReturnUrl=%2FAccount%2FManage.aspx"
///
/// There is an issue in Facebook whereby it will rejects the redirect_uri value if
/// the url contains lowercase % encoded values.
///
private static string NormalizeHexEncoding(string url) {
var chars = url.ToCharArray();
for (int i = 0; i < chars.Length - 2; i++) {
if (chars[i] == '%') {
chars[i + 1] = char.ToUpperInvariant(chars[i + 1]);
chars[i + 2] = char.ToUpperInvariant(chars[i + 2]);
i += 2;
}
}
return new string(chars);
}
#endregion
}
}