go
47 lines · 7 steps
Hashing and verifying passwords with bcrypt in Go
A small auth package that hashes passwords, checks them safely, and knows when a stored hash needs upgrading.
Explained by
highlit
1package auth
2
3import (
4 "errors"
5 "fmt"
6
7 "golang.org/x/crypto/bcrypt"
8)
9
10const minPasswordLength = 8
11
12var (
13 ErrPasswordTooShort = errors.New("password must be at least 8 characters")
14 ErrInvalidCredentials = errors.New("invalid email or password")
15)
16
17func HashPassword(password string) (string, error) {
18 if len(password) < minPasswordLength {
19 return "", ErrPasswordTooShort
20 }
21
22 hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
23 if err != nil {
24 return "", fmt.Errorf("hashing password: %w", err)
25 }
26
27 return string(hash), nil
28}
29
30func VerifyPassword(hash, password string) error {
31 err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
32 if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
33 return ErrInvalidCredentials
34 }
35 if err != nil {
36 return fmt.Errorf("comparing password: %w", err)
37 }
38 return nil
39}
40
41func NeedsRehash(hash string) bool {
42 cost, err := bcrypt.Cost([]byte(hash))
43 if err != nil {
44 return true
45 }
46 return cost < bcrypt.DefaultCost
47}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Sentinel errors let callers distinguish expected failures like bad credentials from unexpected system errors.
- 2Wrapping errors with %w preserves the chain so errors.Is can still match the underlying cause.
- 3Storing bcrypt's cost inside the hash lets you detect and upgrade weak hashes over time.
Related explainers
go
package storage import ( "context"
A SQLite-backed order store in Go
database/sql
sqlite
error-wrapping
Intermediate
7 steps
ruby
require "net/http" require "json" class UrlFetcher
A thread-pool URL fetcher in Ruby
concurrency
thread-pool
queues
Intermediate
8 steps
typescript
import { useState, useCallback } from 'react'; type Todo = { id: string;
Optimistic UI updates in a React hook
optimistic-updates
custom-hooks
error-handling
Intermediate
8 steps
rust
use std::fs::File; use std::io::{self, Read}; use std::path::Path;
Streaming a SHA-256 hash of a file in Rust
hashing
buffered-io
streaming
Intermediate
5 steps
go
package fsutil import ( "io/fs"
Walking a directory tree to find large files in Go
filesystem
recursion
closures
Intermediate
7 steps
go
package middleware import ( "log"
Per-IP rate limiting middleware in Gin
rate-limiting
middleware
concurrency
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/hashing-and-verifying-passwords-with-bcrypt-in-go-explained-go-96d2/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.