Local User Configuration#
Local users are the built-in credential store in Tinyauth, distinct from LDAP and OAuth providers. They are defined in AuthConfig.Users as a list of username:hashed_password entries, or loaded from an external file via AuthConfig.UsersFile. Per-user OIDC attributes (name, email, locale, address, etc.) are attached via a separate AuthConfig.UserAttributes map keyed by username.
User Entry Format#
Each entry follows the format username:bcrypt_hash or username:bcrypt_hash:totp_secret. Parsing happens in ParseUser(), which splits on : (up to 3 parts) and populates the LocalUser struct:
| Field | Source |
|---|---|
Username | First segment |
Password | Second segment (bcrypt hash) |
TOTPSecret | Third segment (optional) |
Attributes | Merged from UserAttributes map in ParseUsers() |
Docker Compose note: bcrypt hashes contain
$characters. When passing via environment variables in Docker Compose, escape each$as$$β e.g.,TINYAUTH_AUTH_USERS=user:$$2a$$10$$....
Passwords are verified with bcrypt via CheckUserPassword(). During login, SearchUser() checks local users first before falling back to LDAP.
User Attributes (OIDC Profile Claims)#
Auth.UserAttributes is a map[string]UserAttributes where each key is a username. The UserAttributes struct covers all standard OIDC profile claims:
| Field | OIDC Claim | Notes |
|---|---|---|
Name | name | Full display name |
GivenName | given_name | |
FamilyName | family_name | |
MiddleName | middle_name | |
Nickname | nickname | |
Email | email | |
PhoneNumber | phone_number | |
Profile | profile | URL |
Picture | picture | URL |
Website | website | URL |
Gender | gender | |
Birthdate | birthdate | YYYY-MM-DD |
Zoneinfo | zoneinfo | e.g. Europe/Athens |
Locale | locale | e.g. en-US |
Address | address | AddressClaim sub-struct |
Defaults when attributes are unset: If Name is empty, the context middleware capitalizes the username . If Email is empty, it constructs username@<cookie-domain> β or returns the username as-is if it already parses as a valid email address .
Configuration reference:
- Env var:
TINYAUTH_AUTH_USERATTRIBUTES_[NAME]_EMAIL,TINYAUTH_AUTH_USERATTRIBUTES_[NAME]_NAME, etc. - YAML:
auth.userAttributes.<username>.email,auth.userAttributes.<username>.name, etc.
OIDC Claim Mapping#
When Tinyauth acts as an OIDC provider and a local user authenticates, userinfoFromContext() populates all UserAttributes fields into the userinfo response. Unlike LDAP/OAuth users (which only get groups passed through), local users get the full profile claim set .
The OIDC sub claim is a deterministic UUID derived from username:clientId, making it stable across sessions but tied to the username .
TOTP and Basic Auth Restriction#
A TOTP secret is stored as the third colon-separated field in the user entry. Users with a non-empty TOTPSecret cannot authenticate via Basic Auth β the basicAuth() handler rejects them because there is no second-factor channel in that flow.
Key Source Files#
| File | Purpose |
|---|---|
internal/model/config.go | AuthConfig, UserAttributes, AddressClaim struct definitions |
internal/model/users.go | LocalUser struct |
internal/utils/user_utils.go | ParseUser, ParseUsers, GetUsers, CompileUserEmail |
internal/service/auth_service.go | SearchUser, CheckUserPassword |
internal/middleware/context_middleware.go | Attribute hydration and default name/email logic |
internal/service/oidc_service.go | userinfoFromContext β maps attributes to OIDC claims |
| Generated configuration reference | Full env var / YAML / flag reference for all Auth.* options |