READ THIS FIRST

Update: 3-4-2016: If you're finding this blog and looking for information related to Azure Mobile Services, I'd strongly recommend checking out Azure Mobile Apps. Azure Mobile Apps is a new version (consider it a v2) of Azure's mobile backend support. All of the same features of Azure Mobile Services are there, with a lot of other very cool features to go along. You can read more about Azure Mobile Apps, and how to transition from Azure Mobile Services, here.

SplashScreen for LensRocket Update 4/22/2014: Version 1 JWTs have been deprecated. Make sure you check out this post to see how the script for JWT creation needs to be changed.

Update 2/20/2014: Due to a few issues, the app formally known as PikShare has been renamed LensRocket. Everything except some names remains the exact same as the originally released source code and application.

With the app I recently released, LensRocket, I wanted to implement custom authentication.  I had already setup custom authentication with Mobile Services last year, however, Mobile Services has launched a few different new features which makes doing custom auth a bit easier / make more sense.  The previous method was based off an early demonstration of doing custom auth which was created by Josh Twist and made use of a table based script to handle both user account registration as well as authenticating and logging users in.  This works fine but now that Mobile Services has Custom APIs which allow you to define functionality for different HTTP methods for a custom endpoint, it seems like this would be a good place to put this functionality.  That’s easy enough, but there is a lot of code for generating a JSON Web Token, creating a HASH, and making a SALT.  Since this code is used in both the login and register functionality, we need to have this code accessible in both places.  Another feature of Mobile Services, shared scripts, helps solve this problem.  Let’s look at that in a bit more detail how we can make authentication a bit easier using these newer capabilities.

Creating a shared script

Turning on script source control is a very easy process once you have a Mobile Service.  Go to the Dashboard tab for your Mobile Service and after a few seconds, you’ll see a link to Set up source control on the right side under quick glance:

Setting up script source control

Once you’ve done that, you’ll be taken to the Configure tab where you can see the URL for your Mobile Service’s GIT repository as well as a URL you can use to trigger a deployment (just go to the URL in the browser).  Once you’ve cloned the GIT repository locally, you can then edit all of your scripts (table, custom api, and scheduler scripts) as well as create and modify shared scripts.  These shared scripts allow you to define functionality which you can then pull into any of your other scripts.  In this case, we’re going to take the createSalt, hash, zumoJwt, and slowEquals methods and put them all into a shared script file (called jwthelper.js for LensRocket).  Not all of these methods are used in both the login and register methods but it’s a good place to put all this similar code:

Note that we’re going to pass the master key into this script when it’s needed.  If we wanted to we could also pull the master key value directly into this script by requiring the mobileservice-config module and using that to access the masterKey property.  One difference I had to make in the midst of working on LensRocket was the addition of an expiration in the JWT creation method.  Expiration is now required.  I didn’t want the users to be kicked out unless they actively logged out so I’m setting the expiration to be sometime in the future (like ten years in the future).  If you wanted users to be more regularly forced to log in, you would just need to alter the expiration to be a (much) smaller value.  Now that I’ve added that file, I can make use of all of those methods from any of my other scripts.

Simplifying our Login and Register

Now that we’ve moved that code to our shared script, our login and register custom APIs become all about the logic and not about the cruft of creating the underlying JWT stuff.  First up is our register API:

The first thing we have is our require line which pulls in our shared script.  From there, we get to our actual Register method.  We first check that the length of the password is at least 7 characters and then that the email address used doesn’t already exist.  You could do any other sort of password validation (i.e. at least X different types of characters) here.  Once we know everything is good we can generate a JWT, save our account data, and send it back to the calling application.  For logging in, pull out the record that matches the username / email address sent in and then compare the password hash against the one saved.  Finally we create a JWT and hand it back:

Summary

Today we saw how shared scripts help simplify the functionality in our Mobile Service scripts.  We also saw how we can use Custom APIs to simplify the design of our backend and avoid using table scripts as virtual endpoints.  As more features are added to Mobile Services you’ll see even more elegant solutions to problems like Custom Auth.  You can check out both the Android client code and the server side scripts for LensRocket here.


Chris Risner


17 Comments

Giacomo

hi, first of all, thanks for your useful posts!
i'm new on azure and zumo auth (testing it on WinStore app with c# backend easy to learn/develop/debug...)
i want a "custom" auth (no fb,google,etc...) but i'm having some troubles .

starting i've tried fb auth, which send me a token, so saved it and in second run replaced the fbAuth call, with the construction of new user and assigning it the "copied" token, its all ok...

then trying your (or josh!?) method for custom auth,
i've generated a jwt (just for test, copied/pasted it in a webapi on new js azure mobile project... and also tried locally some c# "ports" of your code... like http://social.msdn.microsof...
but then using the custom generated one, it doesn't work , i receive an exception still on client parsing/reading jwt i think while preparing the "request"!
on: Newtonsoft.Json.Linq
public static JToken Parse(string json)
where the json string that arrive is "", and then it generates an excpetion...

the first thing that i note is that custom jwt generated is very shorter then the "FB-jwt" in the second section!
fb one is around 617, the custom one just 131/136 (both js/c#).

is it normal? could you confirm it?
or could you help me to understand where i'm wrong...

many thanks Giacomo

Chris

Can you link me to a gist of what your code looks like on the client side and an example of what your generated JWT looks like?

Timmy

Giacomo, did you manage to get this solved or find a good walkthrough for custom authentication using a .net backend? I'm having a real hard time finding out exactly what I am supposed to return to integrate with the rest of the mobile service authentication infrastructure... thanks!!

Giacomo

hi! now i'm working on other things

but i had my custom jwt in c# with that code, hope helpful for you...

string privateKey = yourAzureMasterkey;

var issueTime = DateTime.Now;

var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

var exp = (int)issueTime.AddMinutes(60).Subtract(utc0).TotalSeconds;

var payload = new

{

exp = exp,

iss = "urn:microsoft:windows-azure:zumo",

ver = 1,

aud = "urn:microsoft:windows-azure:zumo",

uid = "custom:123456"

};

using System;

using System.Collections.Generic;

using System.IdentityModel.Tokens;

using System.Linq;

using System.Security.Cryptography;

using System.ServiceModel.Security.Tokens;

using System.Text;

using System.Threading.Tasks;

namespace ConsoleApplicationNotifiche

{

class MyJwtGiorgio

{

public static string getToken(string privateKey, string uid)

{

var jwtSecurityTokenHandler = new System.IdentityModel.Tokens.JwtSecurityTokenHandler();

byte[] signingKey = GetSigningKey(privateKey);

BinarySecretSecurityToken binarySecretSecurityToken = new BinarySecretSecurityToken(signingKey);

var signingCredentials = new SigningCredentials(

new InMemorySymmetricSecurityKey(binarySecretSecurityToken.GetKeyBytes()),

"http://www.w3.org/2001/04/x...",

"http://www.w3.org/2001/04/x...");

var claim_list = new List<system.security.claims.claim>();

claim_list.Add(new System.Security.Claims.Claim("uid", uid));

var jwttoken = jwtSecurityTokenHandler.WriteToken(new System.IdentityModel.Tokens.JwtSecurityToken(

"urn:microsoft:windows-azure:zumo",

"urn:microsoft:windows-azure:zumo",

claim_list,

new System.IdentityModel.Protocols.WSTrust.Lifetime(DateTime.Now, DateTime.Now.AddYears(1)),

signingCredentials)

);

return jwttoken.ToString();

}

private static byte[] GetSigningKey(string secretKey)

{

if (string.IsNullOrEmpty(secretKey))

{

throw new ArgumentNullException("secretKey");

}

UTF8Encoding uTF8Encoding = new UTF8Encoding(true, true);

byte[] bytes = uTF8Encoding.GetBytes(secretKey + "JWTSig");

byte[] result = null;

using (SHA256Managed sHA256Managed = new SHA256Managed())

{

result = sHA256Managed.ComputeHash(bytes);

}

return result;

}

}

}

Matheus Lustosa

Hey Chris,

First of all thank you so much for this article, it was very useful for our team to add custom authentication to our back-end.

Now we are migrating the back-end from NodeJs to .NET and are struggling to replicate this hashing mechanism. I mean, we are able to hash new passwords and authenticate new users easily, however, the users that created the account using the NodeJs (your article) algorithm cannot login anymore as the Hash function we are using doesn't return the same Hash for the same Salt and Password. Know what I mean?

Do you have any ideas on how we can do this migration?

Matheus Lustosa

Hello Chris, I did exatcly what the article suggested and it works for creating new accounts but I cannot login with old accounts as the hashing function is different, any ideas?

Matheus Lustosa

Yes, I am using another Mobile Service. I see where you are heading :-)

The thing is that whey I apply the "jwthelper.hash (my .net version)" to get the password that is generated using the plain password and the database user's salt. This generated password is not equals to the user's db password. I'm kind of lost.

Chris

Ahhhhh, so I think this is the issue. One of the parameters to the zumoJwt method is the master key. The same thing is there in the .NET version. In order for auths to be portable between the two services, you need to use the same master key. I don't believe you can set the master key from the portal at this point but you can do it using the Azure CLI (http://chrisrisner.com/Usin.... Try that out and let me know what you find.

Kai Jin

Hi Chris,

Thanks for sharing the information for custom authentication. On the client side, how do you use the token to login the user once you get the response from the server (in Javascript)? All the info I've found was to use an identity provider from the Azure list (AD, Facebook, Google, Twitter, Microsoft Account) like this:

var MobileServiceClient = WindowsAzure.MobileServiceClient;

client = new MobileServiceClient(AZURE_URL, AZURE_APP_KEY);
client.login(
"facebook",
{"access_token": token})
.done(function (results) {
alert("You are now logged in as: " + results.userId);
}, function (err) {
alert("Error: " + err);
});

Then you can manipulate the tables with:

client.getTable('testTable');

But how do you login with a custom authentication that's not in the list of Identity Providers of Azure?

Kai Jin

I have found the answers here:

http://www.thejoyofcode.com...

var client = new Microsoft.WindowsAzure.MobileServices.MobileServiceClient(
"<your-app-url>",
"<your-app-key>");

client.currentUser = {
userId: "Foo:123456789",
mobileServiceAuthenticationToken: "<your-users-jwt>"
};

Chris

As noted at the top, this post is out of date as Mobile Services has been transitioned to Azure App Service Mobile Apps. You can still get access to an App Service's signing key which you can use similarly to how the master key is used above. Read more about it here: https://shellmonger.com/201...

Leave a Comment