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 both the login and the contact address; passwords are
hashed with scrypt and compared in constant time.
- 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. 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:toddorplex:myplexuser) to make exactly that identity admin + active and leave everyone elsepending. This disables first-user-auto-admin.
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 in production and on non-loopback binds (unless ALLOW_INSECURE_AUTH_BYPASS=1). Use it to
kick the tires locally; never on anything reachable by others.