READ THIS FIRSTUpdate: 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.
I recently had someone come to me with an interesting use case for Windows Azure Mobile Services. They planned to create several different applications, all using Mobile Services. Nothing tricky here. However, what made their case interesting was that they wanted a single datastore for their users. In other words, create one account and then use that same account to login / store data for multiple apps. I’ll first explain why this is complicated and then talk about some solutions.
When using the built in authentication with Mobile Services (Facebook, Google, Microsoft, and Twitter) the hard parts (handling the OAuth dance and generating a token to identify the user) are done for you. Once the user authenticates, the application locally has access to a UserId and any request made to your Mobile Service (through the SDKs) automatically includes that UserId (and an auth token). In the server side scripts, that UserId can be used to save data connected to the user, filter search queries, etc. Prior to actually getting through to the scripting layer though (whether it’s for tables or custom APIs), Mobile Services has a security layer that checks to make sure the authentication token and the UserId match up. If they don’t a 401 is returned to the calling application. In all of the examples I’ve done with custom authentication, the same is true (it’s just more work on the developer’s side in the server side scripting). The way this security layer is able to match up the UserId to the token is that the Master Key for a Mobile Service is used to generate the token. That generation actually uses the UserId. So, on the server side, you can take the User Id that comes in with a request and compare it to what was used to generate the auth token. You can read more about how the token’s (called JSON Web Tokens) are generated in Josh Twist’s article here.
So what’s wrong?
The Master Key is a unique alphanumeric key that is tied to your Mobile Service. Since each specific Mobile Service’s tokens are signed with each specific Mobile Service’s Master Key, the auth token I might get for my user from one service would be different from the token I would get for the same user with another Mobile Service. Meaning that the security check would block access / deny a request made to a Mobile Service other than the one that generated the token! This problem becomes even more serious if you’re doing custom authentication where there isn’t really a concept of the “same user” like there would be if you used the same Facebook or Twitter user credentials to authenticate.
How can we solve this?
There are a few different tactics we can take to get around this issue if we want to have the same users across multiple apps. Let’s look at those different methods.
Just rely on the User Id
If you’re doing auth with Facebook, Google, Microsoft or Twitter accounts, then the User Id you get handed back (in the from of provider : providerId so ex: facebook : 12345678) will be the same no matter which app you authenticate with. So, behind the scenes, I can look at MobileServiceA’s database and MobileServiceB’s database and say “These two users are the same user”. This kind of falls apart when you look at doing custom authentication because you have to build the User Id for custom auth. You could do something clever such as set build the ID based off information the user supplies but then you’re assuming they provide the same info for each provider and that there is no way to fake things. Not exactly safe. Additionally, your users will have to authenticate and grant permission to each individual app. Probably not the experience you’re looking for.
What else can we do?
The approach I recommended them to take ended up being much simpler than I had originally thought. The whole problem with using the same User Id and auth token on multiple Mobile Services was that the security layer would block a request if the User Id and auth token didn’t match up. What if we could prevent this from being an issue? Enter the CLI tools.
Using the same Master Key
One of the great things about the CLI tools is that it’s easier for new features to be added to these than it is for them to be added to the portal. This means that there are some features and capabilities that the CLI has that the portal hasn’t yet received. One such feature is the ability to set the application and master key values. It’s also possible to just regenerate these keys (as it is possible to do in the portal) but setting is only allowed in the CLI (as of writing). What this means is that with the CLI we can set the master key of whatever Mobile Services we want to be the same thing. This means that the security check won’t be an issue because the master keys will match.
What can we do with this?
In the above mentioned person’s case, they wanted to store some information for a user in a single place and then only application (or user-application) specific data in each Mobile Service’s database. Now that we can use the same master key, they can use one single Mobile Service as their user registration and login system as well as to store any user (non-application specific) data. From a client perspective, they would just need to code the ability to register new users and authenticated to the one Mobile Service, and then use that User Id and auth token when talking to any other services. Furthermore, since the user ID will be the exact same across all of the Mobile Services, it’s easy to run any backend jobs that need to touch all of a user’s data. Specifically, this is the command you’d want to use:
azure mobile key set <SERVICENAME> master <NEWVALUE>
Is this dangerous?
Like everything else in development, there are risks everywhere. In this scenario, someone that has access to a user’s account has access across all of the different applications. It’s possible, though a bit more complex, to use different passwords for each app but the same account, however, this reintroduces some of the complexity we were trying to get rid of. The other risk is that the Master Key is not something that you want to spread around too much. When you make a request through the Mobile Service API with the Master Key you’re treated like an Admin user. Now, even with that being said, it doesn’t necessarily mean you can access anything you want. It depends on the permissions set on each table / API as well as what the custom scripts say. Chances are good though that unless you’ve hardened your scripts against Admins having permission to do anything though, it’s risky to lose your Master Key. Using the same Master Key for multiple Mobile Services doesn’t mean you’re more likely to lose the key, it just means there are more applications for a potentially nefarious person to get into if you did accidentally let your key slip out.
Today we looked at how it’s possible to bridge user accounts across multiple Mobile Services. Provided you have a way to ensure a user will have the same ID from one app to another (i.e. getting their Facebook, Google, Microsoft or Twitter ID or making a very intelligent custom auth user ID system) it’s possible to connect users in the backend. However, this system doesn’t offer any ease from the client perspective. Alternatively, using the same Master Key across Mobile Services makes it possible to go from one Mobile Service to another with the same user information.
For anyone else that sees this and has the same question, the command above works just fine on .NET Mobile Services as well. Just enter the name of the service. For whatever reason, those services just don't show up when you list out your services from the CLI.
In the article you stated, "If you’re doing auth with Facebook, Google, Microsoft or Twitter accounts, then the User Id you get handed back (in the from of provider : providerId so ex: facebook : 12345678) will be the same no matter which app you authenticate with.", however, I've found that when authenticating to facebook, the UserId is different, for example, when authenticating from an ASP.NET Web Application and an equivalent Mobile Services hitting using the same app secret and app id. I've also found, for example, when upgrading from Mobile Services 2.0.0-beta-2 to 2.0.0-beta-3, my UserIds changed for all users that authenticated. Have you seen this yourself? It concerns me greatly as we get closer to releasing an app that we want to make available via a native mobile app and an ASP.NET Web Application.