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
- Variables
- type APIKey
- type CreateKeyRequest
- type EntClientInterface
- type EntStore
- func (s *EntStore) Create(ctx context.Context, key *APIKey, keyHash string) error
- func (s *EntStore) Delete(ctx context.Context, id uuid.UUID) error
- func (s *EntStore) GetByID(ctx context.Context, id uuid.UUID) (*APIKey, error)
- func (s *EntStore) GetByPrefix(ctx context.Context, prefix string) (*APIKey, string, error)
- func (s *EntStore) ListByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)
- func (s *EntStore) ListByOwner(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)
- func (s *EntStore) Update(ctx context.Context, key *APIKey) error
- func (s *EntStore) UpdateLastUsed(ctx context.Context, id uuid.UUID, ip string) error
- type EntStoreConfig
- type Environment
- type GeneratedKey
- type Service
- func (s *Service) Create(ctx context.Context, req CreateKeyRequest) (*GeneratedKey, error)
- func (s *Service) Delete(ctx context.Context, ownerID, id uuid.UUID) error
- func (s *Service) Get(ctx context.Context, ownerID, id uuid.UUID) (*APIKey, error)
- func (s *Service) List(ctx context.Context, ownerID uuid.UUID) ([]*APIKey, error)
- func (s *Service) ListByOrganization(ctx context.Context, orgID uuid.UUID) ([]*APIKey, error)
- func (s *Service) RecordUsage(ctx context.Context, id uuid.UUID, ip string) error
- func (s *Service) Revoke(ctx context.Context, ownerID, id uuid.UUID, reason string) error
- func (s *Service) RevokeInOrganization(ctx context.Context, orgID, id uuid.UUID, reason string) error
- func (s *Service) Validate(ctx context.Context, key string) (*APIKey, error)
- func (s *Service) ValidateWithScope(ctx context.Context, key, scope string) (*APIKey, error)
- type ServiceConfig
- type Store
Constants ¶
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 ¶
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 ¶
HasAllScopes returns true if the key has all of the given scopes.
func (*APIKey) HasAnyScope ¶
HasAnyScope returns true if the key has any of the given scopes.
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) GetByPrefix ¶
GetByPrefix retrieves a key by its prefix.
func (*EntStore) ListByOrganization ¶
ListByOrganization lists all keys for an organization.
func (*EntStore) ListByOwner ¶
ListByOwner lists all keys for a user.
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 ¶
Delete permanently removes an API key owned by ownerID. A key owned by anyone else is reported as ErrKeyNotFound.
func (*Service) Get ¶
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) ListByOrganization ¶
ListByOrganization retrieves all keys for an organization.
func (*Service) RecordUsage ¶
RecordUsage updates the last used timestamp and IP.
func (*Service) Revoke ¶
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.
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.