• Home
  • Blazor login example (JWT Token)

Blazor login example (JWT Token)

Hello again in my new experiment tutorial. This time I will show you very very simple example with JWT Authentication in Blazor. So first of all what is Blazor. Blazor is an experimental .NET web framework using C# and HTML that runs in the browser. Yes you heard right C# instead JavaScript that runs in browser. I will not go in details about Blazor here, you can search and find available informations on internet or go directly to https://blazor.net/

So Blazor is still experimental project and maybe not suitable for production apps but let me show you how I build basic Login App in Blazor with JWT Authentication. Before you read any further you must be familiar with some stuff. What I mean is:

* You have Visual Studio (any edition) v15.7 or later. If you are using anything else then at least have knowledge of the dotnet command line.
* you know how to use the Nuget package manager
* You know C# and how to build a basic web project.
* You know what JWT tokens are and why you have chosen to use it 🙂

Here I will not explain in detail how to build full JWT authentication in .NET, we will be using just basic example with hardcoded username and password ( *This approach is not good for real live apps ), and also I will not go in details about Razor, C# and other basic stuff in .NET.

Let’s begin. First you need create basic hosted Blazor project and you can do that from CLI. We will need some Blazor templates so we need to add those. Create some example working directory on your machine and then run:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates::*

As you see you will get some Blazor Templates and next we run this ( to get basic blazor hosted project )

dotnet new blazorhosted -o blazorchrisvz

Open project from your VisualStudio and then you can build and run project. If everything is ok you will get Blazor app when you open http://localhost:5000 (in my case app is runing on port 5000 ). Inside project you will see structure of 3 solutions like this “blazorchrisvz.Client”, “blazorchrisvz.Server” and “blazorchrisvz.Shared”. Most important here is that everything that runs on client machine is inside *.Client sln, and everything that needs to run on server is in *.Server sln, *.Shared sln keeps files that is shared between Client and Server ( we will see that later )

First let’s add some things in our *.Shared sln and also in our *.Server sln. In *.Shared root add User.cs class with Username and Password properties. We will not follow the best practice here because it is only basic example and we will not focus on how to store user in database. Also password will be in plain text in our example hardcoded in repository.

public class User
      {
          public string Username { get; set; }
          public string Password { get; set; }
      }

Next we need to create UserRepository.cs inside root of *.Server sln ( again not best practice but for this example is ok ). We will add 2 test users here.

public class UserRepository
      {
          public List<User> TestUsers;
          public UserRepository()
          {
              TestUsers = new List<User>();
              TestUsers.Add(new User() { Username = "Test1", Password  = "Pass1"});
              TestUsers.Add(new User() { Username = "Test2", Password = "Pass2"});
          }
          public User GetUser(string username)
          {
              try
              {
                  return TestUsers.First(user => user.Username.Equals(username));
              } catch
              {
                  return null;
              }
          }

To start with the actual token task, next you will create a new class in the Models folder, called TokenManager. This will take care of both the creation and the validation of tokens. To use the JWT functionality, you must install a package that offers access to JWT. Just right click on the project in the solution explorer and choose Manage NuGet Packages. Make sure that Browse is selected. Then search for JWT in the search bar and install the System.IdentityModel.Tokens.Jwt package.

Here is my TokenManager class. Again this is not JWT tutorial, this is only basic example

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.IdentityModel.Tokens;

namespace blazorchrisvz.Server.Models
{
    public class TokenManager
    {

        private static string Secret = "3c1cc0fdff2610443a547f1bbce698b5ee643b84274e751612940d613935fbc7";

        public static string GenerateToken(string username)
        {
            byte[] key = Convert.FromBase64String(Secret);
            SymmetricSecurityKey securityKey = new SymmetricSecurityKey(key);
            SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[] {
                      new Claim(ClaimTypes.Name, username)}),
                Expires = DateTime.UtcNow.AddMinutes(30),
                SigningCredentials = new SigningCredentials(securityKey,
                SecurityAlgorithms.HmacSha256Signature)
            };

            JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
            JwtSecurityToken token = handler.CreateJwtSecurityToken(descriptor);
            return handler.WriteToken(token);
        }


        public static ClaimsPrincipal GetPrincipal(string token)
        {
            try
            {
                JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
                JwtSecurityToken jwtToken = (JwtSecurityToken)tokenHandler.ReadToken(token);
                if (jwtToken == null)
                    return null;
                byte[] key = Convert.FromBase64String(Secret);
                TokenValidationParameters parameters = new TokenValidationParameters()
                {
                    RequireExpirationTime = true,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    IssuerSigningKey = new SymmetricSecurityKey(key)
                };
                SecurityToken securityToken;
                ClaimsPrincipal principal = tokenHandler.ValidateToken(token,
                      parameters, out securityToken);
                return principal;
            }
            catch (Exception e)
            {
                return null;
            }
        }

        public static string ValidateToken(string token)
        {
            string username = null;
            ClaimsPrincipal principal = GetPrincipal(token);
            if (principal == null)
                return null;
            ClaimsIdentity identity = null;
            try
            {
                identity = (ClaimsIdentity)principal.Identity;
            }
            catch (NullReferenceException)
            {
                return null;
            }
            Claim usernameClaim = identity.FindFirst(ClaimTypes.Name);
            username = usernameClaim.Value;
            return username;
        }
    }
}

We will be only using GenerateToken method that will generate JWT token for our user. Secret string you can generate with many tools that are available online, basically this is done with HMAC Generator and digest algorithm is SHA256.

Now you can create LoginController.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Threading.Tasks;
using blazorchrisvz.Server.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics.Contracts;
using blazorchrisvz.Shared;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace blazorchrisvz.Server.Controllers
{
    [Route("api/[controller]")]
    public class LoginController : Controller
    {

        [HttpPost]
        public IActionResult Login([FromBody] User user) {
            User u = new UserRepository().GetUser(user.Username);

            if (u == null)
                return Unauthorized();

            bool credentials = u.Password.Equals(user.Password);

            if (!credentials)
                return Unauthorized();

            return Ok(new { token = TokenManager.GenerateToken(user.Username) });

            }
    }
}

Now our server part is ready for test and you can test it through Postman. Run dotnet run and then from Postman send a POST request to http://localhost:5000/api/login/ with this JSON in body

{
"username":"Test1",
"password":"Pass1"
}

If everything is ok you will get 200 Status and token in JSON response

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IlRlc3QxIiwibmJmIjoxNTQyMjkwNTc1LCJleHAiOjE1NDIyOTIzNzUsImlhdCI6MTU0MjI5MDU3NX0.YFvnMhJWlrhcDkNthCOMp_LRb9mLhtudf1OR7UK_pOY"
}

Now it’s time to add Login Page to our *.Client sln so the first thing we will be doing is creating a login.cshtml page within the Pages folder. The markup bellow should be pretty straightforward, especially if you have worked with MVC and Razor before.

@using blazorchrisvz.Shared
@page "/login"
@inject HttpClient Http


<div class="container">
    <h1> Login Example in Blazor by Kristijan Klepač</h1>
    <div class="form-group">
        <label for="username">Username</label>
        <input type="text" name="username" placeholder="Username" class="form-control" bind="@Username" />
    </div>
    <div class="form-group">
        <label for="password">Password</label>
        <input type="password" name="password" placeholder="Password" class="form-control" bind="@Password" />
    </div>
    <button onclick="@SubmitForm">Submit</button>
</div>
@functions {

    public string Username { get; set; } = "";
    public string Password { get; set; } = "";
    public string Token { get; set; } = "";



    private async Task SubmitForm()
    {

        var um = new User
        {
            Username = Username,
            Password = Password
        };

        var response = await Http.PostJsonAsync<object>("http://localhost:5000/api/login/", um);
        Console.WriteLine($"{Username} and {Password}");
        Console.WriteLine(response);
    }

}

Here are explanations of this file.

@using blazorchrisvz.Shared – we are using Shared sln. Inside we have User.cs class (model) that we need which is also used in our *.Server sln. So isn’t that nice, we can share models across both the UI client side and the back end server side!

@page “/login” – this is our route ( in my case http://localhost:5000/login )

@inject HttpClient Http – HttpClient for HTTP requests ( ex. Http.PostJsonAsync)

After that we can see HTML markup and input fields for Username, Password and Submit button.

Below our HTML we need to add a “@functions {}” tag, within this we can add any C# code we like, classes, methods… you name it. To create linked properties to the form I create two properties, one for username and the other for password, then I add a “bind” event to the input html tags which will link the two together in the form of two way binding. Onclick event on Submit button in form will call our SubmitForm method … Next we async Task the SubmitForm method as we will be using the HTTP async methods to call the api/login controller. We create UserModel and pass in the property values. Once this is done using the Console.WriteLine() in the method we should now receive our token from the controller!

When you go to /login and try to submit form with Username:Test1 and Pass1 as Password in Console you will see token value

WASM: {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IlRlc3QxIiwibmJmIjoxNTQyMjk3MjkwLCJleHAiOjE1NDIyOTkwOTAsImlhdCI6MTU0MjI5NzI5MH0.PfkhdhuAw6RWy3V6I4tBXkPh55auur6QOdWfhy7-uB8"}

As you see this is basic example, now you can store this token in your localStorage and then you can use this token anywhere in your app. From my point of view it’s amazing how easy JWT authentication can be done in Blazor.

You can see whole project on my Github here…

Thanks for reading …

Tags: , ,

Copyright by Kristijan Klepač 2018