JSON Web Token (JWT) authentication is a widely used authentication method in web development. In this blog post, we will discuss how to implement JWT authentication between an ASP.NET Core backend and a React frontend.
Introduction
JSON Web Token (JWT) is an open standard for creating tokens that securely transmit information between parties. JWT authentication works by generating a token on the server and sending it to the client. The client then stores the token and sends it with subsequent requests to the server for authentication.
Step-by-Step Implementation
1. Setting up the ASP.NET Core Backend
First, we need to set up the ASP.NET Core backend to generate a JWT token. We will use the Microsoft.AspNetCore.Authentication.JwtBearer
package to handle JWT authentication. Here is an example code snippet:
// ConfigureServices method in Startup.cs file
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
In the above code, we are adding JWT authentication to the ASP.NET Core application. We are setting the token validation parameters, such as the issuer, audience, lifetime, and signing key. We are also specifying the JwtBearerDefaults.AuthenticationScheme
as the default authentication scheme.
2. Generating a JWT Token on Login
When a user logs in, the server generates a JWT token and sends it back to the client. Here is an example code snippet:
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginViewModel model)
{
var user = await _userManager.FindByNameAsync(model.Username);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, "Administrator")
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(new { Token = tokenString });
}
return Unauthorized();
}
In the above code, we are generating a JWT token on successful login. We are using the JwtSecurityTokenHandler
class to create a token and the SecurityTokenDescriptor
class to specify the token’s claims and expiration time. We are also specifying the signing key and algorithm. Finally, we are returning the token string to the client.
3. Storing the JWT Token in Local Storage
The client needs to store the JWT token so that it can be sent with subsequent requests to the server for authentication. One way to store the JWT token is to use localStorage
, which is a browser object that allows you to store data. Here is an example code snippet:
// Function to store JWT token on successful login
function setToken(token) {
localStorage.setItem('token', token);
}
// Function to get JWT token
function getToken() {
return localStorage.getItem('token');
}
In the above code, we are using the `localStorage.setItem()` method to store the JWT token in the browser’s local storage. We are using the key `’token’` to identify the token. We are also using the `localStorage.getItem()` method to retrieve the token.
4. Sending the JWT Token with Subsequent Requests
The client needs to send the JWT token with subsequent requests to the server for authentication. We can use the `Authorization` header to send the token. Here is an example code snippet:
// Function to send HTTP requests with JWT token
function fetchWithToken(url, options) {
const token = getToken();
if (token) {
options = {
...options,
headers: {
'Authorization': `Bearer ${token}`
}
};
}
return fetch(url, options);
}
In the above code, we are creating a fetchWithToken()
function that sends HTTP requests with the JWT token. We are retrieving the token from localStorage
using the getToken()
function. We are then adding the token to the Authorization
header in the options
object.
5. Handling Unauthorized Requests
If the JWT token is invalid or expired, the server will return a 401 Unauthorized response. In this case, the client needs to clear the JWT token from localStorage
and redirect the user to the login page. Here is an example code snippet:
// Function to handle unauthorized requests
function handleUnauthorized() {
localStorage.removeItem('token');
window.location.href = '/login';
}
In the above code, we are creating a handleUnauthorized()
function that removes the JWT token from localStorage
and redirects the user to the login page.
Conclusion
In this blog post, we have discussed how to implement JWT authentication between an ASP.NET Core backend and a React frontend. We have covered generating a JWT token on login, storing the token in localStorage
, sending the token with subsequent requests, and handling unauthorized requests. By implementing JWT authentication, you can ensure that only authenticated users can access your application’s resources.