apikey

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package apikey provides API key generation, validation, and management. API keys are used for server-to-server authentication without user interaction.

Index

Constants

View Source
const (
	// DefaultPrefix is the default key prefix.
	DefaultPrefix = "sf"
	// KeyRandomBytes is the number of random bytes in the key.
	KeyRandomBytes = 32
	// PrefixRandomBytes is the number of random bytes in the visible prefix.
	PrefixRandomBytes = 8
)

KeyFormat defines the format of generated API keys. Format: {prefix}_{environment}_{random} Example: sf_live_abc123def456...

Variables

View Source
var (
	ErrInvalidKey      = errors.New("invalid API key")
	ErrKeyNotFound     = errors.New("API key not found")
	ErrKeyExpired      = errors.New("API key expired")
	ErrKeyRevoked      = errors.New("API key revoked")
	ErrInvalidScope    = errors.New("invalid scope")
	ErrScopeNotAllowed = errors.New("scope not allowed")
	ErrTooManyKeys     = errors.New("too many API keys")
)

Common errors.

Functions

This section is empty.

Types

type APIKey

type APIKey struct {
	// ID is the unique identifier.
	ID uuid.UUID `json:"id"`

	// Name is a human-readable name.
	Name string `json:"name"`

	// Prefix is the visible portion of the key.
	Prefix string `json:"prefix"`

	// OwnerID is the user who owns this key.
	OwnerID uuid.UUID `json:"owner_id"`

	// OrganizationID is the org this key is scoped to (optional).
	OrganizationID *uuid.UUID `json:"organization_id,omitempty"`

	// Scopes are the permissions granted to this key.
	Scopes []string `json:"scopes,omitempty"`

	// Description is an optional note.
	Description string `json:"description,omitempty"`

	// Environment is live or test.
	Environment Environment `json:"environment"`

	// ExpiresAt is when the key expires.
	ExpiresAt *time.Time `json:"expires_at,omitempty"`

	// LastUsedAt is when the key was last used.
	LastUsedAt *time.Time `json:"last_used_at,omitempty"`

	// LastUsedIP is the IP that last used the key.
	LastUsedIP string `json:"last_used_ip,omitempty"`

	// Revoked indicates if the key is revoked.
	Revoked bool `json:"revoked"`

	// RevokedAt is when the key was revoked.
	RevokedAt *time.Time `json:"revoked_at,omitempty"`

	// RevokedReason is why the key was revoked.
	RevokedReason string `json:"revoked_reason,omitempty"`

	// Metadata is additional key-value data.
	Metadata map[string]string `json:"metadata,omitempty"`

	// CreatedAt is when the key was created.
	CreatedAt time.Time `json:"created_at"`

	// UpdatedAt is when the key was last updated.
	UpdatedAt time.Time `json:"updated_at"`
}

APIKey represents an API key with its metadata.

func (*APIKey) HasAllScopes

func (k *APIKey) HasAllScopes(scopes ...string) bool

HasAllScopes returns true if the key has all of the given scopes.

func (*APIKey) HasAnyScope

func (k *APIKey) HasAnyScope(scopes ...string) bool

HasAnyScope returns true if the key has any of the given scopes.

func (*APIKey) HasScope

func (k *APIKey) HasScope(scope string) bool

HasScope returns true if the key has the given scope.

func (*APIKey) IsExpired

func (k *APIKey) IsExpired() bool

IsExpired returns true if the key has expired.

func (*APIKey) IsValid

func (k *APIKey) IsValid() bool

IsValid returns true if the key is valid (not expired, not revoked).

type CreateKeyRequest

type CreateKeyRequest struct {
	// Name is a human-readable name (required).
	Name string

	// OwnerID is the user creating the key (required).
	OwnerID uuid.UUID

	// OrganizationID scopes the key to an organization (optional).
	OrganizationID *uuid.UUID

	// Scopes are the permissions to grant (optional).
	Scopes []string

	// Description is an optional note.
	Description string

	// Environment is live or test (default: live).
	Environment Environment

	// ExpiresIn is the key lifetime (optional, nil = never).
	ExpiresIn *time.Duration

	// Metadata is additional key-value data.
	Metadata map[string]string
}

CreateKeyRequest contains parameters for creating an API key.

type EntClientInterface

type EntClientInterface interface {
	// CreateAPIKey stores a new API key.
	CreateAPIKey(ctx context.Context, key *APIKey, keyHash string) error

	// GetAPIKeyByPrefix retrieves a key by its prefix.
	// Returns the key and its hash for validation.
	// Returns ErrKeyNotFound if not found.
	GetAPIKeyByPrefix(ctx context.Context, prefix string) (*APIKey, string, error)

	// GetAPIKeyByID retrieves a key by its ID.
	// Returns ErrKeyNotFound if not found.
	GetAPIKeyByID(ctx context.Context, id uuid.UUID) (*APIKey, error)

	// ListAPIKeysByOwner lists all keys for a user.
	ListAPIKeysByOwner(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)

	// ListAPIKeysByOrganization lists all keys for an organization.
	ListAPIKeysByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)

	// UpdateAPIKey updates key metadata.
	UpdateAPIKey(ctx context.Context, key *APIKey) error

	// DeleteAPIKey permanently removes a key.
	DeleteAPIKey(ctx context.Context, id uuid.UUID) error

	// UpdateAPIKeyLastUsed updates the last used timestamp and IP.
	UpdateAPIKeyLastUsed(ctx context.Context, id uuid.UUID, ip string) error
}

EntClientInterface abstracts the Ent client to avoid import cycles. Apps implement this interface wrapping their generated Ent client.

Example implementation:

type EntClientWrapper struct {
    client *ent.Client
}

func (w *EntClientWrapper) CreateAPIKey(ctx context.Context, key *apikey.APIKey, keyHash string) error {
    _, err := w.client.APIKey.Create().
        SetID(key.ID).
        SetName(key.Name).
        SetKeyHash(keyHash).
        // ... set other fields
        Save(ctx)
    return err
}

type EntStore

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

EntStore implements Store using Ent.

func NewEntStore

func NewEntStore(config EntStoreConfig) (*EntStore, error)

NewEntStore creates a new Ent-backed API key store.

func (*EntStore) Create

func (s *EntStore) Create(ctx context.Context, key *APIKey, keyHash string) error

Create stores a new API key.

func (*EntStore) Delete

func (s *EntStore) Delete(ctx context.Context, id uuid.UUID) error

Delete permanently removes a key.

func (*EntStore) GetByID

func (s *EntStore) GetByID(ctx context.Context, id uuid.UUID) (*APIKey, error)

GetByID retrieves a key by its ID.

func (*EntStore) GetByPrefix

func (s *EntStore) GetByPrefix(ctx context.Context, prefix string) (*APIKey, string, error)

GetByPrefix retrieves a key by its prefix.

func (*EntStore) ListByOrganization

func (s *EntStore) ListByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)

ListByOrganization lists all keys for an organization.

func (*EntStore) ListByOwner

func (s *EntStore) ListByOwner(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)

ListByOwner lists all keys for a user.

func (*EntStore) Update

func (s *EntStore) Update(ctx context.Context, key *APIKey) error

Update updates key metadata.

func (*EntStore) UpdateLastUsed

func (s *EntStore) UpdateLastUsed(ctx context.Context, id uuid.UUID, ip string) error

UpdateLastUsed updates the last used timestamp and IP.

type EntStoreConfig

type EntStoreConfig struct {
	// Client is the Ent client wrapper.
	// Apps must provide a wrapper that implements EntClientInterface.
	Client EntClientInterface
}

EntStoreConfig configures the Ent-backed API key store.

type Environment

type Environment string

Environment represents the API key environment.

const (
	// EnvLive is for production API keys.
	EnvLive Environment = "live"
	// EnvTest is for test/development API keys.
	EnvTest Environment = "test"
)

func ParseEnvironment

func ParseEnvironment(s string) (Environment, error)

ParseEnvironment parses an environment string.

type GeneratedKey

type GeneratedKey struct {
	// Key is the full API key value (only shown once).
	Key string `json:"key"`

	// APIKey is the key metadata.
	APIKey *APIKey `json:"api_key"`
}

GeneratedKey contains a newly created API key with its full value. The full key is only available at creation time.

type Service

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

Service provides API key management operations.

func NewService

func NewService(config ServiceConfig) *Service

NewService creates a new API key service.

func (*Service) Create

func (s *Service) Create(ctx context.Context, req CreateKeyRequest) (*GeneratedKey, error)

Create generates a new API key. The full key is only returned once and cannot be retrieved later.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, ownerID, id uuid.UUID) error

Delete permanently removes an API key owned by ownerID. A key owned by anyone else is reported as ErrKeyNotFound.

func (*Service) Get

func (s *Service) Get(ctx context.Context, ownerID, id uuid.UUID) (*APIKey, error)

Get retrieves a key by ID. The key must belong to ownerID; a key owned by anyone else is reported as ErrKeyNotFound so IDs cannot be probed.

func (*Service) List

func (s *Service) List(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)

List retrieves all keys for a user.

func (*Service) ListByOrganization

func (s *Service) ListByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)

ListByOrganization retrieves all keys for an organization.

func (*Service) RecordUsage

func (s *Service) RecordUsage(ctx context.Context, id uuid.UUID, ip string) error

RecordUsage updates the last used timestamp and IP.

func (*Service) Revoke

func (s *Service) Revoke(ctx context.Context, ownerID, id uuid.UUID, reason string) error

Revoke revokes an API key owned by ownerID. A key owned by anyone else is reported as ErrKeyNotFound.

func (*Service) RevokeInOrganization added in v0.14.0

func (s *Service) RevokeInOrganization(ctx context.Context, orgID, id uuid.UUID, reason string) error

RevokeInOrganization revokes an API key scoped to orgID, for an organization administrator who does not own it. The caller must already have authorized the administrator for orgID. A key scoped to another organization or to none is reported as ErrKeyNotFound.

func (*Service) Validate

func (s *Service) Validate(ctx context.Context, key string) (*APIKey, error)

Validate validates an API key and returns its metadata.

func (*Service) ValidateWithScope

func (s *Service) ValidateWithScope(ctx context.Context, key, scope string) (*APIKey, error)

ValidateWithScope validates a key and checks for a required scope.

type ServiceConfig

type ServiceConfig struct {
	// Store is the key storage backend.
	Store Store

	// Prefix is the key prefix (default: "sf").
	Prefix string

	// AllowedScopes restricts which scopes can be granted. An entry ending in
	// ":*" allows every scope with that prefix. A key requesting a scope that
	// no entry allows is refused, including the wildcard scope "*" unless an
	// entry lists it exactly.
	//
	// If empty, no scopes can be granted unless AllowAnyScope is set: the
	// service cannot know what the caller is entitled to, so an unconfigured
	// service does not hand out arbitrary privilege.
	AllowedScopes []string

	// AllowAnyScope lets keys request any scope when AllowedScopes is empty.
	// Set it only when the caller of Create has already limited the scopes to
	// what its user may hold.
	AllowAnyScope bool

	// MaxKeysPerUser limits the active (unrevoked, unexpired) keys per user
	// (0 = unlimited). The count and the insert are not one atomic step, so
	// concurrent Create calls for one user can exceed the limit by the number
	// in flight; stores that need a hard cap should enforce it themselves.
	MaxKeysPerUser int

	// DefaultExpiry is the default key lifetime.
	DefaultExpiry *time.Duration
}

ServiceConfig contains configuration for the API key service.

type Store

type Store interface {
	// Create stores a new API key.
	Create(ctx context.Context, key *APIKey, keyHash string) error

	// GetByPrefix retrieves a key by its prefix.
	GetByPrefix(ctx context.Context, prefix string) (*APIKey, string, error)

	// GetByID retrieves a key by its ID.
	GetByID(ctx context.Context, id uuid.UUID) (*APIKey, error)

	// ListByOwner lists all keys for a user.
	ListByOwner(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)

	// ListByOrganization lists all keys for an organization.
	ListByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)

	// Update updates key metadata.
	Update(ctx context.Context, key *APIKey) error

	// Delete permanently removes a key.
	Delete(ctx context.Context, id uuid.UUID) error

	// UpdateLastUsed updates the last used timestamp and IP.
	UpdateLastUsed(ctx context.Context, id uuid.UUID, ip string) error
}

Store defines the interface for API key storage.

Jump to

Keyboard shortcuts

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