Skip to main content

Users and roles

Flexweg CMS has two rolesadmin and editor — plus a special bootstrap admin convention for the very first login. Authentication is delegated to Firebase Authentication; user records (display name, role, locale preferences) live in the Firestore users/{uid} collection.

Roles

admin

Full access:

  • Read + write all posts, pages, terms, media
  • Manage other users (create, change roles, delete)
  • Edit site settings (title, theme, plugins, menus)
  • Install / enable / disable / uninstall plugins and themes
  • Read / write the config/flexweg document (Flexweg API key)

editor

Content-focused:

  • Read + write all posts, pages, terms, media
  • Cannot manage other users
  • Cannot edit site settings, install plugins, or read the Flexweg API key

The role is stored as users/{uid}.role. New users are created with role: "editor" by default.

The bootstrap admin

The first time you deploy the admin, no users/ documents exist yet. Without special-casing this, no one would be able to log in (since the role check would fail) and no one would be able to create the first user (since that requires admin role).

Solution: the admin pins a single email — set via the VITE_ADMIN_EMAIL environment variable (or via the SetupForm on first run) — that's treated as admin even without a Firestore user record. So:

  1. You set up Firebase Auth, create a user with that email + password
  2. You log in via the admin's standard login form
  3. The admin recognises the email match and gives you admin access immediately
  4. On first action, ensureSelfUserRecord writes the users/{uid} doc with role: "admin", adminLocale: "en" (or browser-detected)
  5. From then on you appear as a standard admin user — bootstrap doesn't matter anymore

The bootstrap email lives in users/_meta (or via the VITE_ADMIN_EMAIL baked into the bundle) so Firestore rules can mirror it. Don't lose access to the bootstrap email — recovery requires editing Firestore rules manually.

Creating users

Via the admin

Users sidebar entry (admin-only) → Create user → email + password + display name + role.

This:

  1. Creates the Firebase Auth user via createUserWithEmailAndPassword (requires the admin's session — Firebase doesn't have a "create as admin" flow without a separate backend, so the new user is briefly "logged in" as the admin, the user record is written, then the admin re-authenticates).
  2. Writes users/{uid} with the chosen role and the new user's display name.

Via the Firebase Console

For air-gapped setups or password-reset flows:

  1. Firebase Console → Authentication → Users → Add user
  2. Then Firestore → users collection → New document with { email, displayName, role: "editor" } (or admin)

Changing roles

Admin only. Users → click a user → Role dropdown → Save.

Demotion of the last admin (you'd lock yourself out) is blocked client-side. The bootstrap admin email is always treated as admin even if you accidentally set its role to editor.

Deleting users

Admin only. Users → click a user → Delete user.

This:

  1. Deletes the Firebase Auth user (server-side — irreversible)
  2. Deletes the Firestore users/{uid} document

Posts authored by the deleted user keep their authorId reference. The post's author display name falls back to "Deleted user" or similar in templates that handle missing authors.

Password resets

The CMS doesn't ship a "forgot password" flow because Firebase's built-in flow is enough:

Self-service (when configured)

  1. Firebase Console → Authentication → Templates → enable Password reset email
  2. The login form's "Forgot password?" link triggers sendPasswordResetEmail → user gets an email → clicks the link → enters new password

Admin reset

  1. Firebase Console → Authentication → Users → ⋮ → Reset password
  2. The user gets the reset email

Direct password change in console

Firebase Console → Authentication → Users → ⋮ → Change password — sets a new password directly without emailing the user. Useful for one-off resets when the user's email is unreliable.

2FA / MFA

Firebase supports MFA (TOTP authenticator apps, SMS) via Identity Platform. Configure in Firebase Console → Authentication → Settings → Multi-factor authentication.

Once enabled, users see an MFA enrollment prompt after their next login. The admin's login form handles MFA challenges through Firebase's standard SDK flow — no per-CMS work.

For a single-admin setup, MFA via TOTP is recommended. The admin SPA itself doesn't add anything beyond what Firebase provides.

Per-user preferences

Stored at users/{uid}.preferences:

  • adminLocale — language for the admin UI (en / fr / de / es / nl / pt / ko). Set via the LocaleSwitcher in the topbar; persists across devices since it's in Firestore.

The user record has room for more fields (display photo, signature, etc.) — the schema is loose enough that custom plugins can extend it.

Firestore rules

Security in Flexweg CMS is rules-driven, not application-driven. Even if a malicious admin user found a bug in the admin code, they couldn't read documents the rules forbid. The shipped rules:

  • posts, terms, media — readable by admin or editor; writable by both
  • users — readable by all signed-in users (so the admin can show author names); writable by admin only (with the bootstrap exception)
  • settings/site — readable by all signed-in users; writable by admin only
  • config/flexweg — readable + writable by admin only (so editors never see the API key)

See Operations: Firestore rules for the actual rule code and customisation.

Continue