Sign-in to Mobile Services using custom authentication from a Windows client

UPDATE: I have published a Visual Studio solution that is a .NET backend mobile service with custom authentication plus a universal Windows 8.1 app project. (I cheated a bit with the registration because I didn't want to create a whole new UI, but it should be enough to point you in the right direction for Windows C#.) Just for fun, the service can be converted easily from SQL Database to Azure Table storage.

I spent some time the past few days improving the topic Add custom authentication to your app, which had a few issues—the main one being that we didn’t tell you how to consume the custom authentication endpoints in a client app to sign-in a user. The new section we added describes the steps needed to access the custom authentication endpoints from the client, which are:

  1. Create a sign-in UI to get the username and password.
  2. Create a new registration using the CustomRegistration endpoint.
  3. Sign-in using the CustomLogin endpoint.
  4. Use the returned user ID and authentication token to set the current user for the client.

This guidance we added to the topic is platform agnostic, so it lacks specific code examples. Fortunately, there are other examples of how to call a custom API from the various clients (Carlos’ blog post is still one of the best resources on calling custom APIs). In this post, I show how I did it for a Windows C# app.

Create the custom sign-in UI

The first step is to create a custom UI to supply the username and password, which should be done at runtime (you can cache these credentials, but you need to store them securely using PasswordVault, as shown in this topic).

Because I remember having to create these kinds of sign-in UIs all of the time in the Windows Forms days, I was surprised at how not straightforward it was to create a custom sign-in dialog in a modern Windows app. To me, this demonstrates the benefits of Mobile Services authentication, either client-directed authentication (using Live SDK) or service-directed authentication (which uses the WebAuthentiationBroker class under the covers), both are browser-based authentication so no extra UI is needed.

For my new Windows Store app sign-in UI, I decided to just add a new Grid that overlays the existing UI grid, which contains username and password fields. Here’s the XAML:

 <Grid Name="GridLoginDialog" Background="Black" Visibility="Collapsed" 
      Opacity="0.5" >
    <Grid Width="350" Height="200" Background="White" Opacity="100">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="35" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="60" />
        </Grid.RowDefinitions>
        <TextBlock Name="loginMessage" />
        <TextBlock Grid.Row="1" Grid.Column="0" Text="Username: " 
                   HorizontalAlignment="Right" FontSize="12" 
                   VerticalAlignment="Center"  />
        <TextBox Grid.Row="1" Grid.Column="1" Name="txtUsername" 
                 HorizontalAlignment="Right" FontSize="12" 
                 VerticalAlignment="Center" />
        <TextBlock Grid.Row="2" Grid.Column="0"  Text="Password: "  />
        <PasswordBox Grid.Row="2" Grid.Column="1" Name="txtPassword" 
                     Margin="0,10,22,10" />
        <StackPanel Grid.Column="1" Grid.Row="3"  Orientation="Horizontal">
            <Button Content="Sign in" Width="90" Name="ButtonCustomLogin" 
                    Click="ButtonCustomLogin_Click" />
            <Button Content="Cancel" Width="90" Name="ButtonCancelLogin" 
                    Click="ButtonCancelLogin_Click" />                   
        </StackPanel>
        <ProgressRing Name="LoginProgress" IsActive="false" Grid.Column="0" 
                      Grid.Row="3" HorizontalAlignment="Stretch" 
                      VerticalAlignment="Stretch" Margin="2"/>
    </Grid>          
</Grid>

I added an explicit sign-in button, which when clicked displays my sign-in grid:

 private void ButtonCustomLogin_Click(object sender, RoutedEventArgs e)
{
    // Show the sign-in grid and hide the login button.
    this.GridLoginDialog.Visibility = Visibility.Visible;
    this.ButtonCustomLogin.Visibility = Visibility.Collapsed;

}

Here’s how the UI looks:

image

Google/Bing turned up very little about custom sign-in UI for Windows Store apps, so this is what I came up with. If you know of a better pattern for how to do this, I would love to know about it (please leave me a comment).

Create a new registration

The custom authentication tutorial has you create a CustomRegistration endpoint, which is used to create a new user in the Accounts table. Frankly, this part of the topic makes me the most uneasy, especially since we tell you to set this endpoint to allow anonymous access. (This is the great thing about using identity providers like Facebook and Google with Mobile Services, at least these third-party services already have account provisioning figured out.) I added a note to this section strongly suggesting that you implement some kind of account validation scheme, such as sending a text or email with a confirmation code that the user can enter to complete registration. Or maybe, you make this an endpoint that requires a master key so that only someone with service level access can add accounts.

My client sample doesn’t do registration; I just assume that new account provisioning is done out-of-band, I actually changed the access permissions on my endpoint to [AuthorizeLevel(AuthorizationLevel.Admin)] and add registrations from the API help pages, using the service master key. While I don’t show how to access the CustomRegistration endpoint here, the code you need is nearly identical to the code used to access CustomLogin, which we will look at next.

Sign-in to the CustomLogin endpoint

Assuming that my user account is already provisioned, you just use the supplied username and password to call the CustomLogin API, with a POST request. This is done in the AuthenticateAsync method:

 private async Task<MobileServiceUser> AuthenticateAsync(string username, 
    string password) {           

    // Call the CustomLogin API and set the returned MobileServiceUser
    // as the current user.
    var user = await App.MobileService
        .InvokeApiAsync<LoginRequest, MobileServiceUser>(
        "CustomLogin", new LoginRequest() { 
            UserName = username, 
            Password = password });

    return user;
}

Note that the InvokeApi<T,U> method, which by default calls the endpoint using a POST request, returns a MobileServiceUser object. This works because the shape of the response object returned by the CustomLogin endpoint is the same as the MobileServiceUser class, so the client library is able to deserialize it correctly from the response. Note that the original version of the custom authentication tutorial returned a system-defined LoginResult, which for some reason doesn’t quite match the shape of the client’s user object. When I updated the tutorial, I changed this to instead return a CustomLoginResult object, which does match MobileServiceUser and make it a bit easier to set the current user on the client.

Set the current user on the client

The final thing to do is to set the CurrentUser property on the MobileServiceClient instance to the MobileServiceUser returned by the successful CustomLogin request, as shown in the sign-in button code below:

 private async void ButtonCustomLogin_Click(object sender, RoutedEventArgs e)
{
    if (string.IsNullOrEmpty(txtUsername.Text) 
        || string.IsNullOrEmpty(txtPassword.Password))
    {
        return;
    }

    this.LoginProgress.IsActive = true;

    try
    {
        // Sign-in and set the returned user on the context,
        // then load data from the mobile service.

App.MobileService.CurrentUser = await AuthenticateAsync(this.txtUsername.Text, txtPassword.Password);

         await RefreshTodoItems();
        this.GridLoginDialog.Visibility = Visibility.Collapsed;
    }
    catch (MobileServiceInvalidOperationException ex)
    {
        loginMessage.Text = ex.Message;        
    }
    finally
    {
        ResetLoginUI();
    }
}

Note that setting the current user on the client follows the same basic pattern for caching tokens shown in the client authentication tutorial. Also, I could have set the current user in the AuthenticateAsync method, but I wanted to break out this step for clarity.

With the user set, the Mobile Services client uses the authenticationToken in the current MobileServiceUser to generate the X-ZUMO-AUTH header, which enables access to table controller endpoints that are restricted to only authenticated users.

Yay! It works Smile 

Final thoughts

Having only used the Mobile Service built-in authentication patterns, this was an interesting change of pace. Here are a few things other random things that occurred to me while I worked on this side project….

  • Custom authentication is way harder than using the authentication support built into Azure Mobile Services. But, isn’t that why you are willing to pay a little bit extra for Mobile Services (that and the native client libraries…and push notifications). With the built-in authentiation support, once you get everything configured (which requires almost no code at all) you simply call LoginAsync from the client and you are done.
  • With custom authentication you are on your own. The tutorial we provide for a .NET backend (as well as Josh’s blog post using node.js) are really bare bones, you still need to harden your authentication endpoints, prevent spoofers and fraudulent registrations, etc. To be honest, I’m not really an expert on security programming. If you are, have at it. Maybe you have done this before and feel confident with it. However, if (like me) you are new to this—get an expert to review what you are doing before you go into production with any custom authentication scheme.
  • One of the many benefits of using our Mobile Services client libraries, aside from the ease and convenience, is that they always make requests to your mobile service running in Azure by using HTTPS. This means that InvokeApi will always use an HTTPS request. Using a pure REST call, you need to make sure you are accessing the endpoint using HTTPS.

Anyway, please let us know via Disqus if you have any questions or issues with the Custom Authentication tutorial.

Cheers!

Glenn Gailey