apikeys

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package apikeys adds machine credentials to Auth-All.

A key authenticates through the Authorization header, so a host route under RequireAuth or under a role check accepts it with no change.

k := apikeys.New(apikeys.Prefix("ak_"), apikeys.MaxTTL(365*24*time.Hour))
auth, err := authall.New(authall.WithStore(s), authall.WithPlugins(r, k))

The plaintext key exists one time, in the response of the create route. The store keeps the SHA-256 digest.

Index

Constants

View Source
const DefaultPrefix = "ak_"

DefaultPrefix starts every generated key.

View Source
const DefaultTouchInterval = 60 * time.Second

DefaultTouchInterval limits how often a key request writes the last use time.

View Source
const ID = "apikeys"

ID is the stable plugin identifier.

Variables

This section is empty.

Functions

func HasScope added in v0.7.0

func HasScope(p *plugin.Principal, scope string) bool

HasScope reports whether a principal may use one scope.

A session holds every scope. An API key holds the scopes of its row, and a key of an application that declares no scope passes every check. Any other credential fails the check, because API key scopes do not describe it. A host handler uses authall.PrincipalFrom(ctx).HasScope, which has the same result.

func NewPlaintextKey

func NewPlaintextKey(prefix string) (string, error)

NewPlaintextKey returns one plaintext key with the given prefix. A test uses it to check the shape of a key with no database.

func Table

func Table(o schema.Options) schema.Table

Table returns the key table for the physical schema options.

Types

type CreateInput

type CreateInput struct {
	// UserID is the owner of the key.
	UserID string
	// Name is the label of the owner. It has 1 to 100 characters.
	Name string
	// Role is the role of the key. An empty value takes the role of the owner.
	Role string
	// ExpiresAt ends the key. A nil value means no expiry.
	ExpiresAt *time.Time
	// OrgID names the organization of the key. An empty value creates a key of
	// the whole application.
	OrgID string
	// Scopes names the scopes of the key, separated by a space. An empty value
	// takes the default scopes. The scopes of a key never change after the
	// create.
	Scopes string
}

CreateInput describes a new key.

type Option

type Option func(*Plugin)

Option configures the plugin.

func AdminRole

func AdminRole(name string) Option

AdminRole names the role that can list and revoke the keys of another user. The default is "admin".

func AllowNoExpiry

func AllowNoExpiry() Option

AllowNoExpiry accepts a key with no expiry, even when a maximum lifetime exists.

func DefaultScopes added in v0.7.0

func DefaultScopes(names ...string) Option

DefaultScopes sets the scopes of a key that is created with none, and of a key from before the scope column. Each name must be a declared scope. Without this option such a key holds every declared scope.

func MaxTTL

func MaxTTL(d time.Duration) Option

MaxTTL sets the highest accepted lifetime of a key. A key with no expiry then fails, unless the host allows one with AllowNoExpiry.

func Organizations added in v0.4.0

func Organizations(r OrganizationResolver) Option

Organizations lets a key name an organization. The value is the organizations plugin.

orgs := organizations.New(...)
keys := apikeys.New(apikeys.Organizations(orgs))

func Prefix

func Prefix(value string) Option

Prefix starts every generated key. The default is ak_.

func Scopes added in v0.7.0

func Scopes(names ...string) Option

Scopes declares the scopes that the application knows. A name must match ^[a-z][a-z0-9_:.-]{0,63}$. With no declared scope the plugin refuses a key that asks for a scope, and every scope check passes.

func TouchInterval

func TouchInterval(d time.Duration) Option

TouchInterval limits how often a key request writes the last use time. The default is 60 seconds.

type OrganizationResolver added in v0.4.0

type OrganizationResolver interface {
	// KeyCredential returns the organization, the membership, and the
	// effective statements of one key. It returns an error when the owner
	// holds no active membership of that organization.
	KeyCredential(ctx context.Context, orgID, ownerID, keyRole string) (
		*store.Organization, *store.Membership, []string, error)
	// KnownRole reports whether the organization holds the role.
	KnownRole(ctx context.Context, orgID, role string) (bool, error)
}

OrganizationResolver answers the organization credential of one key. The organizations plugin implements it.

The permissions of an organization key are the intersection of the key permissions and the live permissions of the owner in that organization, so a demoted member keeps no stronger key.

type Plugin

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

Plugin is the API keys plugin.

func New

func New(opts ...Option) *Plugin

New returns the API keys plugin.

func (*Plugin) Claims

func (p *Plugin) Claims(bearer string) bool

Claims implements plugin.CredentialResolver. It reads the shape of the value only, and it makes no database call.

func (*Plugin) Create

func (p *Plugin) Create(ctx context.Context, owner *store.User, in CreateInput) (*store.APIKey, string, error)

Create returns a new key and its plaintext value. The plaintext exists only in this return value.

func (*Plugin) ID

func (p *Plugin) ID() string

ID implements plugin.Plugin.

func (*Plugin) List

func (p *Plugin) List(ctx context.Context, userID string) ([]store.APIKey, error)

List returns every key of one owner. A key from before the scope column shows the scopes that it resolves with.

func (*Plugin) Register

func (p *Plugin) Register(r *plugin.Registry) error

Register implements plugin.Plugin.

func (*Plugin) RequireScope added in v0.7.0

func (p *Plugin) RequireScope(scope string) func(http.Handler) http.Handler

RequireScope returns a middleware that refuses a request with no principal with 401 UNAUTHORIZED, and a key that does not hold the scope with 403 SCOPE_MISSING. It panics when the application declares scopes and the scope is not one of them. Scopes never add a permission: a role check or an organization check beside it still applies.

func (*Plugin) Resolve

func (p *Plugin) Resolve(ctx context.Context, bearer string) (*plugin.Principal, error)

Resolve implements plugin.CredentialResolver.

A revoked key, an expired key, an unknown key, and a key of a disabled owner give one error, so the caller learns nothing about the key.

func (*Plugin) Revoke

func (p *Plugin) Revoke(ctx context.Context, keyID string, actor *store.User, isAdmin bool) error

Revoke ends one key. actor names the user that revokes it.

Jump to

Keyboard shortcuts

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