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 (17)

  1. Ignacio Fuentes says:

    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.

  2. Mauro Da Silva says:

    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.emails

    It 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

  3. 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

  4. Mauro Da Silva says:

    @Carlos Thanks so much again Carlos 🙂

  5. John Douglas says:

    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?

  6. @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.

  7. Andrew R says:

    Great to see Mobile Services' feature set evolving!

    So it looks like enabling this feature creates a __user table, and that once enabled, authentication doesn't work without it. Whatever AMS is doing behind the scenes populates this tables with new user ids (guids) that has nothing to do with any other existing user account table(s).

    I think this feature is great in concept but it current implementation is a little too 'black box'. It would be amazing to be able to customize the login process on the server (after authentication and before authorization?) to more easily manage user attributes.

  8. Jakub says:
    1. Can enable user feature in Web-UI ?

    2. If user feature is enabled then magic table __user is created?

  9. John says:

    Is this still available. I get an error saying "The name 'Users' does not identify a known preview feature.

  10. @John, it's available in node.js backends, not in the .NET backend.

  11. Ankur says:

    Will this feature be provided for .Net Backend? If so, any ETA you can share?

  12. 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.

  13. ncu says:

    Great post! Unfortunately I am using a .NET backend. Wrong decision I guess…

  14. ncu says:

    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!

  15. Lyndon Hughey says:

    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.

  16. Ted Taliaferro says:

    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) ?

  17. Werner van Deventer says:

    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…