Create an ASP.NET MVC 5 App with Facebook and Google OAuth2 and OpenID Sign-on (C#)
This tutorial shows you how to build an ASP.NET MVC 5 web application that enables users to log in using OAuth 2.0 or OpenID with credentials from an external authentication provider, such as Facebook, Twitter, Microsoft, or Google. For simplicity, this tutorial focuses on working with credentials from Facebook and Google.
Enabling these credentials in your web sites provides a significant advantage because millions of users already have accounts with these external providers. These users may be more inclined to sign up for your site if they do not have to create and remember a new set of credentials.
The tutorial also shows how to add profile data for the user, and how to use the Membership API to add roles.
Getting Started
Start by installing and running Visual Studio Express 2013 RC for Web or Visual Studio 2013 RC.
Click New Project from the Start page, or you can use the menu and select File, and then New Project.
Creating Your First Application
Click New Project, then select Visual C# on the left, then Web and then select ASP.NET Web Application. Name your project "MvcAuth" and then click OK.
In the New ASP.NET Project dialog, click MVC and then click Configure Authentication.
In the Configure Authentication dialog, keep the default Individual User Accounts, and then click OK.
Back in the New ASP.NET Project dialog, Click Create Project. Press F5 or Control F5 to run the application. In the image below, the port number is 1234. When you run the application, you'll see a different port number.
Depending on the size of your browser window, you might need to click the navigation icon to see the Home, About, Contact, Register and Log in links.
Enable the Google OpenID provider
Open the App_Start\Startup.Auth.cs file and remove the comment
characters in //app.UseGoogleAuthentication();
to
enable Google authentication.
public void ConfigureAuth(IAppBuilder app) { // Enable the application to use a cookie to store information for the signed in user app.UseApplicationSignInCookie(); // Enable the application to use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(); // Uncomment the following lines to enable logging in with third party login providers //app.UseMicrosoftAccountAuthentication( // clientId: "", // clientSecret: ""); //app.UseTwitterAuthentication( // consumerKey: "", // consumerSecret: ""); //app.UseFacebookAuthentication( // appId: "", // appSecret: ""); app.UseGoogleAuthentication(); }
Press Control F5 to build and run the application. Click the Log in link.
Under Use another service to log in, click Google.
You will be redirected to the google site where you will enter your credentials. After you enter your credentials, you will be prompted to give the following permissions to the web application you just created:
- View basic information about your account.
- View your email address
Click Accept.
You will now be redirected back to the Register page of MvcAuth application where you can register your Google account with the MvcAuth application. Notice the URL in the image above contains openid2. Unlike OAuth2 providers, OpenID providers don't require you to create an application with the authentication provider.
Click Register to add the user name and your Google account information to the MvcAuth application.
Next you are redirected back to the home page where you can see your name and a Log off link.
That's all you need to add Google as an identity provider.
Setting up SSL in the Project
To connect to Facebook, you will need to set up IIS-Express to use SSL. Even though Google doesn't require you to use SSL to log in, it's a security best practice to require SSL in your application. It's important to keep using SSL after login and not drop back to HTTP, your login cookie is just as secret as your username and password, and without using SSL you’re sending it in clear-text across the wire. Besides, you’ve already taken the time to perform the handshake and secure the channel (which is the bulk of what makes HTTPS slower than HTTP) before the MVC pipeline is run, so redirecting back to HTTP after you’re logged in won’t make the current request or future requests much faster.
- In Solution Explorer, click the MvcAuth project.
- Enter the F4 key to show the project properties. Alternatively, from the View menu you can select the Properties Window.
- Change SSL Enabled to True.
- Copy the SSL URL (which will be https://localhost:44300/ unless you've created other SSL projects).
- In Solution Explorer, right click the MvcAuth project and select Properties.
- Select the Web tab, and then paste the SSL URL into the Project Url
box. Save the file (Ctl+S). You will need this URL to configure
Facebook.
Creating the app in Facebook and connecting the app to the project
For Facebook OAuth2 authentication, you need to copy to your project some settings from an application that you create in Facebook.
-
In your browser, navigate to https://developers.facebook.com/apps and log in by entering your Facebook credentials.
-
If you aren’t already registered as a Facebook developer, click Register as a Developer and follow the directions to register.
-
Click Create New App.
-
Enter an App Name and then click Continue.
This must be unique across Facebook. The App Namespace is the part of the URL that your App will use to access the Facebook application for authentication (for example, https://apps.facebook.com/{App Namespace}). If you don't specify an App Namespace, the App ID will be used for the URL. The App ID is a long system-generated number that you will see in the next step.
-
On the Basic Settings page for the app, set the Site URL.
You’ll use the App ID and App Secret settings in the next step.
In the image above, Sandbox Mode is enabled, therefore you will only be able to authenticate using the email alias you have registered. Other users and test accounts will not be able to register. You can grant other Facebook accounts access to the application on the Facebook Developer Roles tab. Attempting to authenticate with a non-registered account when the application is in sandbox mode will produce the following error:
Value cannot be null. Parameter name: id
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
-
In Visual Studio, open App_Start\Startup.Auth.cs.
-
Copy and paste the AppId and App Secret into the
UseFacebookAuthentication
method. Be sure to remove the comment characters. The AppId and App Secret values shown below are samples and will not work.public void ConfigureAuth(IAppBuilder app) { // Enable the application to use a cookie to store information for the signed in user // and to use a cookie to temporarily store information about a user logging in with a third party login provider app.UseSignInCookies(); // Uncomment the following lines to enable logging in with third party login providers //app.UseMicrosoftAccountAuthentication( // clientId: "", // clientSecret: ""); //app.UseTwitterAuthentication( // consumerKey: "", // consumerSecret: ""); app.UseFacebookAuthentication( appId: "000000000000000", appSecret: "000000000000000"); app.UseGoogleAuthentication(); }
-
Click Save Changes.
-
Press CTRL+F5 to run the application.
When you run the application in Internet Explorer (IE), Firefox, or Page Inspector, you get a security certificate warning. This is because the certificates used by IIS Express are not trusted by browsers. You can dismiss these warnings on your development machine. When you deploy the application to Windows Azure, the SSL certificates are trusted and you won't get any warnings. In IE, click Continue to this website (not recommended). In Chrome, click Proceed anyway.


Under Use another service to log in. click Facebook.
Enter your Facebook credentials.
You will be prompted to grant permission for the application to access your profile and friend list.
You are now logged in. You can now register this account with the application.
When you register, an entry is added to the Users table of the membership database.
Examine the Membership Data
In the View menu, click Server Explorer.
Expand DefaultConnection (MvcAuth), expand Tables, right click AspNetUsers and click Show Table Data.
Adding Profile Data to the User Class
In this section you'll add birth date and home town to the user data during registration, as shown in the following image.
Open the Models\IdentityModels.cs file and add birth date and home town properties:
using Microsoft.AspNet.Identity.EntityFramework; using System; namespace MvcAuth.Models { public class ApplicationUser : User { public string HomeTown { get; set; } public DateTime ? BirthData { get; set; } } public class ApplicationDbContext : IdentityDbContextWithCustomUser<ApplicationUser> { } }
Open the Models\AccountViewModels.cs file and the set
birth date and home town properties in ExternalLoginConfirmationViewModel
.
public class ExternalLoginConfirmationViewModel { [Required] [Display(Name = "User name")] public string UserName { get; set; } public string HomeTown { get; set; } public DateTime ? BirthData { get; set; } }
Open the Controllers\AccountController.cs file and update the
ExternalLoginConfirmation
action method as shown:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) { if (User.Identity.IsAuthenticated) { return RedirectToAction("Manage"); } if (ModelState.IsValid) { // Get the information about the user from the external login provider var user = new ApplicationUser() { UserName = model.UserName, BirthData = model.BirthData, HomeTown = model.HomeTown }; IdentityResult result = await IdentityManager.Authentication.CreateAndSignInExternalUserAsync( // AuthenticationManager, new User(model.UserName)); AuthenticationManager, user); if (result.Success) { return RedirectToLocal(returnUrl); } else { AddErrors(result); } } ViewBag.ReturnUrl = returnUrl; return View(model); }
Change the AccountController
constructor to pass an
ApplicationDbContext
parameter:
public AccountController() { IdentityManager = new AuthenticationIdentityManager( new IdentityStore(new ApplicationDbContext())); }
Add birth date and home town to the Views\Account\ExternalLoginConfirmation.cshtml file:
@model MvcAuth.Models.ExternalLoginConfirmationViewModel @{ ViewBag.Title = "Register"; } <hgroup> <h2>@ViewBag.Title.</h2> <h3>Associate your @ViewBag.LoginProvider account.</h3> </hgroup> @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl })) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset> <legend>Association Form</legend> <p class="text-success"> You've successfully authenticated with <strong>@ViewBag.LoginProvider</strong>. Please enter a user name for this site below and click the Register button to finish logging in. </p> @Html.LabelFor(m => m.UserName) @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) <br /> @Html.LabelFor(m => m.HomeTown) @Html.TextBoxFor(m => m.HomeTown) @Html.ValidationMessageFor(m => m.HomeTown) <br /> @Html.LabelFor(m => m.BirthData) @Html.TextBoxFor(m => m.BirthData) @Html.ValidationMessageFor(m => m.BirthData) <br /> <input type="submit" class="btn" value="Register" /> </fieldset> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Delete the membership database so you can again register your Facebook account with your application and verify you can add the new birth date and home town profile information.
From Solution Explorer, click the Show All Files icon, then right click Add_Data\aspnet-MvcAuth-<dateStamp>.mdf and click Delete.
From the Tools menu, click Library Package Manger, then click Package Manager Console (PMC). Enter the following commands in the PMC.
- Enable-Migrations
- Add-Migration BirthDate
- Update-Database
Run the application and use FaceBook to log in and register a user.
The Membership Database
In this section you will examine the membership database and use the new membership API to add a user and a role.
Open the MvcAuth\Global.asax.cs file and replace the contents with the following:
using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using System.Threading.Tasks; using MvcAuth.Models; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using System.Threading; using Microsoft.AspNet.Identity.EntityFramework; namespace MvcAuth { public class MvcApplication : System.Web.HttpApplication { async Task<bool> AddRoleAndUser() { AuthenticationIdentityManager IdentityManager = new AuthenticationIdentityManager( new IdentityStore(new ApplicationDbContext())); var role = new Role("Role1"); IdentityResult result = await IdentityManager.Roles.CreateRoleAsync(role, CancellationToken.None); if (result.Success == false) return false; var user = new ApplicationUser() { UserName = "user1" }; result = await IdentityManager.Users.CreateLocalUserAsync(user, "Password1"); if (result.Success == false) return false; result = await IdentityManager.Roles.AddUserToRoleAsync(user.Id, role.Id, CancellationToken.None); return result.Success; } protected async void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); bool x = await AddRoleAndUser(); } } }
Set a break point in the AddRoleAndUser
method, and then press
F5 to debug the application. If IIS Express is running and the application
has not timed out, the Application_Start
method will not be called
and the break point will not be hit. To restart IIS Express, you can either exit
and restart Visual Studio, or you can right click the IIS Express icon in the
task notification area and click Exit.
Step through the AddRoleAndUser
method. The first time
this method is called, the new user and role are created. On subsequent calls,
the method will return false
on the CreateRoleAsync
call (because "Role1" exists). The AddRoleAndUser
code above shows how to use the new membership API and is
not meant to be the mechanism for adding new users and roles.
Examine the Membership Data
In the View menu, click Server Explorer.
Right click AspNetUsers and click Show Table Data.
In addition to the Facebook and Google accounts you added, you can see the
user1 account you added using the membership API. The Discriminator
column was added by Entity Framework because the ApplicationUser
class is derived from the User
class. You can read about this in
Implementing Inheritance with the Entity Framework in an ASP.NET MVC App.
Require Authorization
Open the Controllers\HomeController.cs file and add the following
Authorize attribute to the About
method.
[Authorize(Roles = "Role1")] public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); }
The Authorize attribute will prevent users who are not members of the Role1 role from accessing this method. A user who is not a member of the Role1 role will be redirected to the Login page (where they have a chance to login as a user who is a member of the Role1 role.)
Run the application and navigate to the About
method.
Using the Facebook or Google account you created, you will be redirected to the
Login page. Login in as user1 (password "Password1") and you will be able to access the About
page.
Remove Local ASP.NET Membership Registration
The current local ASP.NET membership registration in the project does not provide support for password resets and it does not verify that a human is registering (for example with a CAPTCHA). Once a user is authenticated using one of the third party providers, they can register and the third party provider has support for password reset.
Remove or comment out the Register
link in the
Views\Shared\_LoginPartial.cshtml file.
{ <ul class="nav pull-right"> @*<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>*@ <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li> </ul> }
In the AccountController, replace the contents of the GET and POST Register
methods
with the following
redirect:
return RedirectToAction("Index", "Home");
This will prevent bots and anonymous users from registering.
Logging off your App and Logging in With Another Account
If you use the Log off link in your ASP.NET MVC app, then select Log in, and then Use another service to long in and select Facebook, you will be immediately logged in to the Facebook account you had previously logged out of. In order to log out you must navigate to Facebook using the selected browser, and log out of Facebook.
Resetting the Membership Database to Test Registration
If you'd like to test the registration code you'll need to delete the entries in the membership database. An easy way to do this is with the following commands in the Package Manager Console.
Update-Database -TargetMigration:0Update-Database
Next Steps
For an excellent explanation of how ASP.NET External Authentication Services work, see Robert McMurray's External Authentication Services. Robert's article also goes into detail in enabling Microsoft and Twitter authentication.
For more tips on making the application secure, see my tutorial Deploy a Secure ASP.NET MVC app with Membership, OAuth, and SQL Database to a Windows Azure Web Site.
Comments (0) RSS Feed