Authentication & Access
narratorr-requests separates authentication (who you are) from authorization (who may request). Authentication is pluggable; authorization is the in-app approval queue. Enable either or both sign-in methods.
Local email + password
Section titled “Local email + password”On by default (LOCAL_AUTH=true). Email is the login, and starts out as the contact address —
the contact email is separately editable afterwards in the account modal (click your username)
without affecting how you sign in. Passwords are hashed with scrypt and compared in constant
time. For OIDC users the contact email is backfilled from provider claims on login; a manually
saved address wins over later claims, and clearing it re-enables the backfill.
- Users Create account / Sign in from the login page.
- Passwords must be 8–200 characters.
- A wrong login returns a generic “Invalid email or password” (no account enumeration on the login path).
Set LOCAL_AUTH=false to run pure-OIDC.
OIDC providers
Section titled “OIDC providers”List provider ids in OIDC_PROVIDERS (comma-separated), then configure each id <ID> with
OIDC_<UPPERCASE_ID>_* variables. Ids must be lowercase letters/digits/underscores (so
pocketid, not pocket-id) — an invalid or duplicate id fails at startup. Each provider gets its own login button and a callback at
/api/auth/oidc/<id>/callback. Plex (via a bridge), Authelia, Authentik, Keycloak, Pocket-ID,
and Google are all just provider instances — there’s no special-casing.
OIDC_PROVIDERS=plex,authelia
# Plex, via a plex-oidc-bridge:OIDC_PLEX_ISSUER=https://plex-auth.example.comOIDC_PLEX_CLIENT_ID=narratorr-requestsOIDC_PLEX_CLIENT_SECRET=…OIDC_PLEX_REDIRECT_URI=https://requests.example.com/api/auth/oidc/plex/callbackOIDC_PLEX_LABEL=Plex
# Authelia (Authentik / Keycloak / Pocket-ID / Google are the same shape):OIDC_AUTHELIA_ISSUER=https://auth.example.comOIDC_AUTHELIA_CLIENT_ID=narratorr-requestsOIDC_AUTHELIA_CLIENT_SECRET=…OIDC_AUTHELIA_REDIRECT_URI=https://requests.example.com/api/auth/oidc/authelia/callbackOIDC_AUTHELIA_LABEL=AutheliaPer provider, ISSUER / CLIENT_ID / REDIRECT_URI are required; CLIENT_SECRET is optional
(omit it for a public PKCE client). LABEL, SCOPE (default openid profile email), and the
SUBJECT_CLAIM / USERNAME_CLAIM / EMAIL_CLAIM overrides are optional. The flow uses PKCE
(S256) with single-use state and nonce.
The approval queue
Section titled “The approval queue”A valid sign-in is not enough to request — every account has a status:
| Status | What the user can do |
|---|---|
pending | Signed in, but sees an “Awaiting approval” screen — can’t search or request. |
active | Full access: search, request, track. |
rejected | Sees an “Access not approved” screen. Durable — survives re-login. |
A new user lands pending. An admin moves them to active (or rejected) on the Users page.
The gate is enforced both client-side and server-side (a pending account’s API calls get
403 ACCOUNT_PENDING). Admins are always treated as active.
Bootstrapping the admin
Section titled “Bootstrapping the admin”-
First-user-auto-admin (default). The first real identity to sign in — in any method — becomes admin + active automatically. (The
AUTH_BYPASSdev-admin sentinel doesn’t count, so flipping a smoke instance to real auth still lets your first real user claim admin.) -
Pin it instead with
BOOTSTRAP_ADMIN. SetBOOTSTRAP_ADMIN=<provider>:<subjectOrUsername>(e.g.authelia:todd,plex:myplexuser, orlocal:you@example.com) before that identity’s first sign-in to make exactly that identity admin + active and leave everyone elsepending. This disables first-user-auto-admin. The grant applies when the account is created — setting it later won’t promote an existing account (or demote an existing admin); fix those on the Users page.
Behind a reverse proxy
Section titled “Behind a reverse proxy”Set TRUSTED_PROXIES (same variable name as narratorr) so the real client IP is used for the
login rate-limiter — set it to true (trust all), a hop count, or a CIDR/IP list (e.g. your
Docker proxy network). Auth endpoints are rate-limited by client IP and attempted email to
slow brute-force attempts.
AUTH_BYPASS (development only)
Section titled “AUTH_BYPASS (development only)”AUTH_BYPASS=1 seeds a dev admin and makes every request that admin — no login at all. It’s
refused outright in production (no escape hatch), and refused on a non-loopback bind unless you
also set ALLOW_INSECURE_AUTH_BYPASS=1. Use it to kick the tires locally; never on anything
reachable by others.