Configuration
ezauth is configured primarily through environment variables. All variables are prefixed with EZAUTH_.
Global Settings
| Variable |
Description |
Default |
EZAUTH_ADDR |
The address the server listens on. |
:8080 |
EZAUTH_API_KEY |
Master API Key for protecting endpoints. |
|
EZAUTH_PREVIOUS_API_KEY |
Outgoing master API key, accepted alongside EZAUTH_API_KEY for the duration of a rotation (mirrors EZAUTH_JWT_PREVIOUS_PUBLIC_KEY's pattern). Unset means no rotation is in progress. |
|
EZAUTH_API_KEY_DEFAULT_TTL |
Default lifetime for a newly created API key (APIKeyCreate's ttl parameter, when 0). |
87600h (10 years) |
EZAUTH_BASE_URL |
The base URL of the auth service (used for emails). |
http://localhost:8080 |
EZAUTH_DEBUG |
Enable debug logging. |
false |
EZAUTH_FORCE_SECURE_COOKIES |
Force the Secure flag on every cookie ezauth sets (session, oauth_state, trusted-device) regardless of BASE_URL's scheme. Set true when ezauth sits behind a TLS-terminating reverse proxy and BASE_URL can't be https://. |
false |
EZAUTH_TRUST_PROXY_HEADERS |
Trust True-Client-IP/X-Real-IP/X-Forwarded-For to resolve the client IP (used by the rate limiter). Only set true behind a reverse proxy that sets/overwrites these headers itself — otherwise any client can spoof them to bypass rate limiting. |
false |
EZAUTH_ADMIN_ROLE |
RBAC role required to reach Handler's admin/RBAC/org/impersonation HTTP routes by default (see Admin Authorization in the README). Bootstrap your first admin via ezauthapi create-admin. |
admin |
EZAUTH_JWT_SECRET |
Secret key used to sign JWT tokens (HS256). Must be at least 32 characters — LoadConfig rejects a shorter value. |
|
EZAUTH_CSRF_SECRET |
Not currently used: CSRF protection (filippo.io/csrf) validates request headers, not an HMAC-signed token, so there's no key for this to provide. Accepted for config-shape compatibility only. |
|
EZAUTH_CSRF_TRUSTED_ORIGINS |
Comma-separated Origin values (e.g. https://app.example.com) exempted from the CSRF cross-origin check. Only needed when the frontend is served from a different origin than ezauth itself — see CSRF Protection in the README. |
|
EZAUTH_TIMEOUT |
Request timeout duration. |
30s |
EZAUTH_MFA_ISSUER |
Issuer name shown in authenticator apps for TOTP MFA. |
EzAuth |
EZAUTH_TRUSTED_DEVICE_TTL |
How long a "remembered" device skips MFA step-up. |
720h (30 days) |
EZAUTH_TRUSTED_DEVICE_COOKIE_NAME |
Cookie name for the trusted-device token (form/cookie clients). |
ezauth_device |
EZAUTH_ACCOUNT_LOCKOUT_ENABLED |
Count failed attempts and auto-lock accounts after too many. Covers password login, MFA TOTP/recovery-code verification, and SMS OTP verification — all three share one counter, so a failed guess against any of them counts toward the same lockout. |
true |
EZAUTH_ACCOUNT_LOCKOUT_MAX_ATTEMPTS |
Consecutive failed attempts before locking the account. |
5 |
EZAUTH_ACCOUNT_LOCKOUT_DURATION |
How long a locked account stays locked before auto-unlocking. |
15m |
EZAUTH_AUDIT_LOG_ENABLED |
Persist security-relevant events (login, password reset, impersonation, lockout, ...) to the audit log. |
true |
EZAUTH_INVITATION_TTL |
How long an invitation stays valid before expiring. |
168h (7 days) |
EZAUTH_JWT_ALGORITHM |
Access-token signing algorithm: HS256 (symmetric), RS256, or EdDSA (asymmetric). |
HS256 |
EZAUTH_JWT_PRIVATE_KEY |
PEM-encoded (PKCS8) private key; required for RS256/EdDSA. |
|
EZAUTH_JWT_PUBLIC_KEY |
PEM-encoded (PKIX) public key; required for RS256/EdDSA, published via JWKS. |
|
EZAUTH_JWT_KEY_ID |
Explicit kid for the signing key; auto-derived from the public key if unset. |
|
EZAUTH_JWT_PREVIOUS_PUBLIC_KEY |
Outgoing key's public key, kept for verification during rotation. |
|
EZAUTH_JWT_PREVIOUS_KEY_ID |
Outgoing key's kid; auto-derived from EZAUTH_JWT_PREVIOUS_PUBLIC_KEY if unset. |
|
EZAUTH_JWT_ACCESS_TOKEN_TTL |
How long a Bearer access token stays valid before needing a refresh. |
15m |
EZAUTH_JWT_ISSUER |
Stamped into access tokens as iss and enforced by AuthMiddleware; unset means no iss claim and no enforcement. |
|
EZAUTH_JWT_AUDIENCE |
Stamped into access tokens as aud and enforced by AuthMiddleware; unset means no aud claim and no enforcement. Useful when multiple services share a signing key, so a token minted for one can't authenticate to another. |
|
WebAuthn/Passkey Settings
WebAuthn support is disabled unless both EZAUTH_WEBAUTHN_RP_ID and EZAUTH_WEBAUTHN_RP_ORIGINS are set.
| Variable |
Description |
Default |
EZAUTH_WEBAUTHN_RP_ID |
Relying Party ID: the effective domain (e.g. example.com, no scheme/port). |
|
EZAUTH_WEBAUTHN_RP_DISPLAY_NAME |
Relying Party display name shown during registration. |
EzAuth |
EZAUTH_WEBAUTHN_RP_ORIGINS |
Comma-separated list of allowed origins (e.g. https://example.com). |
|
Hashing Settings
| Variable |
Description |
Default |
EZAUTH_HASHING_ALGORITHM |
Password hashing algorithm (bcrypt or argon2id). |
bcrypt |
EZAUTH_HASHING_BCRYPT_COST |
bcrypt work factor (4-31); only used when the algorithm is bcrypt. |
14 |
EZAUTH_HASHING_ARGON2_MEMORY |
Argon2 memory cost in KB (used when algorithm is argon2id). |
65536 |
EZAUTH_HASHING_ARGON2_ITERATIONS |
Argon2 time cost (iterations). |
3 |
EZAUTH_HASHING_ARGON2_PARALLELISM |
Argon2 parallelism (thread count). |
4 |
EZAUTH_HASHING_ARGON2_SALT_LENGTH |
Argon2 salt length in bytes. |
16 |
EZAUTH_HASHING_ARGON2_KEY_LENGTH |
Argon2 derived key length in bytes. |
32 |
Rate Limit Settings
Two independent limiters are mounted (see Middleware):
RATE_LIMIT_REQUESTS/RATE_LIMIT_WINDOW bound every route as a coarse
abuse/DoS guard, while RATE_LIMIT_SENSITIVE_REQUESTS/RATE_LIMIT_SENSITIVE_WINDOW
bound only the unauthenticated endpoints that create or verify a short-lived
credential -- login, password reset, passwordless, SMS OTP, and MFA
verification, on both the Form and JSON API transports (they share one
budget). Splitting them keeps a client's ordinary browsing/API usage from
exhausting the tight budget meant to slow down credential stuffing, and vice
versa.
| Variable |
Description |
Default |
EZAUTH_RATE_LIMIT_ENABLED |
Enable the general, site-wide rate limiter. |
true |
EZAUTH_RATE_LIMIT_REQUESTS |
Maximum requests allowed per window, site-wide. |
300 |
EZAUTH_RATE_LIMIT_WINDOW |
General rate limit window duration (e.g., 1m, 30s). |
1m |
EZAUTH_RATE_LIMIT_BY_CLIENT_IP |
Apply both rate limiters per client IP address. |
true |
EZAUTH_RATE_LIMIT_SENSITIVE_ENABLED |
Enable the stricter limiter on login/password-reset/OTP endpoints. |
true |
EZAUTH_RATE_LIMIT_SENSITIVE_REQUESTS |
Maximum sensitive-endpoint requests allowed per window. |
10 |
EZAUTH_RATE_LIMIT_SENSITIVE_WINDOW |
Sensitive-endpoint rate limit window duration. |
1m |
Database Settings
| Variable |
Description |
Default |
EZAUTH_DB_DIALECT |
Database dialect (sqlite3, postgres, or mysql). mysql requires 8.0.23+ -- migrations use generated/invisible columns and expression column defaults. |
sqlite3 |
EZAUTH_DB_DSN |
Database connection string. |
ezauth.db |
EZAUTH_DB_SCHEMA |
Database schema (PostgreSQL only). Empty uses the schema on the connection's search_path (typically public). |
(empty) |
EZAUTH_DB_MAX_OPEN_CONNS |
Max open connections in the pool. |
25 |
EZAUTH_DB_MAX_IDLE_CONNS |
Max idle connections kept in the pool. |
5 |
EZAUTH_DB_CONN_MAX_LIFETIME |
Max lifetime of a pooled connection before it's recycled (Go duration, e.g. 30m). |
30m |
SMTP Settings
Used for sending password reset and magic link emails.
| Variable |
Description |
Default |
EZAUTH_SMTP_HOST |
SMTP server host. |
|
EZAUTH_SMTP_PORT |
SMTP server port. |
587 |
EZAUTH_SMTP_USER |
SMTP username. |
|
EZAUTH_SMTP_PASSWORD |
SMTP password. |
|
EZAUTH_SMTP_FROM |
The email address to send from. No default — leave unset and mail is sent with an empty sender, which most servers reject. |
(empty) |
Email Templates
Customize the subject and body of emails sent by ezauth. Templates use Go text/template syntax.
Available variables: {{.Link}} (action URL), {{.Token}} (raw token), {{.Email}} (user's email)
| Variable |
Description |
Default |
EZAUTH_EMAIL_PASSWORDLESS_SUBJECT |
Subject for magic link emails. |
Magic Link Login |
EZAUTH_EMAIL_PASSWORDLESS_BODY |
Body for magic link emails. |
Click the following link to login: {{.Link}} |
EZAUTH_EMAIL_PASSWORD_RESET_SUBJECT |
Subject for password reset emails. |
Password Reset Request |
EZAUTH_EMAIL_PASSWORD_RESET_BODY |
Body for password reset emails. |
Click the following link to reset your password: {{.Link}} |
EZAUTH_EMAIL_INVITATION_SUBJECT |
Subject for invitation emails. |
You've been invited |
EZAUTH_EMAIL_INVITATION_BODY |
Body for invitation emails. |
Click the following link to accept your invitation: {{.Link}} |
EZAUTH_EMAIL_CHANGE_SUBJECT |
Subject for the verification email sent to a new address. |
Confirm your new email address |
EZAUTH_EMAIL_CHANGE_BODY |
Body for the verification email sent to a new address. |
Click the following link to confirm your new email address: {{.Link}} |
EZAUTH_EMAIL_CHANGE_NOTIFY_SUBJECT |
Subject for the notice sent to the current address. |
Your email address is being changed |
EZAUTH_EMAIL_CHANGE_NOTIFY_BODY |
Body for the notice sent to the current address. {{.NewEmail}} available. |
A request was made to change the email on your account to {{.NewEmail}}. If this wasn't you, please secure your account immediately. |
SMS OTP Settings
Used for sending SMS one-time login codes. SMS OTP support falls back to a mock sender (no message actually sent) unless all three of EZAUTH_SMS_TWILIO_ACCOUNT_SID, EZAUTH_SMS_TWILIO_AUTH_TOKEN, and EZAUTH_SMS_TWILIO_FROM are set.
| Variable |
Description |
Default |
EZAUTH_SMS_TWILIO_ACCOUNT_SID |
Twilio Account SID. |
|
EZAUTH_SMS_TWILIO_AUTH_TOKEN |
Twilio Auth Token. |
|
EZAUTH_SMS_TWILIO_FROM |
The phone number to send from. |
|
EZAUTH_SMS_OTP_BODY |
SMS body template. {{.Code}}, {{.Phone}} available. |
Your verification code is: {{.Code}} |
Used for the Form-based handlers (browser flows).
| Variable |
Description |
Default |
EZAUTH_REDIRECT_AFTER_LOGIN |
URL to redirect to after successful login. |
/ |
EZAUTH_REDIRECT_AFTER_REGISTER |
URL to redirect to after successful registration. |
/ |
EZAUTH_LOGIN_PAGE_URL |
URL of your custom Login page (for redirects). |
/login |
EZAUTH_REGISTER_PAGE_URL |
URL of your custom Register page (for redirects). |
/register |
EZAUTH_MFA_VERIFY_PAGE_URL |
URL of your custom MFA code-entry page (for step-up login redirects). |
/mfa/verify |
EZAUTH_INVITATION_ACCEPT_PAGE_URL |
URL of your custom invitation-acceptance page. |
/invitation/accept |
OAuth2 Settings
General
| Variable |
Description |
EZAUTH_OAUTH2_CALLBACK_URL |
The URL users are redirected to after successful OAuth2 login. |
Google
| Variable |
Description |
Default |
EZAUTH_OAUTH2_GOOGLE_CLIENT_ID |
Google OAuth2 Client ID. |
|
EZAUTH_OAUTH2_GOOGLE_CLIENT_SECRET |
Google OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_GOOGLE_REDIRECT_URL |
Redirect URL registered in Google Console. Must be: {base_url}/auth/oauth2/google/callback |
|
EZAUTH_OAUTH2_GOOGLE_SCOPES |
Scopes to request. |
openid,profile,email |
GitHub
| Variable |
Description |
Default |
EZAUTH_OAUTH2_GITHUB_CLIENT_ID |
GitHub OAuth2 Client ID. |
|
EZAUTH_OAUTH2_GITHUB_CLIENT_SECRET |
GitHub OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_GITHUB_REDIRECT_URL |
Redirect URL registered in GitHub settings. Must be: {base_url}/auth/oauth2/github/callback |
|
EZAUTH_OAUTH2_GITHUB_SCOPES |
Scopes to request. |
user:email |
Facebook
| Variable |
Description |
Default |
EZAUTH_OAUTH2_FACEBOOK_CLIENT_ID |
Facebook OAuth2 Client ID. |
|
EZAUTH_OAUTH2_FACEBOOK_CLIENT_SECRET |
Facebook OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_FACEBOOK_REDIRECT_URL |
Redirect URL registered in Facebook settings. Must be: {base_url}/auth/oauth2/facebook/callback |
|
EZAUTH_OAUTH2_FACEBOOK_SCOPES |
Scopes to request. |
email,public_profile |
Discord
| Variable |
Description |
Default |
EZAUTH_OAUTH2_DISCORD_CLIENT_ID |
Discord OAuth2 Client ID. |
|
EZAUTH_OAUTH2_DISCORD_CLIENT_SECRET |
Discord OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_DISCORD_REDIRECT_URL |
Redirect URL registered in Discord settings. Must be: {base_url}/auth/oauth2/discord/callback |
|
EZAUTH_OAUTH2_DISCORD_SCOPES |
Scopes to request. |
identify,email |
GitLab
| Variable |
Description |
Default |
EZAUTH_OAUTH2_GITLAB_CLIENT_ID |
GitLab OAuth2 Client ID. |
|
EZAUTH_OAUTH2_GITLAB_CLIENT_SECRET |
GitLab OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_GITLAB_REDIRECT_URL |
Redirect URL registered in GitLab settings. Must be: {base_url}/auth/oauth2/gitlab/callback |
|
EZAUTH_OAUTH2_GITLAB_SCOPES |
Scopes to request. |
read_user |
Slack
| Variable |
Description |
Default |
EZAUTH_OAUTH2_SLACK_CLIENT_ID |
Slack OAuth2 Client ID. |
|
EZAUTH_OAUTH2_SLACK_CLIENT_SECRET |
Slack OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_SLACK_REDIRECT_URL |
Redirect URL registered in Slack settings. Must be: {base_url}/auth/oauth2/slack/callback |
|
EZAUTH_OAUTH2_SLACK_SCOPES |
Scopes to request. |
openid,email |
LinkedIn
| Variable |
Description |
Default |
EZAUTH_OAUTH2_LINKEDIN_CLIENT_ID |
LinkedIn OAuth2 Client ID. |
|
EZAUTH_OAUTH2_LINKEDIN_CLIENT_SECRET |
LinkedIn OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_LINKEDIN_REDIRECT_URL |
Redirect URL registered in LinkedIn settings. Must be: {base_url}/auth/oauth2/linkedin/callback |
|
EZAUTH_OAUTH2_LINKEDIN_SCOPES |
Scopes to request. |
openid,profile,email |
Spotify
| Variable |
Description |
Default |
EZAUTH_OAUTH2_SPOTIFY_CLIENT_ID |
Spotify OAuth2 Client ID. |
|
EZAUTH_OAUTH2_SPOTIFY_CLIENT_SECRET |
Spotify OAuth2 Client Secret. |
|
EZAUTH_OAUTH2_SPOTIFY_REDIRECT_URL |
Redirect URL registered in Spotify settings. Must be: {base_url}/auth/oauth2/spotify/callback |
|
EZAUTH_OAUTH2_SPOTIFY_SCOPES |
Scopes to request. |
user-read-email,user-read-private |
Custom OAuth2 Providers
For providers not in the built-in list, use the dynamic provider configuration:
| Variable |
Description |
EZAUTH_OAUTH2_PROVIDERS |
Comma-separated list of custom provider names to register. |
EZAUTH_OAUTH2_<NAME>_CLIENT_ID |
OAuth2 Client ID for the custom provider. |
EZAUTH_OAUTH2_<NAME>_CLIENT_SECRET |
OAuth2 Client Secret for the custom provider. |
EZAUTH_OAUTH2_<NAME>_REDIRECT_URL |
Redirect URL for the custom provider. |
EZAUTH_OAUTH2_<NAME>_SCOPES |
Comma-separated scopes to request. |
EZAUTH_OAUTH2_<NAME>_ISSUER_URL |
OIDC Issuer URL (enables automatic OIDC discovery). |
EZAUTH_OAUTH2_<NAME>_AUTH_URL |
Authorization endpoint (manual config, requires TOKEN_URL). |
EZAUTH_OAUTH2_<NAME>_TOKEN_URL |
Token endpoint (manual config, requires AUTH_URL). |
EZAUTH_OAUTH2_<NAME>_USERINFO_URL |
Userinfo endpoint (manual config, requires AUTH_URL + TOKEN_URL). |
EZAUTH_OAUTH2_<NAME>_ID_FIELD |
JSON field name for the user ID in the userinfo response. |
EZAUTH_OAUTH2_<NAME>_EMAIL_FIELD |
JSON field name for the email in the userinfo response. |