Documentation
¶
Overview ¶
Package systemauthsvc assembles a production-grade SystemAuth OAuth 2.0 / OpenID Connect server from configuration, for the standalone systemauth command and for host binaries that embed SystemAuth next to other applications in one process.
It owns the steps between a configuration file and a ready http.Handler:
- LoadConfig, LoadConfigBytes: read the YAML/JSON configuration from a file or memory (with environment variable expansion), then apply overrides, defaults and validation, in that order.
- New: enforce the production requirements (signing key, https issuer, persistent database, secure cookies) unless Options.Dev is set; open PostgreSQL ("pgx") or SQLite ("sqlite3") or use an injected *sql.DB or Ent client; optionally migrate; bootstrap the system user that owns statically configured clients; register or update those clients; and select the Ent-backed token, login session, login state and consent stores so restarts and replicas share state.
- Service: the http.Handler plus Migrate, Ready, Close, Issuer and the discovery Metadata an in-process relying party can use without a network round trip.
Embedding SystemAuth puts its signing key in the same process (and memory) as the host's application code, and a restart of the host is a restart of the login service. See docs/systemauth/embedding.md.
Index ¶
- Variables
- func CheckProduction(cfg *Config, opts Options) error
- func Migrate(ctx context.Context, cfg *Config) (err error)
- func NewLogger(w io.Writer, level, format string) (*slog.Logger, error)
- type Config
- type Database
- type Options
- type Override
- type Service
- func (s *Service) Close() error
- func (s *Service) Config() Config
- func (s *Service) Discovery() systemauth.OpenIDConfiguration
- func (s *Service) EntClient() *ent.Client
- func (s *Service) Handler() http.Handler
- func (s *Service) Issuer() string
- func (s *Service) KeyID() string
- func (s *Service) Metadata() relyingparty.Metadata
- func (s *Service) Migrate(ctx context.Context) error
- func (s *Service) Ready(ctx context.Context) error
- func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Service) Server() *systemauth.Server
- func (s *Service) StorageName() string
Constants ¶
This section is empty.
Variables ¶
var ErrNotProductionReady = errors.New("systemauthsvc: refusing to start in production mode")
ErrNotProductionReady is returned by New and CheckProduction when the configuration does not meet the production requirements and Options.Dev is not set.
Functions ¶
func CheckProduction ¶
CheckProduction reports, as an error wrapping ErrNotProductionReady, every production requirement the configuration and options miss: a signing key, a public https issuer, a persistent database and secure login cookies. It returns nil when opts.Dev is set.
Types ¶
type Config ¶
type Config = systemauth.Config
Config is the SystemAuth server configuration.
func LoadConfig ¶
LoadConfig reads the configuration file at path (YAML or JSON by extension, with environment variable expansion; an empty path starts from an empty configuration), applies the overrides in order, then applies defaults and validates the result. Validation runs after the overrides, so an override can supply a value the file omits (e.g. WithDefaultIssuer).
func LoadConfigBytes ¶
LoadConfigBytes is LoadConfig for configuration already in memory, e.g. a section embedded in a host's own configuration file. format is "yaml" (or "yml") or "json"; an empty format detects JSON when the first non-space byte is '{' and YAML otherwise. Empty data starts from an empty configuration.
type Database ¶
type Database struct {
// Client is the Ent client.
Client *ent.Client
// DB is the connection pool.
DB *sql.DB
}
Database is an Ent client with its underlying connection pool.
func OpenDatabase ¶
func OpenDatabase(cfg *systemauth.DatabaseConfig) (*Database, error)
OpenDatabase opens the configured database without connecting: PostgreSQL through the pgx stdlib driver, SQLite through go-sqlite3, each with the matching Ent dialect.
type Options ¶
type Options struct {
// Dev relaxes the production requirements: an ephemeral signing key,
// in-memory storage, an http issuer and insecure login cookies are
// allowed. Never set it for a deployment that serves real users.
Dev bool
// Logger receives server logs. Default: slog.Default().
Logger *slog.Logger
// SigningKey supplies the RSA signing key programmatically (e.g. from a
// secret manager), taking precedence over keys.private_key_file and
// keys.private_key_pem.
SigningKey *rsa.PrivateKey
// DB injects an open connection pool instead of opening
// cfg.Database. DBDialect names its database ("postgres" or "sqlite")
// and is required with DB. The caller owns DB; Close does
// not close it.
DB *sql.DB
DBDialect string
// EntClient injects an Ent client for the identity schema instead of
// opening a database. When DB is also set it is used for the readiness
// ping. The caller owns the client; Close does not close it.
EntClient *ent.Client
// Migrate creates or updates the database schema before the system
// user and static clients are written. Without it the schema must
// already exist (run Migrate or "systemauth migrate" first).
Migrate bool
// ServerOptions are passed to systemauth.NewEmbedded after the storage,
// logger and readiness options New sets, e.g. WithObservability or
// custom social login stores.
ServerOptions []systemauth.Option
}
Options configures New with what does not belong in the configuration file: the deployment mode, the logger, programmatic secrets and injected database handles. The issuer, database DSN, signing key file and key ID are configuration fields; set them in the file, through LoadConfig overrides, or directly on the Config.
type Override ¶
Override adjusts a loaded configuration before defaults and validation are applied, e.g. from command-line flags or environment variables.
func WithDatabase ¶
WithDatabase sets the database driver ("postgres" or "sqlite") and DSN. Environment variables in the DSN are expanded. Both must be given together; when both are empty the override does nothing.
func WithDefaultIssuer ¶
WithDefaultIssuer sets the issuer only when the configuration has none, e.g. a localhost URL in development.
func WithDefaultSigningKeyPEM ¶
WithDefaultSigningKeyPEM sets a PEM RSA signing key only when the configuration supplies none, e.g. from a secret injected through the environment.
func WithKeyID ¶
WithKeyID sets the JWKS key ID ("kid"). The default is the RFC 7638 thumbprint of the signing key.
func WithSigningKeyFile ¶
WithSigningKeyFile sets the PEM RSA signing key file, replacing any configured key.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is a configured SystemAuth server ready to be mounted.
func New ¶
New builds a SystemAuth server from cfg. Unless opts.Dev is set it refuses a configuration that misses a production requirement (see CheckProduction). With a database it connects, optionally migrates, bootstraps the system user that owns statically configured clients, registers or updates those clients, and keeps tokens, login sessions, login state and consent grants in the database. Without one (Dev only) everything is in memory.
func (*Service) Close ¶
Close releases the database New opened. Injected handles (Options.DB, Options.EntClient) are left to their owner.
func (*Service) Discovery ¶
func (s *Service) Discovery() systemauth.OpenIDConfiguration
Discovery returns the OpenID Provider configuration served at /.well-known/openid-configuration.
func (*Service) Handler ¶
Handler returns the HTTP handler serving every SystemAuth endpoint (discovery, JWKS, OAuth, UserInfo, health and, when configured, social login). Mount it at the root of the issuer's host.
func (*Service) Metadata ¶
func (s *Service) Metadata() relyingparty.Metadata
Metadata returns the provider metadata a relying party needs, identical to what discovery serves. Pass it to relyingparty.NewClientWithMetadata so an in-process relying party skips the discovery request.
func (*Service) Migrate ¶
Migrate creates or updates the database schema. It is idempotent and does nothing with in-memory storage.
func (*Service) Ready ¶
Ready runs the readiness checks behind GET /readyz (the database ping) and returns nil when the service can serve requests.
func (*Service) ServeHTTP ¶
func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
func (*Service) Server ¶
func (s *Service) Server() *systemauth.Server
Server returns the underlying SystemAuth server.
func (*Service) StorageName ¶
StorageName names the storage backend: the database driver or dialect, "ent" for an injected client, or "in-memory".