Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

A Better Approach for Consuming Authorized Back-End Services while Transparently Handling Refresh Tokens Renewals for C#/Xamarin Apps

3.00/5 (1 vote)
30 Sep 2020CPOL4 min read 8.7K  
How to consume authorized back-end services while transparently handling refresh token renewals
In this post, you will see a solution wherein I have created a Xamarin.Forms service class called RESTService that is responsible for handling WebAPIs calls. The main purpose of this class is given. You will see a sample code for Xamarin and also learn how to use the code.

Most of the time, we deal with back-end service on our mobile (client) apps for consuming Microservices such as ASP .NET Core Web APIs.

Calling these resources without authentication is fairly easy, as you don’t have to worry either with Bearer-Tokens (JWT), or Refresh-Tokens, all you need is to make a simple httpclient request, for instance:

JavaScript
using (var client = new HttpClient())
 {
     var responseMessage = await client.GetAsync(URL);

     responseMessage.EnsureSuccessStatusCode();

     var jsonResponse = await responseMessage.Content.ReadAsStringAsync();

     var response = JsonConvert.DeserializeObject<IEnumerable<PersonInfo>>(jsonResponse);

     return response;
 }

In the above code, we are just making an HttpClient request to a WebAPI and reading back the data. Note that we are not authenticating by passing any JWT (Bearer Token) nor handling token expirations and http request retries.

Handling Bearer Token Renewals using Refresh Tokens

For security reasons, a Bearer Token aka JWT (JSON Web Token) does not last forever and when they expire, we must obtain a new one for being able to communicate with the back end services.

There are two ways for doing this:

  1. Forcing your user to re authenticate / sign-in again, or
  2. Using your existing Refresh Token to retrieve a new Bearer Token + Refresh Token pair.

As the first option is annoying to the user, we will be covering the second one in this post today.

A typical workflow for consuming WebApi while dealing with Bearer-Token (JWT) / Refresh Tokens renewals during calls look similar to this:

The workflow above works perfectly for single async-tasks calls.

If you raise multiple async-task calls at the same time and your Bearer-Token expires during these calls, all of your calls would try to independently renew the token by using the Refresh-Token they have, and they will all fail.

In this scenario, you have to implement some kind of semaphore to allow only the very first async-task to perform the tokens’s renewals while the other async-tasks awaits for the renewal to finish.

The Solution

I’ve created a Xamarin.Forms service class called RESTService that is responsible for handling WebAPIs calls, these classes can be found in the Xamarin Forms project in the sample code available on my Github.

The main purpose of this class is:

  1. Authenticate on your back-end service
  2. Execute any HttpClient call (GET/POST/PUT/DELETE) you write to consume your WebAPIs
  3. Gracefully handle JWT Expirations
  4. Transparently force renewal of Access Token / JWT / Bearer Token
  5. Synchronize the execution of multiple async-tasks when renewing tokens
  6. Resume your WebAPI call right after a token renewal

Sample Code for Xamarin

On my Github, you can download the whole sample/working solution in C# which is composed of a Xamarin.Forms project and a Back-End project in ASP.NET Core.

The screenshots below were got from the sample project.

Back-End’s Project Assumptions

  • I will not go deeper on details of the back-end project as it only exists for the sake of demonstration.
  • This back-end project is basically an ASPNET Core 3.1 project which uses In-memory Entity Framework Core, supports JWT/Refresh token and contains two WebApis, one for authentication/Refresh token, and other for demonstration of data being retrieved.
  • For the sake of brevity, I only implemented username/password authentication. If you use social authentication, I think the provided code is a good start point to implement on your own.
  • For testing purposes, I’ve configured the Bearer Token (JWT) to expire every 15 seconds, the Refresh-Token expires every 12 months. Feel free to change it on the back-end project.
  • I’ve hardcoded a user in the Startup.cs of the back-end project, so you must use Username = “test” and Password = “test” for testing purposes.

Using the Code

As I told above, the class RESTService class is available on the sample code, inside the folder “Services” in the Xamarin.Forms shared project.

Authenticating

You must first be authenticated before using RESTService.ExecuteWithRetryAsync(), so let’s start by authenticating through AuthWithCredentialsAsync() method:

JavaScript
var response = await RESTService.AuthWithCredentialsAsync(Username, Password);

if (response.Success)
{
    //Authenticated
}
else
{
    //Authentication Failed
}

On a successful authentication, the Bearer-Token (JWT) and the refresh-token received are stored on local cache, and also accessible through RESTService.BearerToken and RESTService.RefreshToken, so that they can be used later.

Calling Your WebAPI

The RESTService.ExecuteWithRetryAsync() takes a lambda method that should be your own httpclient request to the WebAPI controller you want retrieve/submit data.

JavaScript
return RESTService.ExecuteWithRetryAsync(async () =>
{
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("Authorization", $"bearer {RESTService.BearerToken}");

        var responseMessage = await client.GetAsync(URL);

        responseMessage.EnsureSuccessStatusCode();

        var jsonResponse = await responseMessage.Content.ReadAsStringAsync();

        var response = JsonConvert.DeserializeObject<IEnumerable<PersonInfo>>(jsonResponse);

        return response;
    }
});

A couple of notes:

  • The current RESTService.BearerToken should be provided in the Header (line 5) of your own httpclient request.
  • You should always use EnsureSuccessStatusCode() method (line 9) so that in case of an expired Bearer-Tokens (JWT), an HttpRequestException is thrown and internally handled to start the renewal of tokens by using RefreshToken.

That's it.

Hope you enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)