Environment Variable Parsing#
Tinyauth reads configuration from environment variables using the paerser library β a Go library for loading configuration into structs from multiple sources. All Tinyauth env vars share the prefix TINYAUTH_ , and a dedicated EnvLoader handles the full parsing lifecycle.
How It Works#
The parsing pipeline runs in two steps inside EnvLoader.Load:
-
Filter β
env.FindPrefixedEnvVarsinspects the target configuration struct via reflection and returns only the env vars whose names start with a field-derived prefix . This avoids processing irrelevant env vars. -
Decode β
env.Decodeconverts the filtered vars into a typed Go struct through four internal stages :- Strip the
TINYAUTH_prefix and lowercase + normalize:TINYAUTH_SERVER_PORTβtinyauth.server.port(underscores become dots) parser.DecodeToNodesplits each dot-separated key into a tree of untyped nodesparser.AddMetadataaugments nodes with type/kind info inferred from the target structparser.Fillpopulates the typed struct from the annotated node tree
- Strip the
The full three-stage parser pipeline is defined in parser.Decode.
Naming Conventions#
| Type | Env Var Pattern | Example |
|---|---|---|
| Scalar field | TINYAUTH_<SECTION>_<KEY> | TINYAUTH_SERVER_PORT=3000 |
| Nested struct | TINYAUTH_<SECTION>_<SUBSECTION>_<KEY> | TINYAUTH_DATABASE_DRIVER=sqlite |
| Map entry (simple value) | TINYAUTH_<FIELD>_<MAPKEY> | β |
| Map entry (struct value) | TINYAUTH_<FIELD>_<MAPKEY>_<SUBKEY> | TINYAUTH_AUTH_USERATTRIBUTES_[NAME]_EMAIL |
| Slice | TINYAUTH_<FIELD>=val1,val2 | TINYAUTH_FOO=bar,baz |
For slices, multiple values are comma-separated in a single env var .
Dynamic Map Keys#
The most nuanced aspect is how paerser resolves map keys at runtime. Because env var names are static strings, the segment that represents a map key is inferred positionally by comparing the remaining path segments against the struct type. When paerser encounters a map[string]T field during AddMetadata, the next path segment becomes the map key.
For example, a map[string]UserAttributes field named UserAttributes is populated by:
TINYAUTH_AUTH_USERATTRIBUTES_alice_EMAIL=alice@example.com
TINYAUTH_AUTH_USERATTRIBUTES_bob_EMAIL=bob@example.com
The segment after USERATTRIBUTES (alice, bob) becomes the map key, and everything after is decoded into the value struct. This is demonstrated exhaustively in the paerser test suite, including nested maps (map[string]struct{ Bar map[string]struct{ Value string } }) decoded from a single flat env var like TRAEFIK_FOO_NAME1_BAR_NAME2_VALUE=bar .
In documentation and generated reference output, dynamic map keys are shown as <NAME> (the MapNamePlaceholder constant, value "<name>") β e.g. TINYAUTH_AUTH_USERATTRIBUTES_<NAME>_EMAIL .
Key Configuration Struct Fields Using Maps#
From the Tinyauth config model, the main map-keyed fields that can be configured via env vars are:
auth.UserAttributesβmap[string]UserAttributesβ per-user OIDC claim overridesAppsβmap[string]Appβ per-application ACL rulesoauth.Providersβmap[string]OAuthServiceConfigβ named OAuth provider configsoidc.Clientsβmap[string]OIDCClientConfigβ named OIDC client configs
Key Entry Points#
| File | Purpose |
|---|---|
internal/utils/loaders/loader_env.go | EnvLoader β glues paerser into Tinyauth's loader chain |
internal/model/constants.go | Defines DefaultNamePrefix = "TINYAUTH_" |
paerser/env/env.go | Decode and Encode β core env var β struct conversion |
paerser/env/filter.go | FindPrefixedEnvVars β reflection-based env var filtering |
paerser/parser/parser.go | parser.Decode β three-stage node pipeline |
paerser/env/env_test.go | Comprehensive decode/encode test cases, including nested maps |