JWT Authentication in .NET MAUI: A Step-by-Step Guide

In modern mobile apps, security is paramount, and authentication plays a vital role in protecting user data. One widely used method of secure authentication is JWT (JSON Web Token). In this blog post, we will walk through implementing JWT authentication in a .NET MAUI application using an example project.

The goal is to authenticate a user by retrieving a JWT token from the backend and then using that token to fetch protected data.

What is JWT?

JWT is a compact, URL-safe token used for securely transmitting information between parties. The token is signed by the server, ensuring the data cannot be tampered with. After successful login, a JWT token is generated and sent to the client, who then includes the token in the Authorization header for subsequent requests.

The Project Structure

This example will show how to authenticate a user using JWT in .NET MAUI by calling a backend API.

Main Components

  • MainPage.xaml: Defines the UI layout for authentication.
  • MainPage.cs: Contains the logic to handle user interaction and API calls.
  • RestService.cs: A helper class for making HTTP calls.

Step 1. UI Layout (MainPage.xaml)

Here’s the XAML for the page that allows users to authenticate and view the results.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Mauitemp.PageTwo"
             Title="PageTwo">
    <VerticalStackLayout>
        <Label 
            Text="JWT Authentication Demo"
            VerticalOptions="Center" 
            HorizontalOptions="Center"
            FontSize="24"/>
        <Label/>

        <Button Text="Authenticate" Clicked="Button_Clicked" WidthRequest="200"/>
        <Label/>
        <HorizontalStackLayout Spacing="20" HorizontalOptions="Center">
            <Label Text="JWT Token:" TextColor="White" FontSize="24"/>
            <Label x:Name="token1" Text="" TextColor="Red" FontSize="24" MaximumWidthRequest="1100"/>
        </HorizontalStackLayout>
        <Label/>
        <HorizontalStackLayout Spacing="20" HorizontalOptions="Center">
            <Label Text="Response:" TextColor="White" FontSize="24"/>
            <Label x:Name="respo" Text="" TextColor="Red" FontSize="24"/>
        </HorizontalStackLayout>
    </VerticalStackLayout>
</ContentPage>

JWT

In this simple UI

  • The button triggers the authentication process.
  • Labels display the JWT token and the API response after authentication.

Step 2. Handling Button Clicks and API Calls (MainPage.cs)

This is where we handle the button click event, authenticate the user, and retrieve the data using the JWT token.

public partial class PageTwo : ContentPage
{
	private readonly RestService restService;
	public PageTwo()
	{
		InitializeComponent();
	}
    private async void Button_Clicked(object sender, EventArgs e)
    {
		string url = "https://localhost:7261/api/auth/token";
		string url2 = "https://localhost:7261/api/values";
        bool authneeded = false;
        (int statuscode, string content) = await RestService.HTTPCall3(url, "POST", null, authneeded);
		if (statuscode == 200)
		{
            string Token = content;
            if (!string.IsNullOrEmpty(Token))
			{
                authneeded = true;
                (int statuscode1, string content1) = await RestService.HTTPCall3(url2, "GET", Token, authneeded);
				if (statuscode1 == 200)
				{
					string result = content1;
					if(!string.IsNullOrEmpty(result))
					{
                        token1.Text = Token;
                        respo.Text = result;
					}
				}
                else
                {
                    await DisplayAlert("Error", "Failed to retrieve Response data", "OK");
                }
            }
            else
            {
                await DisplayAlert("Error", "Token not retrieved", "OK");
            }
        }
        else
        {
            await DisplayAlert("Error", "Invalid Credentials", "OK");
        }
    }
}

Here’s a breakdown of the logic.

  • Button_Clicked: This method is triggered when the user presses the "Authenticate" button.
    • It makes a POST request to obtain the JWT token.
    • If the authentication is successful, the token is stored and displayed.
    • The app then makes a second request, this time including the token in the header, to fetch protected data from the API.

Step 3. HTTP Call Logic (RestService.cs)

All API communication is handled in the RestService class. This class is responsible for sending requests to the server and managing token-based authentication.

public class RestService
{
    private static readonly HttpClient _client = new HttpClient();
    private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = true
    };
    public static async Task<(int ResultValue, string ResponseContent)> HTTPCall3(string url, string method, object data, bool Auth)
    {
        HttpResponseMessage response;
        string responseContent = string.Empty;
        if (Auth)
        {
            string AuthToken = data.ToString();
            _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
        }
        try
        {
            if (method.ToUpper() == "GET")
            {
                response = await _client.GetAsync(url);
            }
            else if (method.ToUpper() == "POST")
            {
                var jsonData = JsonSerializer.Serialize(data, _serializerOptions);
                var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
                response = await _client.PostAsync(url, content);
            }
            else
            {
                throw new ArgumentException("HTTP method not supported. Use 'GET' or 'POST'.");
            }

            responseContent = await response.Content.ReadAsStringAsync();
            return ((int)response.StatusCode, responseContent);
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"\tERROR: {ex.Message}");
            return (-1, $"Error: {ex.Message}");
        }
    }
}

Demo

The HTTPCall3 method takes care of the following.

  • GET and POST requests.
  • Authorization header for passing the JWT token.
  • Proper error handling and logging.

Conclusion

JWT authentication is an effective method for securing your mobile apps. This example demonstrates how to implement JWT authentication in a .NET MAUI app using RESTful API calls. By following this pattern, you can easily integrate secure user authentication into your mobile applications.

By ensuring that the token is safely handled and attached to each request, you can protect sensitive data and provide a secure experience for users of your app.

Next Recommended Reading Building a login flow with .NET MAUI