Help us shape the future of Go! Take the 2026 Go Developer Survey

apikey

package
v1.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package apikey authenticates requests that present an API key, independent of any login provider. Static keys are configured with a name and a secret; keys issued by the application are looked up by a Resolver. Either way a valid key puts an auth.Identity into the request context.

The Authenticator never logs and never starts goroutines. It is safe for concurrent use.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Authenticator

type Authenticator struct {
	// contains filtered or unexported fields
}

Authenticator turns a presented API key into an auth.Identity. It is safe for concurrent use.

func New

func New(options *Options) (*Authenticator, error)

New validates options and returns an Authenticator; an error names a key by its position in Keys, counting from 1. It does not modify options, and changing them afterwards has no effect.

Example
package main

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/govengers/auth"
	"github.com/govengers/auth/apikey"
)

func main() {
	authenticator, err := apikey.New(&apikey.Options{
		Keys: []apikey.Key{{
			Name:        "ci",
			Secret:      "ci-secret-0123456789",
			Roles:       []string{auth.RoleAdmin},
			Permissions: []auth.Permission{{Resource: "builds", Access: auth.AccessWrite}},
		}},
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	protected := authenticator.Middleware()(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		identity := auth.IdentityFrom(request.Context())
		_, _ = fmt.Fprintln(writer, identity.Subject, identity.Roles, identity.Permissions) // the recorder never fails a write
	}))

	for _, key := range []string{"ci-secret-0123456789", "guess"} {
		request := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/builds", nil)
		request.Header.Set("X-API-Key", key)
		recorder := httptest.NewRecorder()
		protected.ServeHTTP(recorder, request)
		fmt.Print(recorder.Code, " ", recorder.Body.String())
	}
}
Output:
200 ci [admin] [builds:write]
401 {"code":"invalid_api_key","message":"authentication required"}

func (*Authenticator) Middleware

func (a *Authenticator) Middleware() func(http.Handler) http.Handler

Middleware authenticates requests that carry a key and passes the others on untouched. A valid key puts its identity into the request context. An invalid key is answered with 401 JSON (code invalid_api_key) and never falls through to another authenticator; a Resolver failure is answered with 500. Mount it before a session.Guard, which passes requests that already carry an identity, and not in front of a jwt.Verifier middleware: both read "Authorization: Bearer". Every decision is reported to the Observer as Action authenticate.

type Key

type Key struct {
	Name        string            // required, unique, non-empty; becomes Identity.Subject and Username
	Secret      string            // required, at least 16 bytes, no surrounding whitespace; SHA-256 pre-hashed at construction
	Roles       []string          // optional, e.g. auth.RoleAdmin
	Permissions []auth.Permission // optional, each valid (auth.Permission.Validate), e.g. "builds:write"; every identity of the key gets a copy
}

Key is one statically configured API key.

type Options

type Options struct {
	Keys       []Key
	Resolver   Resolver // at least one of Keys and Resolver
	HeaderName string   // default "X-API-Key"; "Authorization: Bearer <key>" is always accepted too
	Observer   auth.Observer
}

Options configure an Authenticator.

type Resolver

type Resolver func(ctx context.Context, key string) (*auth.Identity, error)

Resolver resolves application-issued keys. Unknown or revoked: return an error matching auth.ErrUnauthenticated. A returned identity with empty Provider gets "apikey"; it carries its own Permissions (e.g. a stored read_only level becomes "*:read"). Set Active: the Authenticator does not, and every authorization check but IsAuthenticated refuses an inactive identity (403, Reason auth.ReasonInactive). Any other error is answered as a 500, whatever its kind; only context.Canceled and context.DeadlineExceeded stay detectable in it. Every error's text is reported in Outcome.Err and recorded on the wide event, so it must not repeat the key. It must be safe for concurrent use.

Jump to

Keyboard shortcuts

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