.NET 6.0 - Hash and Verify Passwords with BCrypt
Tutorial built with .NET 6.0
Other versions available:
- .NET: .NET 5.0, ASP.NET Core 3.1
- Node: Node.js
This is a quick example of how to hash and verify passwords in .NET 6.0 using the BCrypt.Net-Next
password hashing library which is a C# implementation of the bcrypt
password hashing function.
For more info on the BCrypt.Net-Next password hashing C# library see https://www.nuget.org/packages/BCrypt.Net-Next.
For more info on the underlying bcrypt password hashing function, see https://en.wikipedia.org/wiki/bcrypt.
Installing BCrypt.Net-Next via NuGet
.NET CLI: dotnet add package BCrypt.Net-Next
Visual Studio Package Manager Console: Install-Package BCrypt.Net-Next
Hashing a password in .NET 6.0
The following line of code hashes the password "Pa$$w0rd"
using bcrypt and stores the result in the passwordHash
string variable.
string passwordHash = BCrypt.Net.BCrypt.HashPassword("Pa$$w0rd");
Verify a password against a hash in .NET 6.0
The following line of code verifies the password "Pa$$w0rd"
using bcrypt against the hash stored in the passwordHash
variable.
bool verified = BCrypt.Net.BCrypt.Verify("Pa$$w0rd", passwordHash);
Example usage in a .NET User Service
Below is an example .NET 6.0 user service with a Register()
method that saves a user account with a hashed password and an Authenticate()
method that verifies a provided password against the PasswordHash
of a saved user account. The password is hashed on line 70
and verified on line 41
.
The service is from a .NET API tutorial I posted recently, for more info or to download and test the API locally see .NET 6.0 - User Registration and Login Tutorial with Example API.
namespace WebApi.Services;
using AutoMapper;
using BCrypt.Net;
using WebApi.Authorization;
using WebApi.Entities;
using WebApi.Helpers;
using WebApi.Models.Users;
public interface IUserService
{
AuthenticateResponse Authenticate(AuthenticateRequest model);
IEnumerable<User> GetAll();
User GetById(int id);
void Register(RegisterRequest model);
void Update(int id, UpdateRequest model);
void Delete(int id);
}
public class UserService : IUserService
{
private DataContext _context;
private IJwtUtils _jwtUtils;
private readonly IMapper _mapper;
public UserService(
DataContext context,
IJwtUtils jwtUtils,
IMapper mapper)
{
_context = context;
_jwtUtils = jwtUtils;
_mapper = mapper;
}
public AuthenticateResponse Authenticate(AuthenticateRequest model)
{
var user = _context.Users.SingleOrDefault(x => x.Username == model.Username);
// validate
if (user == null || !BCrypt.Verify(model.Password, user.PasswordHash))
throw new AppException("Username or password is incorrect");
// authentication successful
var response = _mapper.Map<AuthenticateResponse>(user);
response.Token = _jwtUtils.GenerateToken(user);
return response;
}
public IEnumerable<User> GetAll()
{
return _context.Users;
}
public User GetById(int id)
{
return getUser(id);
}
public void Register(RegisterRequest model)
{
// validate
if (_context.Users.Any(x => x.Username == model.Username))
throw new AppException("Username '" + model.Username + "' is already taken");
// map model to new user object
var user = _mapper.Map<User>(model);
// hash password
user.PasswordHash = BCrypt.HashPassword(model.Password);
// save user
_context.Users.Add(user);
_context.SaveChanges();
}
public void Update(int id, UpdateRequest model)
{
var user = getUser(id);
// validate
if (model.Username != user.Username && _context.Users.Any(x => x.Username == model.Username))
throw new AppException("Username '" + model.Username + "' is already taken");
// hash password if it was entered
if (!string.IsNullOrEmpty(model.Password))
user.PasswordHash = BCrypt.HashPassword(model.Password);
// copy model to user and save
_mapper.Map(model, user);
_context.Users.Update(user);
_context.SaveChanges();
}
public void Delete(int id)
{
var user = getUser(id);
_context.Users.Remove(user);
_context.SaveChanges();
}
// helper methods
private User getUser(int id)
{
var user = _context.Users.Find(id);
if (user == null) throw new KeyNotFoundException("User not found");
return user;
}
}
Need Some .NET Help?
Search fiverr for freelance .NET developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!