Auth
This page covers application-level configuration for provider access and authentication.
Auth behavior
BASE_URLandAUTH_SECRETare required at startup.- Keep
AUTH_TRUSTED_ORIGINSempty to trust onlyBASE_URL. - Anonymous auth sessions are disabled by default.
- Set
USE_ANONYMOUS_AUTH_SESSIONS=trueto enable anonymous session flows.
Single sign-on (OAuth / OIDC)
Alongside email/password, two optional SSO methods are supported. Each appears on the sign-in page only when configured:
- GitHub — set
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRET. The OAuth callback URL to register with GitHub is<BASE_URL>/api/auth/callback/github. - Generic OIDC — for self-hosted identity providers (Pocket ID, Authelia, Authentik, Keycloak, etc.). Set
OIDC_CLIENT_ID,OIDC_CLIENT_SECRET, andOIDC_DISCOVERY_URL(the provider's/.well-known/openid-configurationURL). The callback URL to register with your provider is<BASE_URL>/api/auth/callback/<OIDC_PROVIDER_ID>(oidcunless you overrideOIDC_PROVIDER_ID). Optional:OIDC_PROVIDER_NAMElabels the sign-in button (defaults toSSO), andOIDC_SCOPESoverrides the requested scopes (defaults toopenid profile email).
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret
OIDC_DISCOVERY_URL=https://auth.example.com/.well-known/openid-configuration
OIDC_PROVIDER_NAME=Pocket ID
OIDC_DISCOVERY_URL must use https://; plain http:// is accepted only for localhost during development, because the discovery document decides where the client secret and authorization codes are sent.
A user who originally signed up with email/password and later signs in through your identity provider with the same email address is attached to their existing account, keeping their documents and settings. Linking requires both sides to be verified: the provider must return email_verified: true for the user, and the local account's email must be verified, which requires account email delivery to be enabled. Whether the provider sends email_verified depends on its configuration — Pocket ID reflects its email-verification setting, Authentik 2025.10+ sends false unless you add a scope mapping, and Keycloak reflects the per-user flag — so check the claim in your provider before relying on linking. When either side is unverified, an existing email/password user who tries the OIDC button is told to sign in with their password instead, while users who never had a local account can still sign up through the provider.
Runtime modes
OpenReader has two common runtime modes:
- Auth enabled, non-admin user: user account/session features are available, but no admin controls.
- Auth enabled, admin user: full Settings → Admin access (shared providers + site features).
Admin role
On a fresh installation, set a one-time first-admin credential before boot:
BOOTSTRAP_ADMIN_EMAIL=owner@example.com
BOOTSTRAP_ADMIN_PASSWORD=<unique-initial-password-at-least-16-characters>
OpenReader creates that account once. Sign in and change the initial password under Settings → Account; the Admin tab appears after the password change. If account email delivery is already enabled, the first sign-in attempt sends a verification link. Follow it before signing in. No configuration edit or restart is needed afterward. The initial password is invalid after the change; removing the seed values later is optional. The email is not an admin allowlist, and changing it later does not alter the role. Existing v4 admins are preserved on upgrade. Additional admins are granted under Settings → Admin → Users.
Admins see dedicated areas for users, providers, account email, instance settings, compute, and maintenance.
- Shared TTS providers — server-managed TTS provider instances with encrypted keys, visible to all users.
- Site features — runtime overrides for what were previously build-time public env flags (including account signup availability, default TTS provider, audiobook export, etc.).
Email verification and password recovery
Account email is opt-in and disabled by default. An administrator configures it under Settings → Admin → Email using a verified Resend sender and a sending-only API key, sends a test, and then explicitly enables it.
When enabled:
- password registrations receive a one-hour verification link;
- password sign-in is blocked for existing and new unverified accounts and can resend a fresh verification link;
- Forgot password? sends a generic acknowledgement whether or not the address exists;
- reset links expire after one hour, successful resets revoke existing sessions, and the user signs in again;
- GitHub sign-in and already-active sessions keep their existing behavior.
- Registered users can request a new address in Settings → Account. The address changes only after the new inbox's verification link is followed.
When disabled, registration and password sign-in retain their previous behavior; verification, email change, and recovery actions are clearly unavailable. Users can still change a known password under Settings → Account. Turning the feature off also prevents queued verification/reset messages from being delivered.
Changing a password signs out other sessions. Admin role changes and signup approval are managed in Admin Panel, not through email lists.
Route behavior
/is a public landing/onboarding page and remains indexable./appis the protected app home (document list and uploader UI).- If a valid session exists (including anonymous), visiting
/redirects to/app. - Protected app routes continue to require auth; when anonymous sessions are disabled and no session exists, users are redirected to
/signin. /verify-email,/forgot-password, and/reset-passwordare public. Token-bearing pages send ano-referrerpolicy and are excluded from indexing.
Related docs
- For auth environment variables: Environment Variables
- For admin role and shared TTS provider config: Admin Panel
- For TTS character limits and quota behavior: Compute Rate Limiting
- For provider-specific guidance: TTS Providers
- For storage/S3/SeaweedFS behavior: Object / Blob Storage
- For database mode: Database
- For migration behavior and commands: Migrations
Sync notes
Auth enabled
- Settings and reading progress are saved to the server.
- Updates are not instant push-based sync; they use normal client polling/refresh behavior.
- If two devices change the same item around the same time, the newest update wins.
Claim modal note
- You may still see old anonymous settings/progress available to claim from older deployments.
- Legacy
unclaimeddata is only surfaced through the claim flow; normal authenticated routes are scoped to your current user id.