Categorygithub.com/sfomuseum/go-http-auth
modulepackage
0.11.0
Repository: https://github.com/sfomuseum/go-http-auth.git
Documentation: pkg.go.dev

# README

go-http-auth

Go package to provide a simple interface for enforcing authentication in HTTP handlers.

Documentation

Go Reference

Important

This work is nearly settled (at least for a "v1" release) but may still change.

Motivation

The go-http-auth package aims to provide a simple interface for enforcing authentication in Go-based web applications in a way that those applications don't need to know anyt hing about how authentication happens.

// type Authenticator is a simple interface for	enforcing authentication in HTTP handlers.
type Authenticator interface {
	// WrapHandler wraps a `http.Handler` with any implementation-specific middleware.
	WrapHandler(http.Handler) http.Handler
	// GetAccountForRequest returns an `Account` instance  for an HTTP request.
	GetAccountForRequest(*http.Request) (*Account, error)
	// SigninHandler returns a `http.Handler` for implementing account signin.
	SigninHandler() http.Handler
	// SignoutHandler returns a `http.Handler` for implementing account signout.
	SignoutHandler() http.Handler
	// SignupHandler returns a `http.Handler` for implementing account signups.
	SignupHandler() http.Handler
	// SetLogger assigns a `log.Logger` instance.
	SetLogger(*log.Logger)
}

All the web application (specifically its net/http.Handler instances) know is that it has an implementation of the auth.Authenticator interface which exposes a GetAccountForRequest method which returns an auth.Account struct or an error.

// type Account is a struct that defines minimal information for an account.
type Account struct {
	// The unique ID associated with this account.
	Id int64 `json:"id"`
	// The name associated with this account.
	Name string `json:"name"`
}

Account structs are not meant to be accurate reflections of the underlying implementation's account structure but rather a minimalist struct containing on an account name and unique identifier.

Here is a simplified example, with error handling omitted for brevity, that uses the built-in null:// Authenticator implementation (that will always return a Account instance with ID "0"):

package main

import (
     "context"	
     "log"
     "net/http"

     "github.com/sfomuseum/go-http-auth"
)

type HandlerOptions struct {
     Authenticator auth.Authenticator
}

func Handler(opts *HandlerOptions) (http.Handler, error) {

	fn := func(rsp http.ResponseWriter, req *http.Request) {

		acct, err := opts.Authenticator.GetAccountForRequest(req)

		if err != nil {
			switch err.(type) {
			case auth.NotLoggedIn:
				signin_handler := opts.Authenticator.SigninHandler()
				signin_handler.ServeHTTP(rsp, req)
				return

			default:
				http.Error(rsp, "Internal server error", http.StatusInternalServerError)
				return
			}
		}

		log.Printf("Authenticated as %s (%d)\n", acct.Name, acct.Id)
		
		... carry on with handler
	}

	return http.HandlerFunc(fn), nil
}

func main (){

     ctx := context.Background()
     
     authenticator, _ := auth.NewAuthenticator(ctx, "null://")

     handler_opts := &HandlerOptions{
     	Authenticator: authenticator,
     }
     
     handler, _ := Handler(handler_opts)
     handler = authenticator.WrapHandler(handler)
     
     mux := http.NewServeMux()

     mux.Handle("/", handler)

     http.ListenAndServe(":8080", mux)
}

Note the use the of the authenticator.WrapHandler() method. This is a net/http "middleware" handler where implementation-specific logic for checking whether a user is authenticated is expected to happen. That information is expected to be retrievable using the GetAccountForRequest method in the subsequent handlers that WrapHandler serves. The details of how authentication information is stored and retrieved between handlers is left to individual implmentations.

For concrete examples, have a look at the code for the NullHandler and NoneHandler which always return a "null" user and a "not authorized" error, respectively.

# Functions

EnsureAccountHandler is a middleware `net/http` handler that wraps 'next' and ensures that the authenticator.GetAccountForRequest method does not return an error.
NewAuthenticator returns a new `Authenticator` instance configured by 'uri'.
NewNoneAuthenticator implements the Authenticator interface that always returns a "not authorized" error.
NewNullAuthenticator implements the Authenticator interface such that no authentication is performed configured by 'uri' which is expected to take the form of: null://.
NewSharedSecretAuthenticator implements the Authenticator interface to ensure that requests contain a `X-Shared-Secret` HTTP header configured by 'uri' which is expected to take the form of: sharedsecret://{SECRET} Where {SECRET} is expected to be the shared secret passed by HTTP requests.
RegisterAuthenticator registers 'scheme' as a key pointing to 'init_func' in an internal lookup table used to create new `Authenticator` instances by the `NewAuthenticator` method.
Schemes returns the list of schemes that have been registered.

# Constants

SHARED_SECRET_ACCOUNT_ID is the account ID used for `Account` instances when shared secret authentication validates.
SHARED_SECRET_ACCOUNT_NAME is the account name used for `Account` instances when shared secret authentication validates.
SHARED_SECRET_HEADER is the name of the HTTP header to check for "shared secret" authentication.

# Structs

type Account is a struct that defines minimal information for an account.
AccountNotExist defines a well-known error for signaling that a given account does not exist.
type NoneAuthenticator implements the Authenticator interface that always returns a "not authorized" error.
NotAuthorized defines a well-known error for signaling that the request is not authorized.
NotLoggedIn defines a well-known error for signaling that the account is not logged in.
type NullAuthenticator implements the Authenticator interface such that no authentication is performed.
type SharedSecretAuthenticator implements the Authenticator interface to require a simple shared secret be passed with all requests.

# Interfaces

type Authenticator is a simple interface for enforcing authentication in HTTP handlers.

# Type aliases

AuthenticatorInitializationFunc is a function defined by individual authenticator package and used to create an instance of that authenticator.