Help us shape the future of Go! Take the 2026 Go Developer Survey

auth

package
v0.2.12 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: GPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package auth implements core.Auth: it maps the X-Plex-Token a Plex app presents to an Ether user, and keeps the users table with per-user settings (stream limit, content rating cap, languages, sections).

A token is recognised, in order, as

  1. the server's own token (the owner),
  2. a server access token synced from plex.tv for the owner or a friend,
  3. any other plex.tv token, validated against plex.tv (GET /api/v2/user) and checked for access to this server (owner id, synced friend, or the server in that token's resources list).

Results of (3) are cached (positive and negative) so plex.tv is asked at most once per token per TTL; during a plex.tv outage a previously valid token keeps working for StaleTTL.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HashToken

func HashToken(token string) string

HashToken is how tokens are stored: never in plain text.

func StoredIdentity

func StoredIdentity(ctx context.Context, db *sql.DB, id int64) (*core.User, error)

StoredIdentity looks up an import destination without granting access or creating an authentication service. Inactive viewers retain their history.

Types

type Options

type Options struct {
	// Validator checks unknown tokens; nil means only server and synced
	// tokens are accepted.
	Validator Validator
	// CacheTTL is how long a plex.tv-validated token is trusted (15m).
	CacheTTL time.Duration
	// NegativeTTL is how long a rejected token is remembered (2m).
	NegativeTTL time.Duration
	// StaleTTL lets a validated token keep working this long past CacheTTL
	// while plex.tv is unreachable (24h).
	StaleTTL time.Duration
	// MaxCacheEntries bounds the token caches (10000).
	MaxCacheEntries int
	// MaxConcurrentValidations bounds distinct unknown tokens being checked
	// with plex.tv (16). Excess requests fail fast; cached tokens still work.
	MaxConcurrentValidations int
	Logger                   *slog.Logger
	Now                      func() time.Time
}

Options configures the Service.

type PlexTVValidator

type PlexTVValidator struct {
	Client    *plextv.Client
	MachineID string
}

PlexTVValidator is the production Validator.

func (PlexTVValidator) Account

func (v PlexTVValidator) Account(ctx context.Context, token string) (*plextv.Account, error)

Account implements Validator.

func (PlexTVValidator) HasServer

func (v PlexTVValidator) HasServer(ctx context.Context, token string) (bool, error)

HasServer implements Validator.

type Service

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

Service implements core.Auth and plextv.UserSync.

func New

func New(ctx context.Context, db *sql.DB, o Options) (*Service, error)

New loads users and known tokens from db (migrated with store.Migrate).

func (*Service) ActiveUser

func (s *Service) ActiveUser(ctx context.Context, id int64) (*core.User, error)

ActiveUser returns a current access snapshot, including for stream grants.

func (*Service) AllUsers

func (s *Service) AllUsers(ctx context.Context) ([]UserInfo, error)

AllUsers lists every known user including those who lost access.

func (*Service) Authenticate

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

Authenticate implements core.Auth.

func (*Service) BootstrapOwner

func (s *Service) BootstrapOwner(ctx context.Context, p config.Plex) error

BootstrapOwner creates the owner from config without network access (on startup, before plex.tv is reachable) and registers the server token.

func (*Service) Close

func (s *Service) Close()

Close disconnects the cluster bus.

func (*Service) FlushSeen

func (s *Service) FlushSeen(ctx context.Context) error

FlushSeen persists last-seen times (call periodically and at shutdown). Every node flushes its own observations; the update only ever moves last_seen_at forward, so nodes flushing in any order keep the latest.

func (*Service) Invalidate

func (s *Service) Invalidate(token string)

Invalidate forgets cached validations of token.

func (*Service) IssueDelegation added in v0.2.7

func (s *Service) IssueDelegation(ctx context.Context, userID int64) (string, error)

IssueDelegation creates a server-local credential, never a plex.tv account token. Only hashes persist; expiry and membership are checked on every use, including when another cluster node receives the credential.

func (*Service) Owner

func (s *Service) Owner(ctx context.Context) (*core.User, error)

Owner implements core.Auth.

func (*Service) SetBus

func (s *Service) SetBus(bus clusterbus.Bus)

SetBus connects the cluster bus (nil disconnects): after every write this service tells the other nodes to reload users and tokens, and it reloads when they write. A standalone server never calls it.

func (*Service) SetOwner

func (s *Service) SetOwner(ctx context.Context, a plextv.Account, serverToken string) error

SetOwner implements plextv.UserSync: it makes a the owner and registers serverToken as the owner's token. A unique index admits one owner row, so when another node changes the owner concurrently the losing transaction is retried against the winner's committed state.

func (*Service) SyncFriends

func (s *Service) SyncFriends(ctx context.Context, friends []plextv.Friend) error

SyncFriends implements plextv.UserSync: it replaces the synced access tokens, upserts friends' profiles (never their Ether settings) and deactivates every non-owner absent from the authoritative membership list, including viewers first discovered through personal-token validation.

func (*Service) UpdateUser

func (s *Service) UpdateUser(ctx context.Context, u core.User) error

UpdateUser implements core.Auth. It changes only per-user settings: stream limit, content rating cap, languages and allowed sections. Identity fields come from plex.tv and are ignored.

func (*Service) User

func (s *Service) User(ctx context.Context, id int64) (*core.User, error)

User returns one user by local id (active or not).

func (*Service) Users

func (s *Service) Users(ctx context.Context) ([]core.User, error)

Users implements core.Auth: active users, owner first, then by name.

type UserInfo

type UserInfo struct {
	core.User
	Active       bool      `json:"active"`
	Origin       string    `json:"origin"`
	Home         bool      `json:"home"`
	Restricted   bool      `json:"restricted"`
	PlexSections []int     `json:"plexSections"`
	LastSeen     time.Time `json:"lastSeen,omitempty"`
}

UserInfo is a user plus bookkeeping for the admin UI.

type Validator

type Validator interface {
	// Account returns the account behind token. An error matching
	// core.ErrUnauthorized means the token is invalid; other errors mean
	// plex.tv could not answer.
	Account(ctx context.Context, token string) (*plextv.Account, error)
	// HasServer reports whether token's resources list includes this
	// server (i.e. the account was granted access).
	HasServer(ctx context.Context, token string) (bool, error)
}

Validator checks tokens Ether does not already know against plex.tv.

Jump to

Keyboard shortcuts

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