basicauth

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package basicauth provides HTTP Basic authentication middleware for the express framework. It challenges unauthenticated requests with a WWW-Authenticate header and rejects invalid credentials with 401. It is the Go analogue of Node middleware such as express-basic-auth or the classic basic-auth helper, packaged as a drop-in express.Handler.

Use this middleware to protect an entire application or a subtree of routes behind a username/password gate without standing up sessions, cookies, or a login page. Because the browser's built-in credential dialog is triggered by the challenge, Basic auth is a good fit for internal tools, staging environments, health dashboards, and machine-to-machine calls where a full authentication flow would be overkill. Mount it with app.Use for a global guard, or attach it to a specific router or path prefix to protect only part of the tree.

Operationally the middleware sits at the front of the chain. On each request it reads the Authorization request header, expects a "Basic <base64>" value, and decodes it into a username and password separated by the first colon. Those credentials are handed to the caller-supplied Options.Verify callback, which is the single source of truth for whether access is granted. When Verify returns true the middleware calls next() and the request proceeds untouched; the credentials are not stored on the request, so downstream handlers that need the identity should capture it inside Verify.

When the header is missing, malformed, not Basic, un-decodable, or Verify returns false (or is nil), the request is short-circuited: the middleware sets a "WWW-Authenticate: Basic realm=..." response header and writes a 401 Unauthorized body, and next() is never invoked. The realm advertised in the challenge comes from Options.Realm and defaults to "Restricted" when empty. All failure modes are treated identically and yield the same 401 so that a caller cannot distinguish "no header" from "wrong password".

Security note: Basic authentication transmits credentials in every request, protected only by base64 encoding, so it must always be layered over TLS. The comparison performed inside Verify is entirely the caller's responsibility; to resist timing attacks, compare secrets with crypto/subtle.ConstantTimeCompare rather than the == operator. Compared with the Node originals, this port keeps the same challenge-and-reject semantics but is deliberately minimal: it does not ship its own user store, does not support the "challenge: false" silent mode, and delegates every credential decision to Verify.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(opts Options) express.Handler

New returns middleware that enforces HTTP Basic authentication. Requests without valid credentials receive a 401 response carrying a WWW-Authenticate challenge.

Example

ExampleNew builds Basic authentication middleware and mounts it in front of a protected route. The Verify callback checks the supplied username and password with crypto/subtle.ConstantTimeCompare so that credential checks do not leak timing information. The example then drives two requests through the application with httptest: one carrying no Authorization header, which is challenged with a 401 and a WWW-Authenticate response header, and one carrying valid "admin:secret" credentials, which reaches the handler and returns 200. The printed output shows both outcomes, demonstrating the challenge-and-reject contract of the middleware.

package main

import (
	"crypto/subtle"
	"encoding/base64"
	"fmt"
	"net/http/httptest"

	"github.com/malcolmston/express"
	"github.com/malcolmston/express/middleware/basicauth"
)

func main() {
	app := express.New()
	app.Use(basicauth.New(basicauth.Options{
		Realm: "example",
		Verify: func(user, pass string) bool {
			okUser := subtle.ConstantTimeCompare([]byte(user), []byte("admin")) == 1
			okPass := subtle.ConstantTimeCompare([]byte(pass), []byte("secret")) == 1
			return okUser && okPass
		},
	}))
	app.Get("/", func(req *express.Request, res *express.Response, next express.Next) {
		res.Send("welcome")
	})

	// A request with no credentials is challenged.
	r1 := httptest.NewRequest("GET", "/", nil)
	w1 := httptest.NewRecorder()
	app.ServeHTTP(w1, r1)
	fmt.Printf("no creds: %d %q\n", w1.Code, w1.Header().Get("WWW-Authenticate"))

	// A request with valid credentials reaches the handler.
	cred := base64.StdEncoding.EncodeToString([]byte("admin:secret"))
	r2 := httptest.NewRequest("GET", "/", nil)
	r2.Header.Set("Authorization", "Basic "+cred)
	w2 := httptest.NewRecorder()
	app.ServeHTTP(w2, r2)
	fmt.Printf("valid creds: %d %q\n", w2.Code, w2.Body.String())

}
Output:
no creds: 401 "Basic realm=\"example\""
valid creds: 200 "welcome"

Types

type Options

type Options struct {
	// Realm is the protection space presented to the client in the
	// WWW-Authenticate challenge. Defaults to "Restricted".
	Realm string
	// Verify reports whether the supplied username and password are valid.
	// It is required.
	Verify func(user, pass string) bool
}

Options configures the Basic authentication middleware.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL