users

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package users manages operator identities + API keys. It issues a per-user bearer key (shown once), authenticates a presented token by its hash, and seeds a bootstrap admin from SYNAPSE_API_TOKEN so existing deployments keep working and historical "operator" attribution stays valid.

Index

Constants

View Source
const BootstrapID = "operator"

BootstrapID is the stable id of the bootstrap admin. Historical actions were attributed to "operator", so the bootstrap user owns that id and history stays coherent ("who did this?" resolves to the bootstrap admin, not a dangling string).

Variables

This section is empty.

Functions

func HashToken

func HashToken(token string) string

HashToken returns the lowercase-hex SHA-256 of a bearer token (the only form stored or compared). Exported so the auth resolver and tests agree on the format.

Types

type Actor added in v0.2.0

type Actor struct {
	ID       string
	TenantID string
}

Actor is the authenticated caller of a user-management action. It carries the caller's own tenant, which is the tenant every action is confined to.

type Service

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

Service manages users + authentication.

func NewService

func NewService(repo ports.UserRepository, audit ports.AuditLogger, clock ports.Clock, ids ports.IDGenerator) (*Service, error)

NewService validates dependencies and returns the users service.

func (*Service) Authenticate

func (s *Service) Authenticate(ctx context.Context, token string) (*user.User, error)

Authenticate resolves a presented bearer token to its (enabled) user, or an error.

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, actor Actor, tenantID string, name string, role user.Role) (*user.User, string, error)

CreateUser provisions a new operator and returns the raw API key ONCE (it is never recoverable afterwards). tenantID is assigned server-side by the admin provisioning the user (never from the new user's own token) and must be the actor's own tenant unless the actor is the platform admin; empty means the actor's tenant, so a single-tenant admin keeps creating users with no ceremony. The tenant the user lands in is what scopes every read/write they later make, so it is captured in the audit record. Audited.

func (*Service) EnsureBootstrapAdmin

func (s *Service) EnsureBootstrapAdmin(ctx context.Context, token string) error

EnsureBootstrapAdmin idempotently makes the bootstrap admin (id "operator") whose key is the env SYNAPSE_API_TOKEN, so the existing token keeps authenticating – now as a real, admin user. Safe to call on every startup.

func (*Service) List

func (s *Service) List(ctx context.Context, actor Actor) ([]*user.User, error)

List returns the users of the actor's own tenant (the hash is on the struct; the adapter must not serialize it). No caller, the platform admin included, lists another tenant's roster.

func (*Service) RotateAPIKey added in v0.2.0

func (s *Service) RotateAPIKey(ctx context.Context, actor Actor, id shared.ID) (*user.User, string, error)

RotateAPIKey issues a new API key for a user in the actor's tenant and returns it ONCE. The previous key stops authenticating immediately, which is how a leaked key is revoked from the product. Audited; the key itself never reaches the audit log. A disabled user may be rotated — rotation invalidates the old credential whether or not the account is currently usable.

func (*Service) SetDisabled added in v0.2.0

func (s *Service) SetDisabled(ctx context.Context, actor Actor, id shared.ID, disabled bool) (*user.User, error)

SetDisabled turns a user's credentials off or back on inside the actor's tenant. Disabling is the revocation the product offers instead of deletion: the identity, and therefore every past attribution, is preserved while authentication stops. Disabling the tenant's last enabled admin is refused, else nobody could administer the tenant afterwards. Audited.

func (*Service) SetTransactionRunner added in v0.2.0

func (s *Service) SetTransactionRunner(transactions ports.TenantTransactionRunner)

SetTransactionRunner makes the last-admin guard atomic against a concurrent second mutation. Without it the count and the write commit separately, and the roster can change in between.

func (*Service) Update added in v0.2.0

func (s *Service) Update(ctx context.Context, actor Actor, id shared.ID, name string, role user.Role) (*user.User, error)

Update changes a user's display name and role inside the actor's tenant. An empty name or role leaves that field unchanged, so a caller can rename without knowing the current role. Demoting the tenant's last enabled admin is refused, else the tenant would be left unmanageable. Audited.

Jump to

Keyboard shortcuts

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