Published: July 16 2020

ASP.NET Core 3.1 - Hash and Verify Passwords with BCrypt

Tutorial built with ASP.NET Core 3.1

Other versions available:

This is a quick example of how to hash and verify passwords in ASP.NET Core 3.1 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 Core CLI: dotnet add package BCrypt.Net-Next

Visual Studio Package Manager Console: Install-Package BCrypt.Net-Next


Hashing a password in ASP.NET Core

This 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 ASP.NET Core

This 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 an Account Service

Below is an example account service with a Register() method that saves an account with a hashed password and an Authenticate() method that verifies a provided password against the PasswordHash of a saved account.

The service is a simplified version of the account service from a boilerplate api project I posted recently, for more info and to test out the service in a fully functioning project see ASP.NET Core 3.1 - Boilerplate API with Email Sign Up, Verification, Authentication & Forgot Password.

One small thing to note is the using alias directive on the first line (using BC = BCrypt.Net.BCrypt;). This is required to avoid having to use the full path to the class when calling a BCrypt method (e.g. BCrypt.Net.BCrypt.HashPassword()) because the namespace and the class name are both the same (BCrypt). Another way around this is to move the using statement using BCrypt.Net; inside the namespace (namespace WebApi.Services) which would allow you to call BCrypt.HashPassword() directly. I chose the first approach to keep all of my using statements together at the top of the file.

using BC = BCrypt.Net.BCrypt;
using System.Linq;
using WebApi.Entities;
using WebApi.Helpers;
using WebApi.Models.Accounts;

namespace WebApi.Services
{
    public interface IAccountService
    {
        void Register(RegisterRequest model);
        bool Authenticate(AuthenticateRequest model);
    }

    public class AccountService : IAccountService
    {
        private readonly DataContext _context;

        public AccountService(DataContext context)
        {
            _context = context;
        }

        public void Register(RegisterRequest model)
        {
            // create new account object from model
            var account = new Account(model);

            // hash password
            account.PasswordHash = BC.HashPassword(model.Password);

            // save account
            _context.Accounts.Add(account);
            _context.SaveChanges();
        }

        public bool Authenticate(AuthenticateRequest model)
        {
            // get account from database
            var account = _context.Accounts.SingleOrDefault(x => x.Email == model.Email);

            // check account found and verify password
            if (account == null || !BC.Verify(model.Password, account.PasswordHash))
            {
                // authentication failed
                return false;
            }
            else
            {
                // authentication successful
                return true;
            }
        }
    }
}

 


Need Some ASP.NET Core Help?

Search fiverr for freelance ASP.NET Core 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