Step by step guide Adding Custom Authentication to Azure mobile app service walkthrough

This post assumes you have already created a new Azure Mobile app service. Im also assuming you already have an existing database on Azure with AspUsers tables like so:

usertables

Steps:

  1. Open Azure portal and select app services then select your mobile app

selectappservice

2. Choose Authentication/Authorization and turn App Service Authentication on.  In this post we’re only looking at custom authentication so in the Action to take dropdown select Allow requst no action. If you will have additional external auth then you may select that. Hit save changes.

turnonauth

3. OK now we need to edit our server code, if you’ve not already done so download the quick start project. For our example we’ll be looking at C# not Nodejs

quickstart

4. Open the project in Visual Studio. As we’re going to be using Asp.net Identity we need to add these Nuget packages as well as EntityFramework Identity. Make sure you have all of the below if not add them in:

packagaes

5. Under the App_Start folder modify Startup.MobileApp.cs and add the following lines to intiate Owin identity:

 public static void ConfigureMobileApp(IAppBuilder app)
        {
            //added to enable authentication
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

...

After the HttpConfiguration config = new HttpConfiguration(); add the following route. This will be used by your app later when we select “Custom” auth the app will call the below route on your service.

config.Routes.MapHttpRoute("custom", ".auth/login/custom", new { controller = "Auth" });

As Im using existing database for this Im also going to comment our the database seed intialization and uncomment the intialize with null line:

 // Use Entity Framework Code First to create database tables based on your DbContext
           // Database.SetInitializer(new siteauditsappInitializer());//not used as dont want code first to overwrite database

            // To prevent Entity Framework from modifying your database schema, use a null database initializer
            Database.SetInitializer<siteauditsappContext>(null);

6. Then add IdentityConfig.cs to the App_Start folder. Im not going to go into the code for this as you should ready have it, if not you should be able to get it from them Asp.net MVC project template when select IndivualAccounts for authentication.

7. Under Controllers folder create a new WebApi Controller called AuthController.cs with below code:

 public class AuthController : ApiController
    {

        public class LoginResult
        {
            public string authenticationToken { get; set; }
            public LoginResultUser user { get; set; }
        }

        public class LoginResultUser
        {
            public string userId { get; set; }
        }

        private ApplicationUserManager _userManager;
        private ApplicationSignInManager _signInManager;

        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }

        public ApplicationSignInManager SignInManager
        {
            get
            {
                return _signInManager ?? HttpContext.Current.GetOwinContext().Get<ApplicationSignInManager>();
            }
            private set
            {
                _signInManager = value;
            }
        }



        public IHttpActionResult Post([FromBody] JObject assertion)
        {
            
            bool passValid = IsPasswordValid(assertion).Result;
            if (passValid) // user-defined function, checks against a database
            {

                var signingKey = Environment.GetEnvironmentVariable("WEBSITE_AUTH_SIGNING_KEY"); //This will be provided by Azure Mobile service when we publish our project
                
                var audience = "https://your app here.azurewebsites.net/"; // audience must match the url of the site
                var issuer = "https://your app here.azurewebsites.net/"; // audience must match the url of the site

                string username = assertion.GetValue("email").Value<string>();

                JwtSecurityToken token = AppServiceLoginHandler.CreateToken(new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, username) },
                    signingKey,
                    audience,
                    issuer,
                    TimeSpan.FromHours(24));
                return Ok(new LoginResult()
                {
                    authenticationToken = token.RawData,
                    user = new LoginResultUser() { userId = username }
                });
            }
            else // user assertion was not valid
            {
                return Content(HttpStatusCode.Unauthorized, "Wrong credentials");
            }
        }

        private async Task<bool> IsPasswordValid(JObject assertion)
        {
            // this is where we would do checks agains a database
            try
            {
                string username = assertion.GetValue("email").ToString();
                string password = assertion.GetValue("password").ToString();
               
                
                var resultTask = SignInManager.PasswordSignInAsync(username, password, true, shouldLockout: true);
                var result = resultTask.Result;
                switch (result)
                {
                    case SignInStatus.Success:
                        return true;
                    case SignInStatus.LockedOut:
                        return false;
                    case SignInStatus.RequiresVerification:
                        return false;
                    case SignInStatus.Failure:
                    default:
                        return false;
                }

            }
            catch (Exception ex)
            {
                return false;
            }
        }
}

8. Add IdentityModel.cs to your Models folder:

using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;

namespace siteauditsappService.Models
{
    public class ApplicationUser : IdentityUser
    {

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }

    }



    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        private const string connectionStringName = "Name=MS_TableConnectionString";

        public ApplicationDbContext()
            : base(connectionStringName, throwIfV1Schema: false)
        {
            Configuration.ProxyCreationEnabled = false;
            Configuration.LazyLoadingEnabled = false;
        }

        // protected override void OnModelCreating(DbModelBuilder modelBuilder)
        // {
        //     base.OnModelCreating(modelBuilder);
        //      modelBuilder.HasDefaultSchema("Application");//if users table has different scheme from dbo
        //   }


        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }


    }
}

In above code note the connection string should be for where you aspnet users database is. Store your connection string in web.config for dev but on Azure this will be in the Application Settings area. When you publish your project to Azure whatever connection string you have in  y ou web.config it will be replaced with the ones in Azure:

webconfig

9. Finally you should be ready to test this. Publish the project and then open you favourite Restful client. I google chrome extension Postman. In the client set body to json and do a post to the service with header Content-Type application/json and body like below:

postman

If credentials are correct you should get back token like so:

{
  "authenticationToken": "blablabbla",
  "user": {
    "userId": "myemail@hotmail.com"
  }
}

Finally add the

[Authorize]

attribute to all the table controllers that you want to secure.

 

Useful tip: What I found really useful was the ability to monitor issues when testing authentication using the Azure Log stream.

Next we need to modify our app to authenticate with this service. I show how to do this using Xamarin app.