apikey

package
v0.0.12 Latest Latest
Warning

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

Go to latest
Published: Jan 3, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CodeAPIKeyNotFound           = "API_KEY_NOT_FOUND"
	CodeAPIKeyInactive           = "API_KEY_INACTIVE"
	CodeAPIKeyExpired            = "API_KEY_EXPIRED"
	CodeInsufficientScope        = "INSUFFICIENT_SCOPE"
	CodeInsufficientPermission   = "INSUFFICIENT_PERMISSION"
	CodeIPNotAllowed             = "IP_NOT_ALLOWED"
	CodeInvalidKeyFormat         = "INVALID_KEY_FORMAT"
	CodeMaxKeysReached           = "MAX_KEYS_REACHED"
	CodeAPIKeyAlreadyExists      = "API_KEY_ALREADY_EXISTS"
	CodeAPIKeyCreationFailed     = "API_KEY_CREATION_FAILED"
	CodeAPIKeyUpdateFailed       = "API_KEY_UPDATE_FAILED"
	CodeAPIKeyDeletionFailed     = "API_KEY_DELETION_FAILED"
	CodeAPIKeyRotationFailed     = "API_KEY_ROTATION_FAILED"
	CodeAPIKeyVerificationFailed = "API_KEY_VERIFICATION_FAILED"
	CodeInvalidAPIKeyHash        = "INVALID_API_KEY_HASH"
	CodeMissingAppContext        = "MISSING_APP_CONTEXT"
	CodeMissingEnvContext        = "MISSING_ENV_CONTEXT"
	CodeAccessDenied             = "ACCESS_DENIED"
	CodeInvalidRateLimit         = "INVALID_RATE_LIMIT"
)
View Source
const (
	// KeyTypePublishable - Frontend-safe, identifies app, limited operations
	// Can be safely exposed in client-side code (browser, mobile apps)
	// Limited to read-only and session creation operations
	KeyTypePublishable = base.KeyTypePublishable

	// KeyTypeSecret - Backend-only, full administrative privileges
	// Must be kept secret on server-side only
	// Has unrestricted access to all operations
	KeyTypeSecret = base.KeyTypeSecret

	// KeyTypeRestricted - Backend-only, scoped to specific operations
	// Must be kept secret on server-side
	// Access limited to explicitly granted scopes
	KeyTypeRestricted = base.KeyTypeRestricted
)

Variables

View Source
var (
	ErrAPIKeyNotFound           = &errs.AuthsomeError{Code: CodeAPIKeyNotFound}
	ErrAPIKeyInactive           = &errs.AuthsomeError{Code: CodeAPIKeyInactive}
	ErrAPIKeyExpired            = &errs.AuthsomeError{Code: CodeAPIKeyExpired}
	ErrInsufficientScope        = &errs.AuthsomeError{Code: CodeInsufficientScope}
	ErrInsufficientPermission   = &errs.AuthsomeError{Code: CodeInsufficientPermission}
	ErrIPNotAllowed             = &errs.AuthsomeError{Code: CodeIPNotAllowed}
	ErrInvalidKeyFormat         = &errs.AuthsomeError{Code: CodeInvalidKeyFormat}
	ErrMaxKeysReached           = &errs.AuthsomeError{Code: CodeMaxKeysReached}
	ErrAPIKeyAlreadyExists      = &errs.AuthsomeError{Code: CodeAPIKeyAlreadyExists}
	ErrAPIKeyCreationFailed     = &errs.AuthsomeError{Code: CodeAPIKeyCreationFailed}
	ErrAPIKeyUpdateFailed       = &errs.AuthsomeError{Code: CodeAPIKeyUpdateFailed}
	ErrAPIKeyDeletionFailed     = &errs.AuthsomeError{Code: CodeAPIKeyDeletionFailed}
	ErrAPIKeyRotationFailed     = &errs.AuthsomeError{Code: CodeAPIKeyRotationFailed}
	ErrAPIKeyVerificationFailed = &errs.AuthsomeError{Code: CodeAPIKeyVerificationFailed}
	ErrInvalidAPIKeyHash        = &errs.AuthsomeError{Code: CodeInvalidAPIKeyHash}
	ErrMissingAppContext        = &errs.AuthsomeError{Code: CodeMissingAppContext}
	ErrMissingEnvContext        = &errs.AuthsomeError{Code: CodeMissingEnvContext}
	ErrAccessDenied             = &errs.AuthsomeError{Code: CodeAccessDenied}
	ErrInvalidRateLimit         = &errs.AuthsomeError{Code: CodeInvalidRateLimit}
)
View Source
var KeyTypeScopes = map[KeyType][]string{
	KeyTypePublishable: {
		"app:identify",
		"sessions:create",
		"users:verify",
		"public:read",
	},
	KeyTypeSecret: {
		"admin:full",
	},
	KeyTypeRestricted: {},
}

KeyTypeScopes defines default scopes for each key type These are automatically granted based on key type

View Source
var SafePublicScopes = map[string]bool{
	"app:identify":    true,
	"sessions:create": true,
	"sessions:verify": true,
	"users:verify":    true,
	"users:read":      true,
	"public:read":     true,
	"webhooks:verify": true,
}

SafePublicScopes defines scopes that are safe for publishable keys Only these scopes can be granted to pk_ keys

View Source
var ScopeToRBACMapping = map[string]RBACPermission{

	"users:read":   {Action: "view", Resource: "users"},
	"users:write":  {Action: "edit", Resource: "users"},
	"users:create": {Action: "create", Resource: "users"},
	"users:delete": {Action: "delete", Resource: "users"},
	"users:*":      {Action: "*", Resource: "users"},

	"sessions:read":   {Action: "view", Resource: "sessions"},
	"sessions:create": {Action: "create", Resource: "sessions"},
	"sessions:delete": {Action: "delete", Resource: "sessions"},
	"sessions:*":      {Action: "*", Resource: "sessions"},

	"apikeys:read":   {Action: "view", Resource: "apikeys"},
	"apikeys:write":  {Action: "edit", Resource: "apikeys"},
	"apikeys:create": {Action: "create", Resource: "apikeys"},
	"apikeys:delete": {Action: "delete", Resource: "apikeys"},
	"apikeys:*":      {Action: "*", Resource: "apikeys"},

	"organizations:read":   {Action: "view", Resource: "organizations"},
	"organizations:write":  {Action: "edit", Resource: "organizations"},
	"organizations:create": {Action: "create", Resource: "organizations"},
	"organizations:delete": {Action: "delete", Resource: "organizations"},
	"organizations:*":      {Action: "*", Resource: "organizations"},

	"roles:read":   {Action: "view", Resource: "roles"},
	"roles:write":  {Action: "edit", Resource: "roles"},
	"roles:create": {Action: "create", Resource: "roles"},
	"roles:delete": {Action: "delete", Resource: "roles"},
	"roles:*":      {Action: "*", Resource: "roles"},

	"permissions:read":   {Action: "view", Resource: "permissions"},
	"permissions:write":  {Action: "edit", Resource: "permissions"},
	"permissions:create": {Action: "create", Resource: "permissions"},
	"permissions:delete": {Action: "delete", Resource: "permissions"},
	"permissions:*":      {Action: "*", Resource: "permissions"},

	"admin:full":  {Action: "*", Resource: "*"},
	"admin:users": {Action: "*", Resource: "users"},
	"admin:orgs":  {Action: "*", Resource: "organizations"},

	"app:identify": {Action: "identify", Resource: "app"},
	"public:read":  {Action: "view", Resource: "public"},
	"users:verify": {Action: "verify", Resource: "users"},
}

ScopeToRBACMapping maps legacy scope strings to RBAC (action, resource) pairs This enables backward compatibility with existing scopes while migrating to RBAC

Functions

func APIKeyAlreadyExists

func APIKeyAlreadyExists(prefix string) *errs.AuthsomeError

func APIKeyCreationFailed

func APIKeyCreationFailed(err error) *errs.AuthsomeError

CRUD operation errors

func APIKeyDeletionFailed

func APIKeyDeletionFailed(err error) *errs.AuthsomeError

func APIKeyExpired

func APIKeyExpired() *errs.AuthsomeError

func APIKeyInactive

func APIKeyInactive() *errs.AuthsomeError

func APIKeyNotFound

func APIKeyNotFound() *errs.AuthsomeError

API Key lookup errors

func APIKeyRotationFailed

func APIKeyRotationFailed(err error) *errs.AuthsomeError

func APIKeyUpdateFailed

func APIKeyUpdateFailed(err error) *errs.AuthsomeError

func APIKeyVerificationFailed

func APIKeyVerificationFailed(reason string) *errs.AuthsomeError

func AccessDenied

func AccessDenied(reason string) *errs.AuthsomeError

Access control errors

func CheckScopeOrRBAC

func CheckScopeOrRBAC(scopes []string, rbacPermissions []string, requiredAction, requiredResource string) bool

CheckScopeOrRBAC checks if a scope string OR RBAC permission grants access This is the flexible check for backward compatibility

func GenerateSuggestedRole

func GenerateSuggestedRole(scopes []string) string

GenerateSuggestedRole analyzes scopes and suggests appropriate RBAC roles Returns suggested role names based on the scope patterns

func IPNotAllowed

func IPNotAllowed(ip string) *errs.AuthsomeError

Security errors

func InsufficientPermission

func InsufficientPermission(required string) *errs.AuthsomeError

func InsufficientScope

func InsufficientScope(required string) *errs.AuthsomeError

Permission and scope errors

func InvalidAPIKeyHash

func InvalidAPIKeyHash() *errs.AuthsomeError

func InvalidKeyFormat

func InvalidKeyFormat() *errs.AuthsomeError

func InvalidRateLimit

func InvalidRateLimit(rateLimit, maxRateLimit int) *errs.AuthsomeError

func IsSafeForPublicKey

func IsSafeForPublicKey(scope string) bool

IsSafeForPublicKey checks if a scope is safe for publishable keys

func MapScopeToRBAC

func MapScopeToRBAC(scope string) (action, resource string)

MapScopeToRBAC converts a legacy scope string to RBAC action and resource Returns ("", "") if no mapping exists

func MaxKeysReached

func MaxKeysReached(limit int) *errs.AuthsomeError

Limit errors

func MissingAppContext

func MissingAppContext() *errs.AuthsomeError

Context errors

func MissingEnvContext

func MissingEnvContext() *errs.AuthsomeError

Types

type APIKey

type APIKey = base.APIKey

APIKey represents an API key with its metadata (DTO) Updated for V2 architecture: App → Environment → Organization

func FromSchemaAPIKey

func FromSchemaAPIKey(s *schema.APIKey) *APIKey

FromSchemaAPIKey converts a schema.APIKey to APIKey DTO

func FromSchemaAPIKeys

func FromSchemaAPIKeys(keys []*schema.APIKey) []*APIKey

FromSchemaAPIKeys converts multiple schema.APIKey to APIKey DTOs

type Config

type Config struct {
	DefaultRateLimit int           `json:"default_rate_limit"`
	MaxRateLimit     int           `json:"max_rate_limit"`
	DefaultExpiry    time.Duration `json:"default_expiry"`
	MaxKeysPerUser   int           `json:"max_keys_per_user"`
	MaxKeysPerOrg    int           `json:"max_keys_per_org"`
	KeyLength        int           `json:"key_length"`
}

Config holds the API key service configuration

type CreateAPIKeyRequest

type CreateAPIKeyRequest = base.CreateAPIKeyRequest

CreateAPIKeyRequest represents a request to create an API key Updated for V2 architecture

type EffectivePermissions

type EffectivePermissions struct {
	Scopes               []string      `json:"scopes"`                      // Legacy scope strings
	Permissions          []*Permission `json:"permissions"`                 // RBAC permissions
	DelegatedFromCreator bool          `json:"delegatedFromCreator"`        // If creator permissions are included
	ImpersonatingUser    *xid.ID       `json:"impersonatingUser,omitempty"` // If impersonating a user
}

EffectivePermissions represents all permissions that apply to an API key

func (*EffectivePermissions) CanAccess

func (ep *EffectivePermissions) CanAccess(action, resource string) bool

CanAccess checks if effective permissions allow access (scopes OR RBAC)

func (*EffectivePermissions) HasPermission

func (ep *EffectivePermissions) HasPermission(action, resource string) bool

HasPermission checks if effective permissions include a specific action/resource

func (*EffectivePermissions) HasScope

func (ep *EffectivePermissions) HasScope(scope string) bool

HasScope checks if effective permissions include a specific scope

type EnvironmentRepository added in v0.0.5

type EnvironmentRepository interface {
	FindByID(ctx context.Context, id xid.ID) (*schema.Environment, error)
}

EnvironmentRepository provides environment lookup for prefix generation This is a minimal interface to avoid tight coupling with the environment service

type KeyType

type KeyType = base.KeyType

KeyType represents the type of API key

type ListAPIKeysFilter

type ListAPIKeysFilter struct {
	pagination.PaginationParams
	AppID          xid.ID  `json:"appId" query:"app_id"`
	EnvironmentID  *xid.ID `json:"environmentId,omitempty" query:"environment_id"`
	OrganizationID *xid.ID `json:"organizationId,omitempty" query:"organization_id"`
	UserID         *xid.ID `json:"userId,omitempty" query:"user_id"`
	Active         *bool   `json:"active,omitempty" query:"active"`
}

ListAPIKeysFilter represents filter parameters for listing API keys Supports flexible filtering by app, environment, organization, and user

type ListAPIKeysResponse

type ListAPIKeysResponse = pagination.PageResponse[*APIKey]

ListAPIKeysResponse is a type alias for the paginated response

type Permission

type Permission struct {
	ID       xid.ID `json:"id"`
	Action   string `json:"action"`           // e.g., "view", "edit", "delete", "*"
	Resource string `json:"resource"`         // e.g., "users", "posts", "*"
	Source   string `json:"source,omitempty"` // "key", "creator", "impersonation"
}

Permission represents an RBAC permission (simplified DTO)

type RBACPermission

type RBACPermission struct {
	Action   string // e.g., "view", "edit", "create", "delete", "*"
	Resource string // e.g., "users", "sessions", "apikeys", "*"
}

RBACPermission represents a parsed RBAC permission

func ConvertScopesToRBAC

func ConvertScopesToRBAC(scopes []string) []RBACPermission

ConvertScopesToRBAC converts an array of scope strings to RBAC permissions Useful for migrating existing API keys from scopes to RBAC roles

type Repository

type Repository interface {
	// Create/Read operations
	CreateAPIKey(ctx context.Context, key *schema.APIKey) error
	FindAPIKeyByID(ctx context.Context, id xid.ID) (*schema.APIKey, error)
	FindAPIKeyByPrefix(ctx context.Context, prefix string) (*schema.APIKey, error)

	// List with pagination
	ListAPIKeys(ctx context.Context, filter *ListAPIKeysFilter) (*pagination.PageResponse[*schema.APIKey], error)

	// Update operations
	UpdateAPIKey(ctx context.Context, key *schema.APIKey) error
	UpdateAPIKeyUsage(ctx context.Context, id xid.ID, ip, userAgent string) error
	DeactivateAPIKey(ctx context.Context, id xid.ID) error
	DeleteAPIKey(ctx context.Context, id xid.ID) error

	// Count operations
	CountAPIKeys(ctx context.Context, appID xid.ID, envID *xid.ID, orgID *xid.ID, userID *xid.ID) (int, error)

	// Maintenance
	CleanupExpiredAPIKeys(ctx context.Context) (int, error)
}

Repository defines the interface for API key storage operations Following Interface Segregation Principle (ISP) - works with schema types

type Role

type Role struct {
	ID          xid.ID `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

Role represents an RBAC role (simplified DTO)

type RoleRepository

type RoleRepository interface {
	// Role assignment
	AssignRole(ctx context.Context, apiKeyID, roleID xid.ID, orgID *xid.ID, createdBy *xid.ID) error
	UnassignRole(ctx context.Context, apiKeyID, roleID xid.ID, orgID *xid.ID) error
	BulkAssignRoles(ctx context.Context, apiKeyID xid.ID, roleIDs []xid.ID, orgID *xid.ID, createdBy *xid.ID) error
	BulkUnassignRoles(ctx context.Context, apiKeyID xid.ID, roleIDs []xid.ID, orgID *xid.ID) error
	ReplaceRoles(ctx context.Context, apiKeyID xid.ID, roleIDs []xid.ID, orgID *xid.ID, createdBy *xid.ID) error

	// Role queries
	GetRoles(ctx context.Context, apiKeyID xid.ID, orgID *xid.ID) ([]*schema.Role, error)
	HasRole(ctx context.Context, apiKeyID, roleID xid.ID, orgID *xid.ID) (bool, error)
	GetAPIKeysWithRole(ctx context.Context, roleID xid.ID, orgID *xid.ID) ([]*schema.APIKey, error)

	// Permission queries
	GetPermissions(ctx context.Context, apiKeyID xid.ID, orgID *xid.ID) ([]*schema.Permission, error)

	// Creator permissions (for delegation)
	GetCreatorPermissions(ctx context.Context, creatorID xid.ID, orgID *xid.ID) ([]*schema.Permission, error)
	GetCreatorRoles(ctx context.Context, creatorID xid.ID, orgID *xid.ID) ([]*schema.Role, error)
}

RoleRepository interface for RBAC operations on API keys This is implemented by repository.APIKeyRoleRepository

type RotateAPIKeyRequest

type RotateAPIKeyRequest = base.RotateAPIKeyRequest

RotateAPIKeyRequest represents a request to rotate an API key Updated for V2 architecture

type Service

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

Service handles API key operations Updated for V2 architecture: App → Environment → Organization

func NewService

func NewService(repo Repository, auditSvc *audit.Service, cfg Config) *Service

NewService creates a new API key service

func (*Service) AssignRole

func (s *Service) AssignRole(ctx context.Context, apiKeyID, roleID xid.ID, orgID *xid.ID, createdBy *xid.ID) error

AssignRole assigns a role to an API key

func (*Service) BulkAssignRoles

func (s *Service) BulkAssignRoles(ctx context.Context, apiKeyID xid.ID, roleIDs []xid.ID, orgID *xid.ID, createdBy *xid.ID) error

BulkAssignRoles assigns multiple roles to an API key

func (*Service) CanAccess

func (s *Service) CanAccess(ctx context.Context, apiKey *APIKey, action, resource string, orgID *xid.ID) (bool, error)

CanAccess checks if an API key can perform a specific action on a resource This checks both scopes (legacy) and RBAC permissions (new)

func (*Service) CleanupExpired

func (s *Service) CleanupExpired(ctx context.Context) (int, error)

CleanupExpired removes expired API keys

func (*Service) CreateAPIKey

func (s *Service) CreateAPIKey(ctx context.Context, req *CreateAPIKeyRequest) (*APIKey, error)

CreateAPIKey creates a new API key

func (*Service) DeleteAPIKey

func (s *Service) DeleteAPIKey(ctx context.Context, appID, id, userID xid.ID, orgID *xid.ID) error

DeleteAPIKey deletes an API key

func (*Service) GetAPIKey

func (s *Service) GetAPIKey(ctx context.Context, appID, id, userID xid.ID, orgID *xid.ID) (*APIKey, error)

GetAPIKey retrieves an API key by ID

func (*Service) GetEffectivePermissions

func (s *Service) GetEffectivePermissions(ctx context.Context, apiKeyID xid.ID, orgID *xid.ID) (*EffectivePermissions, error)

GetEffectivePermissions computes all effective permissions for an API key This includes: 1. API key's own permissions (scopes + roles) 2. If delegation enabled: creator's permissions 3. If impersonation set: target user's permissions

func (*Service) GetPermissions

func (s *Service) GetPermissions(ctx context.Context, apiKeyID xid.ID, orgID *xid.ID) ([]*Permission, error)

GetPermissions retrieves all permissions for an API key through its roles

func (*Service) GetRoles

func (s *Service) GetRoles(ctx context.Context, apiKeyID xid.ID, orgID *xid.ID) ([]*Role, error)

GetRoles retrieves all roles assigned to an API key

func (*Service) ListAPIKeys

func (s *Service) ListAPIKeys(ctx context.Context, filter *ListAPIKeysFilter) (*ListAPIKeysResponse, error)

ListAPIKeys lists API keys with filtering and pagination

func (*Service) RotateAPIKey

func (s *Service) RotateAPIKey(ctx context.Context, req *RotateAPIKeyRequest) (*APIKey, error)

RotateAPIKey rotates an API key (creates a new key with same settings)

func (*Service) SetEnvironmentRepository added in v0.0.5

func (s *Service) SetEnvironmentRepository(envRepo EnvironmentRepository)

SetEnvironmentRepository sets the environment repository for prefix generation This is set after service initialization to avoid circular dependencies

func (*Service) SetRoleRepository

func (s *Service) SetRoleRepository(roleRepo RoleRepository)

SetRoleRepository sets the role repository (for RBAC integration) This is set after service initialization to avoid circular dependencies

func (*Service) UnassignRole

func (s *Service) UnassignRole(ctx context.Context, apiKeyID, roleID xid.ID, orgID *xid.ID, actorID *xid.ID) error

UnassignRole removes a role from an API key

func (*Service) UpdateAPIKey

func (s *Service) UpdateAPIKey(ctx context.Context, appID, id, userID xid.ID, orgID *xid.ID, req *UpdateAPIKeyRequest) (*APIKey, error)

UpdateAPIKey updates an API key

func (*Service) VerifyAPIKey

func (s *Service) VerifyAPIKey(ctx context.Context, req *VerifyAPIKeyRequest) (*VerifyAPIKeyResponse, error)

VerifyAPIKey verifies an API key and returns the associated key info

type UpdateAPIKeyRequest

type UpdateAPIKeyRequest = base.UpdateAPIKeyRequest

UpdateAPIKeyRequest represents a request to update an API key

type VerifyAPIKeyRequest

type VerifyAPIKeyRequest = base.VerifyAPIKeyRequest

VerifyAPIKeyRequest represents a request to verify an API key

type VerifyAPIKeyResponse

type VerifyAPIKeyResponse = base.VerifyAPIKeyResponse

VerifyAPIKeyResponse represents a response from API key verification

Jump to

Keyboard shortcuts

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