thewayofcode

My Thoughts about software engineering

Sidebar

Latest tweets

Tweets by s0nica

Tag Cloud

.Net Asp.Net Asp.Net MVC Asp.Net MVC 3 Async file upload C# Custom Unobtrusive Validation Data Annotations DataAnnotations Design Pattern Drag and drop drag n drop Express.js Facebook Facebook Access Token Facebook authentication Facebook login Facebook OAuth FileAPI HTML5 HTML5 game HTML5 multiplayer game IntelliSense javascript jQuery json knockout knockout databinding dropdownlist knockoutJS mass assign vulnerability Model Binding MVC MVVM Node Node.js PongR query string RestAPI safe model binding SignalR Single page application software-development transactions TransactionScope Twitter Twitter Streaming API Unobtrusive jQuery Validation Visual Studio 2010 XMLHttpRequest xmlhttprequest object
  • RSS - Posts

Enter your email address to follow this blog and receive notifications of new posts by email.

+Valerio Gherion
View Valerio Gheri's profile on LinkedIn

Hey I’m on StackOverflow

profile for s0nica at Stack Overflow, Q&A for professional and enthusiast programmers

Recent Posts

  • Moving to Silvrback!
  • ASP.NET WebApi Identity System: how to login with Facebook access token
  • Asp.NET MVC 5: How to retrieve user information on login with Facebook
  • How to secure your HTTP API endpoints using Facebook as OAuth provider
  • How we do the hiring process in my team

Categories

  • Code examples
  • General
  • Software architecture & design
  • Tips&Tricks
  • Tutorial
  • Uncategorized

Archives

  • July 2014
  • March 2014
  • January 2014
  • November 2013
  • September 2013
  • April 2013
  • January 2013
  • December 2012
  • November 2012
  • September 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011

Blogroll

  • Asp Italia
  • CodeClimber
  • CodeTailor
  • My github
  • ScottGu's blog

Month: March 2014

ASP.NET WebApi Identity System: how to login with Facebook access token

Standard

Heads up!

The blog has moved!
If you are interested in reading new posts, the new URL to bookmark is http://blog.valeriogheri.com/

 

The context

I’m working on a project where I have a RESTful HTTP API implemented using the WebAPI framework that is consumed by a native Android application.
This application allows the user to login using their Facebook account and this feature is implemented using the Facebook SDK for Android.
Now the Facebook SDK always gives you an access token if the OAuth process completes correctly and that’s exactly where I found some hurdles integrating with the WebAPI Asp.Net Identity flow: in the facebook authentication flow for asp.net identity, the facebook oath dialog appends a code rather than access token to the redirect_url, so that the server can exchange this code for an access token via http://localhost:49164/signin-facebook?code=…&state=…

Obviously this is not good for our scenario as we already have the facebook access token!
The goal is not to reinvent the wheel, but to find a solution that integrates with the existing OWIN authentication and authorization pipeline.
What we want is to find a way to use existing Asp.Net Identity methods to register the claim identity, so that the system knows about the user, and to generate an API Bearer token that will be given back to the client and that will need to be supplied for each subsequent call to the API endpoints.

The solution

The proposed solution acts on two different files:

Startup.cs


public partial class Startup
{
/// <summary>
/// This part has been added to have an API endpoint to authenticate users that accept a Facebook access token
/// </summary>
static Startup()
{
PublicClientId = "self";
UserManagerFactory = () =>
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
userManager.UserValidator = new UserValidator<ApplicationUser>(userManager) { AllowOnlyAlphanumericUserNames = false };
return userManager;
};
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// This is a key step of the solution as we need to supply a meaningful and fully working
// implementation of the OAuthBearerOptions object when we configure the OAuth Bearer authentication mechanism.
// The trick here is to reuse the previously defined OAuthOptions object that already
// implements almost everything we need
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
OAuthBearerOptions.AccessTokenFormat = OAuthOptions.AccessTokenFormat;
OAuthBearerOptions.AccessTokenProvider = OAuthOptions.AccessTokenProvider;
OAuthBearerOptions.AuthenticationMode = OAuthOptions.AuthenticationMode;
OAuthBearerOptions.AuthenticationType = OAuthOptions.AuthenticationType;
OAuthBearerOptions.Description = OAuthOptions.Description;
// The provider is the only object we need to redefine. See below for the implementation
OAuthBearerOptions.Provider = new CustomBearerAuthenticationProvider();
OAuthBearerOptions.SystemClock = OAuthOptions.SystemClock;
}
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static Func<UserManager<ApplicationUser>> UserManagerFactory { get; set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
//[Initial boilerplate code]
//Here we use the OAuthBearerOptions object
OAuthBearerAuthenticationExtensions.UseOAuthBearerAuthentication(app, OAuthBearerOptions);
//[More boilerplate code]
}
}
public class CustomBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
// This validates the identity based on the issuer of the claim.
// The issuer is set in the API endpoint that logs the user in
public override Task ValidateIdentity(OAuthValidateIdentityContext context)
{
var claims = context.Ticket.Identity.Claims;
if (claims.Count() == 0 || claims.Any(claim => claim.Issuer != "Facebook" && claim.Issuer != "LOCAL_AUTHORITY" ))
context.Rejected();
return Task.FromResult<object>(null);
}
}

view raw

Startup.cs

hosted with ❤ by GitHub

AccountController.cs


[HttpPost]
[AllowAnonymous]
[Route("FacebookLogin")]
public async Task<IHttpActionResult> FacebookLogin([FromBody] string token)
{
if (string.IsNullOrEmpty(token))
{
return BadRequest("Invalid OAuth access token");
}
var tokenExpirationTimeSpan = TimeSpan.FromDays(14);
ApplicationUser user = null;
// Get the fb access token and make a graph call to the /me endpoint
var fbUser = await VerifyFacebookAccessToken(token);
if (fbUser == null)
{
return BadRequest("Invalid OAuth access token");
}
// Check if the user is already registered
user = await UserManager.FindByNameAsync(fbUser.Username);
// If not, register it
if (user == null)
{
var randomPassword = System.Web.Security.Membership.GeneratePassword(10, 5);
user = await RegisterUserAsync(fbUser.Username, randomPassword, fbUser.ID);
var customer = await RegisterCustomerAsync(fbUser.FirstName, fbUser.LastName, fbUser.Email, user);
}
// Sign-in the user using the OWIN flow
var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName, null, "Facebook"));
// This is very important as it will be used to populate the current user id
// that is retrieved with the User.Identity.GetUserId() method inside an API Controller
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id, null, "LOCAL_AUTHORITY"));
AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(tokenExpirationTimeSpan);
var accesstoken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
Request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accesstoken);
Authentication.SignIn(identity);
// Create the response building a JSON object that mimics exactly the one issued by the default /Token endpoint
JObject blob = new JObject(
new JProperty("userName", user.UserName),
new JProperty("access_token", accesstoken),
new JProperty("token_type", "bearer"),
new JProperty("expires_in", tokenExpirationTimeSpan.TotalSeconds.ToString()),
new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
);
// Return OK
return Ok(blob);
}

view raw

AccountController.cs

hosted with ❤ by GitHub

I posted this solution on StackOverflow to answer the following question: http://stackoverflow.com/questions/21092723/webapi-asp-net-identity-facebook-login

I hope this helps,
Valerio

  • Date March 1, 2014
  • Tags Asp.Net, Asp.Net WebAPI, Authentication, C#, Facebook Access Token, Facebook authentication, Facebook login, Facebook OAuth, OWIN, WebAPI
  • Comments 20 Comments
Blog at WordPress.com.
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy
  • Subscribe Subscribed
    • thewayofcode
    • Join 137 other subscribers
    • Already have a WordPress.com account? Log in now.
    • thewayofcode
    • Subscribe Subscribed
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar
Design a site like this with WordPress.com
Get started