Enhanced users feature in Azure Mobile Services

In the last post I talked about the ability to get an access token with more permissions to talk to the authentication provider API, so we made it that feature more powerful. Last week we released a new update to the mobile services that makes some of that easier. With the new (preview) enhanced users feature, expanded data about the logged in user to the mobile service is available directly at the service itself (via a call to user.getIdentities), so there’s no more need to talk to the authentication provider APIs to retrieve additional data from the user. Let’s see how we can do that.

To opt-in to this preview feature, you’ll need the Command-Line Interface. If you haven’t used it before, I recommend checking out its installation and usage tutorial to get acquainted with its basic commands. Once you have it installed, and the publishing profile for your subscription properly imported, we can start with that. For this blog post, I created a new mobile service called ‘blog20131216’, and as a newly created service, it doesn’t have any of the preview features enabled, which we can see with the ‘azure mobile preview list’ command, which lists the new feature we have:

C:\temp>azure mobile preview list blog20131216
info: Executing command mobile preview list
+ Getting preview features
data: Preview feature Enabled
data: --------------- -------
data: SourceControl No
data: Users No
info: You can enable preview features using the 'azure mobile preview enable' command.
info: mobile preview list command OK

A sample app

Let’s see how the feature behaves before we turn the feature on. As usual, I’ll create a simple app which will demonstrate how this works, and I’ll post it to my blogsamples repository on GitHub, under AzureMobileServices/UsersFeature. This is an all in which we can log in to certain providers, and call a custom API or a table script. Here’s the app:

001-TestApp

The API implementation does nothing but return the result of the call to user.getIdentities in its response.

  1. exports.get = function (request, response) {
  2.     request.user.getIdentities({
  3.         success: function (identities) {
  4.             response.send(statusCodes.OK, identities);
  5.         }
  6.     });
  7. };

And the table script will do the same (bypassing the database):

  1. function read(query, user, request) {
  2.     user.getIdentities({
  3.         success: function (identities) {
  4.             request.respond(200, identities);
  5.         }
  6.     });
  7. }

Now, if we run the app, login with all providers and call the API and table scripts, we get what we currently receive when calling the getIdentities method:

Logged in as Facebook: <my-fb-id>
API result: {
"facebook": {
"userId": "Facebook: <my-fb-id> ",
"accessToken": " <the long access token> "
}
}
Logged out
Logged in as Google: <my-google-id>
Table script result: {
"google": {
"userId": "Google: <my-google-id> ",
"accessToken": " <the access token> "
}
}
Logged out
Logged in as MicrosoftAccount: <my-microsoft-id>
API result: {
"microsoft": {
"userId": "MicrosoftAccount: <my-microsoft-id> ",
"accessToken": " <the very long access token> "
}
}

So for all existing services nothing really changes.

Enabling the users feature

Now let’s see what starts happening if we enable that new preview feature.

Caution: just like the source control preview feature, the users feature cannot be disabled once turned on. I'd strongly suggest you to try the feature in a test mobile service prior to enabling it in a service being used by an actual mobile application.

In the Command-Line interface, let’s enable the users feature:

C:\temp>azure mobile preview enable blog20131216 Users
info: Executing command mobile preview enable
+ Enabling preview feature for mobile service
info: Result of enabling feature:
info: Successfully enabled Users feature for Mobile Service 'blog20131216'
info: mobile preview enable command OK

And just like that (after a few seconds), the feature is enabled:

C:\temp>azure mobile preview list blog20131216
info: Executing command mobile preview list
+ Getting preview features
data: Preview feature Enabled
data: --------------- -------------
data: Users Yes
data: SourceControl No
info: You can enable preview features using the 'azure mobile preview enable' command.
info: mobile preview list command OK

Time now to run the same test as before. And the result is a lot more interesting. For Facebook:

Logged in as Facebook: <my-fb-id>
API result: {
"facebook": {
"id": " <my-fb-id> ",
"username": " <my-facebook-username> ",
"name": "Carlos Figueira",
"gender": "male",
"first_name": "Carlos",
"last_name": "Figueira",
"link": https://www.facebook.com/ <my-facebook-username> ,
"locale": "en_US",
"accessToken": " <the-long-access-token> ",
"userId": "Facebook: <my-fb-id> "
}
}

And Google:

Logged in as Google: <my-google-id>
Table script result: {
"google": {
"family_name": "Figueira",
"given_name": "Carlos",
"locale": "en",
"name": "Carlos Figueira",
"picture": "https://lh3.googleusercontent.com/ <some-path>/<some-other-path>/<yet-another-path>/<and-one-more-path> /photo.jpg",
"sub": " <my-google-id>",
"accessToken": " <the-access-token> ",
"userId": "Google: <my-google-id> "
}
}

And Microsoft:

Logged in as MicrosoftAccount: <my-microsoft-id>
API result: {
"microsoft": {
"id": " <my-microsoft-id> ",
"name": "Carlos Figueira",
"first_name": "Carlos",
"last_name": "Figueira",
"link": "https://profile.live.com/",
"gender": null,
"locale": "en_US",
"accessToken": " <the very long access token> "
"userId": "MicrosoftAccount: <my-microsoft-id> "
}
}

So that’s basically what we get now “for free” with this new feature… One more thing – I didn’t include Twitter in the example, but it works just as well as the other providers: you’ll get information such as the screen name in the user identities.

User.getIdentities change

One thing I only showed but didn’t really talk about: the call to user.getIdentities is different than how it was previously used. It’s a change required to support the new functionality, and the synchronous version may eventually be deprecated. In order to give you more information about the users, we’re now storing that information in a database table, and retrieving that data is something we cannot do synchronously. What we need to change in the scripts then is to pass a callback function to the users.getIdentities call, and when that data is retrieved the success callback will be invoked. Changing the code to comply with the new mode is fairly straightforward, as the code below shows. Here’s the “before” code:

  1. exports.get = function (request, response) {
  2.     var identities = request.user.getIdentities();
  3.     // Do something with identities, send response
  4. }

And with the change we just need to move the remaining of the code to a callback function:

  1. exports.get = function (request, response) {
  2.     request.user.getIdentities({
  3.         success: function (identities) {
  4.             // Do something with identities, send response
  5.         }
  6.     });
  7. }

The synchronous version of user.getIdentities will continue working in mobile services where the users feature is not enabled (since we can’t break existing services), but I strongly recommend changing your scripts to use the asynchronous version to be prepared for future changes.

Wrapping up

As I mentioned this is a preview feature, which means it’s something we intend on promoting to “GA” (general availability) level, but we’d like to get some early feedback so we can better align it with what the customers want. Feel free to give us feedback about this feature and what we can do to improve it.

Comments

  • Anonymous
    December 16, 2013
    What can I say? Awesome stuff.I just wish I had this 6 months ago when i had to write a lot of custom code and add a bunch of libraries to my project to achieve this functionality.In any case,Good job.

  • Anonymous
    December 16, 2013
    Hey Carlos,Awesome stuff that you guys are doing there in AMS :)Just one thing, I was trying out the new user identities with the login scopes that you guys released not to long ago and I came across the issue where the users email is not returned when using their Microsoft account. I have setup the app settings with the following values:MS_MicrosoftScope : wl.basic wl.signin wl.emailsIt use to work with the old user identities. Do you know if this is a know issue?BTW, Facebook seems to work fine.Thanks again

  • Anonymous
    December 17, 2013
    Thanks!@Mauro, yes, that's a bug which we have in our code which should be fixed in an upcoming release. You can see a workaround you can use in the meantime in my answer to your post in the forums at social.msdn.microsoft.com/.../4c89d496-165d-427c-87a5-fbe8f21300a5

  • Anonymous
    December 17, 2013
    @Carlos Thanks so much again Carlos :)

  • Anonymous
    December 18, 2013
    This works great.  Would it be possible to expose the enhanced properties through the api, so there would be something like user.name, etc. rather than the custom api call?

  • Anonymous
    December 18, 2013
    @John, in theory that'd be possible. Currently we don't do that because the user details (such as name) cannot be retrieved directly from the incoming request, so it needs to be retrieved from where it's stored (currently in a database table, but it would be the same if it were in a shared cache, for example) and not all APIs (or table scripts) need that information, so doing it for all calls would cause a performance hit in the "normal" operations. Feel free to file a feature request at our uservoice (mobileservices.uservoice.com) if you think that would be useful.

  • Anonymous
    January 22, 2014
    The comment has been removed

  • Anonymous
    May 21, 2014
    Can enable user feature in Web-UI ? If user feature is enabled then magic table __user is created?

  • Anonymous
    October 29, 2014
    Is this still available. I get an error saying "The name 'Users' does not identify a known preview feature.

  • Anonymous
    October 29, 2014
    @John, it's available in node.js backends, not in the .NET backend.

  • Anonymous
    October 30, 2014
    Will this feature be provided for .Net Backend? If so, any ETA you can share?

  • Anonymous
    October 30, 2014
    Eventually, yes. You can create a feature request under http://aka.ms/amsfeedback (or vote up a request if it already exists) so that the team can prioritize it against other features.

  • Anonymous
    November 23, 2014
    Great post! Unfortunately I am using a .NET backend. Wrong decision I guess...

  • Anonymous
    November 23, 2014
    I couldn't find the feature request, so I have created one: feedback.azure.com/.../6762129-implement-enhanced-users-feature-for-net-backend Please vote!

  • Anonymous
    March 23, 2015
    I'm surprised that this functionality isn't present in a .net backend.  The expected inclusion of this functionality is one of the main reasons why decided to go with Azure Mobile Services.  Having to write custom classes for each provider just to get profie details is tedious.

  • Anonymous
    May 08, 2015
    I noticed that the mandatory migration to Facebook Graph 2.0 causes the facebook identity information to be incomplete or less than what we use to get back. What changes do we need to make on the Azure Configuration and Mobile Client to get this to work again where we could retrieve the user's public profile (especially their profile picture) ?

  • Anonymous
    July 15, 2015
    Enabled the preview option and it doesn't change the data that comes back from user.getIdentities. Even worse, I only get the userId (same as request.user) in each provider property when making the call and no access tokens values in the result. The documentation for the user object (msdn.microsoft.com/.../jj554220.aspx) is also wrong stating that you can get to the access tokens from request.user.accessTokens but that property is always null. This makes it really difficult to implement a custom solution such as the one on your your blog post: blogs.msdn.com/.../getting-user-information-on-azure-mobile-services.aspx How can we get the user details or even the access token so we can call the relevant API's to get the information ourselves? Documentation and various blog posts are all inconsistent and unreliable...