:::: MENU ::::

Thursday, February 8, 2018

This article will walk you through implementing an authentication system based on OAuth standard. We'll start by registering the user with their email and password. Afterwards, we'll use these credentials to login and get an access_token. We'll then use the access token to invoke protected web services.

Before we start, here are some considerations:

  • The backend will be in ASP.NET and Identity, using the "Individual Accounts" template.
  • The client application will be in Xamarin Forms which will generate iOS, Android and Windows UWP apps.
  • We'll use the Http Client nuget library to create Http requests.
  • To test the web services, we'll use Postman. You can use other tools such as Fiddler or curl

Creating the backend

Visual Studio has a project template with the minimum code required for registering and signing users. We'll use that template to create a new project: File -> New -> Project -> Web -> ASP.NET Web Application (.NET Framework). Give a name to the project, and select Web API. Then click on Change Authentication and choose Individual User Accounts. Then click OK to create the project.

Note: We selected .NET Framework instead of .NET Core because right now there's no template with Individual User Accounts in ASP.NET Core Web API project. That template will be released with ASP.NET Core 2.1. This tutorial should stay applicable as both ASP.NET Core and .NET Framework default templates relies on Identity.  

At this point, Visual Studio generated an ASP.NET project with all the code required to run authentication. The ApplicationUser inherits properties like UserName, Email, PhoneNumber. You can also add other properties (i.e BirthDate or CreatedAt).

Creating the client app

To add a Xamarin Forms project to the solution, right click the solution and go through the following steps:  Add -> New project -> Cross Platform -> Cross Platform App (Xamarin). Give your app a name, then choose Portable Class Library (PCL) and click OK.

This will add 4 projects to the solution: iOS, Android and Windows UWP projects where we can add platform specific code, and a PCL project where we can put the shared code. Here we'll use the PCL project with the HTTP Client Library NuGet package.

Testing and implementing Signup

The AccountController exposes a web service for registering users. It takes a parameter which has the user's email and password.

// POST api/Account/Register  [AllowAnonymous]  [Route("Register")]  public async Task<IHttpActionResult> Register(RegisterBindingModel model)  {      // …code removed for brievety      var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };      IdentityResult result = await UserManager.CreateAsync(user, model.Password);      // …code removed for brievety   }  

To test this web service using Postman, we can create an HTTP request with the following parameters:

Address: http://localhost:Port_Number/api/Account/Register

Verb : POST

Content : json object ({"Email": …})

Content-Type : application/json

To be able to register users from Xamarin app, we'll invoke the Register web service. For that, we add a new class; we typically call this ApiServices. We then add the following code, which will create the HTTP request using the HttpClient object.

public async Task RegisterUserAsync(      string email, string password, string confirmPassword)  {      var model = new RegisterBindingModel      {          Email = email,          Password = password,          ConfirmPassword = confirmPassword      };      var json = JsonConvert.SerializeObject(model);      HttpContent httpContent = new StringContent(json);      httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");      var client = new HttpClient();      var response = await client.PostAsync(          "http://localhost:49563/api/Account/Register", httpContent);  }  

Note: To use the HttpClient object, install the HTTP Client Library nuget package. To do this, right click the PCL project -> Manage Nuget Packages -> Browse, search for it and click Install.

To use the JsonConvert object, install the Newtonsoft.json nuget package.

To use the RegisterBindingModel, copy it from the ASP.NET project to the PCL project.

Testing and implementing Signin

Unlike Register, Signin web service is not shown in AccountController. Instead, its endpoint and configuration are specified in Startup.Auth.cs class:

TokenEndpointPath = new PathString("/Token"),  

We invoke the Signin web service to get an access token by creating an HTTP request:

Address: http://localhost:Port_Number/Token

Verb : POST

Content : key values for UserName, Password and grant_type.

Content-Type : x-www-form-urlencoded

We should have the following request in Postman, which we get as a result a JWT object containing the access token with expiration date and type.

Note: The token here expires in 14 days, that value could be changed from within the Startup.Auth.cs file: AccessTokenExpireTimeSpan = TimeSpan.FromDays(14);

grant_type value should be "password", each OAuth implementation could change these key value pairs.

The equivalent to this call in Xamarin is the following Login method. Note how we are extracting the access_token value from the JWT object:

public async Task LoginAsync(string userName, string password)  {      var keyValues = new List<KeyValuePair<string, string>>      {          new KeyValuePair<string, string>("username", userName),          new KeyValuePair<string, string>("password", password),          new KeyValuePair<string, string>("grant_type", "password")      };      var request = new HttpRequestMessage(HttpMethod.Post,         "http://localhost:49563/Token");      request.Content = new FormUrlEncodedContent(keyValues);      var client = new HttpClient();      var response = await client.SendAsync(request);      var content = await response.Content.ReadAsStringAsync();      JObject jwtDynamic = JsonConvert.DeserializeObject<dynamic>(content);      var accessToken = jwtDynamic.Value<string>("access_token");  }  

Testing and Invoking protected web service

The generated web project already exposes a protected web service (Get method). ASP.NET Identity uses the [Authorize] attribute to protect web services. This means any HTTP request to invoke Get should contain the access_token. Otherwise, the server will return 401 unauthorized. Authorize will verify the validity of the token then pass the request to the Get method.

[Authorize]  public class ValuesController : ApiController  {      // GET api/values      public IEnumerable<string> Get()      {          return new string[] {"value1", "value2"};      }  }  

Now that we have a valid access_token, we can invoke the protected web services by sending it in the Authorisation Header of the HTTP request.

Note: We added the Bearer keyword to the Authorisation value to indicate the type of the access_token. That value was specified in the JWT object as token_type.

The invocation from the code is as follows:

public async Task GetValuesAsync(string access_token)  {      var client = new HttpClient();      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token);      var json = await client.GetStringAsync(          "http://localhost:49563/api/values");      var values = JsonConvert.DeserializeObject<List<string>>(json);  }  

Conclusion

The access_token can be used multiple times, and even if the client app relaunches. This means we need to save the access_token to reuse it during the 14 days default validity period. As it is a simple string, we don't need a database or file. Instead, we use application settings through Xam.Plugins.Settings nuget plugin. This allow us to save data as key value pairs. Reading and writing is as simple as manipulating an object attribute Settings.AccessToken.

For more information, I also have the project available as a GitHub repository here: https://github.com/HoussemDellai/CheapIdeas

And check out the following video tutorials:

OAuth with ASP.NET Identity

Implementing Signup to ASP.NET with Xamarin Forms

Login from Xamarin Forms to ASP.NET Identity

More