Published: January 16 2022

.NET 6.0 - Hash and Verify Passwords with BCrypt

Tutorial built with .NET 6.0

Other versions available:

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

On Twitter or RSS.


When I'm not coding...

Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!


Comments


Supported by