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:
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:
- Forcing your user to re authenticate / sign-in again, or
- 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:
- Authenticate on your back-end service
- Execute any
HttpClient
call (GET
/POST
/PUT
/DELETE
) you write to consume your WebAPIs - Gracefully handle JWT Expirations
- Transparently force renewal of Access Token / JWT / Bearer Token
- Synchronize the execution of multiple async-tasks when renewing tokens
- 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:
var response = await RESTService.AuthWithCredentialsAsync(Username, Password);
if (response.Success)
{
}
else
{
}
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.
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!