Previous part: Encrypting User Passwords [GamesCatalog] 20
Step 1. When the user wants to use the API, we will authenticate them using a bearer token. To do this, we will create a route where they can authenticate and generate a JWT token.
As a starting point, let’s create the function that will generate the token:

Code
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace Services.Functions
{
public interface IJwtTokenService
{
string GenerateToken(int uid, string email, DateTime expireDt);
int? GetUidFromToken(string token);
}
public class JwtTokenService(string jwtKey) : IJwtTokenService
{
public string GenerateToken(int uid, string email, DateTime expireDt)
{
JwtSecurityTokenHandler tokenHandler = new();
byte[] key = Encoding.ASCII.GetBytes(jwtKey);
SecurityTokenDescriptor tokenDescriptor = new()
{
Subject = new ClaimsIdentity([new Claim("uid", uid.ToString()), new Claim(ClaimTypes.Email, email)]),
Expires = expireDt,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
public int? GetUidFromToken(string token)
{
if (token == null)
return null;
JwtSecurityTokenHandler tokenHandler = new();
byte[] key = Encoding.ASCII.GetBytes(jwtKey);
try
{
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
JwtSecurityToken jwtToken = (JwtSecurityToken)validatedToken;
int uid = int.Parse(jwtToken.Claims.First(x => x.Type == "uid").Value);
return uid;
}
catch
{
throw;
}
}
}
}
With this code, we generate a token with the user’s ID and later retrieve it from the token that will be passed.
Step 2. Right-click on the class and generate a test class:

Code
using Services.Functions;
namespace ServicesTests.Functions
{
[TestClass()]
public class JwtTokenServiceTests
{
//https://generate-random.org/encryption-key-generator?count=1&bytes=32&cipher=aes-256-cbc&string=&password=
private const string JwtKey = "iezfxheYc3rduxaqQ+OXQNkbp0MAfZs4jU/8nU+c3isVuvcOdFPV1TzLDIy9X6oe";
private readonly JwtTokenService _jwtTokenService;
public JwtTokenServiceTests()
{
_jwtTokenService = new JwtTokenService(JwtKey);
}
[TestMethod()]
public void GetUidFromToken_ShouldReturnCorrectUid()
{
int uid = 123;
string email = "[email protected]";
DateTime expireDt = DateTime.UtcNow.AddHours(1);
string token = _jwtTokenService.GenerateToken(uid, email, expireDt);
int? extractedUid = _jwtTokenService.GetUidFromToken(token);
Assert.IsNotNull(extractedUid);
Assert.AreEqual(uid, extractedUid);
}
}
}
Generate any test key—you can use this site to generate a test key and another for use in configuration. With this test created, check if the key is being correctly generated.
Step 3. Insert your key into appsettings.json:

Step 4. In Program.cs, configure the JwtTokenService via DI.

Code
builder.Services.AddScoped<IJwtTokenService, JwtTokenService>(p
=> new JwtTokenService(builder.Configuration["JwtKey"]));
Step 5. After creating our function to generate the token, let's go to UserRepo and create the function that will retrieve the user from the database if they exist:

Code
public async Task<UserDTO?> GetByEmailAndPasswordAsync(string email, string encryptedPassword)
{
using var context = DbCtx.CreateDbContext();
return await context.User.FirstOrDefaultAsync(x
=> x.Email == email && x.Password == encryptedPassword);
}
Right-click and pull this function to the interface.
Step 6. Let's create a return model for the token:

Code










Join the conversation! Your thoughts help the community grow.