Users and roles
Admins add, block and delete people under Users; people edit their own profile and can delete their own account. A role on each record decides what someone may do.
What it is
A person is one Firebase Auth account plus one record in the users collection. The record id is not the Auth uid: the record carries the uid in its uid field, and the account carries the record id in its arccms_uid claim.
The record's role is copied onto the account as the arccms_role claim, which the security rules and functions check. The roles are:
| Role | May |
|---|---|
admin | Everything, including the whole admin area (/admin/...). |
user | Their own record, profile and member area (/user/...), and what your app grants. |
How claims are set, refreshed and checked, and how an app adds its own roles, is in Roles and claims. How people sign in is in Sign-in methods.
Turn it on or off
Users and roles are core and always on. They belong to no switchable feature.
Set it up
The first admin comes from the setup wizard on a fresh install: see Create the first admin.
Settings, User Settings: choose whether people may sign up on their own (Enable User Signups, on by default) and the Default Role for New Users (
userunless you change it).
The default role applies to every self sign-up. Setting it to Admin makes everyone who signs up an admin.
Use it
Users (admin)
Admin, Users (/admin/users) lists every record with name, email, phone, role and status. An account an app created for someone with no email and no phone shows App account in the email column (see App accounts).
- Add User creates the sign-in account and the record together, with a temporary password you share with the person (the same rule as members' passwords: at least 8 characters and not easy to guess, or at least 6 in an app that chose simple passwords, see Passwords). Sign-ups do not have to be on. If the address already has a sign-in account (another app's user in a shared Firebase project), that account is reused unchanged, the person keeps their existing password, and the record is marked
authOwner: 'shared'. - Add an admin: open
/admin/users/admin, which lists the admins, and press Add Admin. People added from/admin/usersget theuserrole. The admin screens do not change the role of someone who already has a record. - View opens the record in a side panel, and Edit changes the person's name there. A person who has no email can be saved without one; an email typed in is still checked. Update Password sets a new password for someone with an email: it must pass the same password rule as every new password (see Passwords), goes to their sign-in account only (never to the record) and signs them out of their other sessions. It is not offered for a sign-in shared with another app (that app changes it) or a locked app account (its app does). People change their own email or phone number on their profile, with a code (see Sign-in methods).
- Block sets
isActivetofalse. The person's Arc CMS claims are removed and every session is ended within the hour, and they cannot sign in until an admin presses Unblock, which puts the claims back. - All, People and App accounts, above the list, narrow it to everyone (the default), to the people, or to the accounts an app made (
by: 'app'). They work with Detached accounts and with the role pages such as/admin/users/admin. - Detached accounts shows records whose only email or phone number moved to another account (see Sign-in methods). They are kept and cannot sign in; an admin can delete them.
- Delete removes the record, and the server then removes everything listed below.
Profile (the person)
The profile page is /profile, and /user/profile in the member area. People change their name and photo, manage their sign-in methods and password, and, unless they are an admin, delete their own account under Delete account.
Deleting your own account needs a sign-in within the last 10 minutes; otherwise the page asks the person to sign in again. Admins cannot delete themselves: another admin removes them under Users.
What deleting an account removes
Whoever deletes it, the users record goes first, and then the onUserDeleted function, in this order:
Access: removes the Arc CMS claims and ends every session, before anything else, so a failure later never leaves a removed admin an admin.
Firestore: every subcollection under
users/{docId}at any depth, the person'sFeedback, and their in-appNotifications.Storage: the per-user folder
users/{docId}/(under the install's upload folder, if it has one) and the profile photos inavatars/{uid}/.Sign-in: the Firebase Auth account, unless another app owns or shares it (
authOwnerishostorshared), plus theemail_lookupentry, the phone number index and the PIN, and an app's own PINs and its gates' counts of wrong phone PINs (see PINs for your app).Event:
user.deletedon the event bus, withuserId(the Auth uid) anddata.userDocId, once every step above has worked.
A step that fails makes the whole cleanup run again (each step is safe to repeat) for up to an hour after the delete.
A sign-in deleted some other way, such as by the person's browser, leaves the record as it is. The onSignInDeleted function then emits user.signInDeleted instead, and nothing is removed. An admin can still delete the record. See Follow the account contract.
The person's contact (their address in the audience): a person deleting their own account also erases it, with its lists, consent and form sign-ups, and an erasure receipt is kept in ErasureLog. An admin deleting a user only unlinks the contact from the account (with the audience feature), since the address may have been on a list before the account existed.
Kept: payment records (Transactions, CreditLedger) are not deleted. Data your app keeps outside users/{docId} is your app's to delete: see Follow the account contract.
Extend it
- Per-person app data belongs under
users/{docId}/...in Firestore and in the per-user Storage folder, so deleting the account removes it with no extra code. See Follow the account contract. - Clean up data kept elsewhere with a trigger on
users/{docId}deletes infunctions/src/custom/, or by reacting touser.deleted(see Automations). - Your own roles: Arc CMS never reads or writes a plain
roleclaim, so an app may use it for its own roles. Never name an app claimarccms_*. See Roles and claims. - Where each role lands after signing in:
src/custom/home.ts.
What it stores
| Where | What |
|---|---|
users/{docId} | uid, name, email, phone, photo, role, status, isActive, authOwner, by (how it was made), selfService (only on app accounts), and the fields of other features (plan, credits, app install). |
Settings/users | Sign-ups on or off, the default role, the sign-in method switches, and a copy of the SMS countries (the default and the allowed ones) for the sign-in page. |
_system/first_admin | Marks that the first admin was claimed. |
ErasureLog/{emailHash} | A receipt for each erased contact, with no address in it. |
Storage avatars/{uid}/ | Profile photos. |
Storage users/{docId}/ | The person's private files, such as feedback screenshots and your app's files. |
Cloud Functions:
| Function | Does |
|---|---|
adminCreateUser | Callable, admins: Add User. |
adminSetPassword | Callable, admins: Edit, Update Password. |
deleteMyAccount | Callable: the person deletes their own account. Never a locked app account: its app deletes it (App accounts). |
refreshMyClaims | Callable: puts the claims back on the caller's token at sign-in. |
claimFirstAdmin | Callable: the setup wizard's first admin, once. |
syncAllUserRoles | Callable, admins: re-applies every account's claims from its record. |
fillAccountSources | Callable, admins: gives every record with no by the value unknown, so People finds it. The users page calls it by itself, once, the first time it lists people and finds such records. |
onUserRoleChange | On every record write: applies the default role to a sign-up, and keeps the claims in step with the role and the block. |
onUserCreated, onUserCreateWelcomeEmail | On a new record: the email lookup, the admin alert (not for an app account) and user.signed_up event, and the welcome email. |
onUserDeleted | On a deleted record: the cleanup above. |
See Cloud Functions and Data model.
Who can do what
| Action | Who |
|---|---|
Read a users record | The person themselves, and admins |
| Create a record | Admins and the server. Every sign-up creates its record on the server. |
| Edit own record | The person, except role, uid, isActive, status, authOwner, email, phone, phoneVerified, the detach fields and the plan and credit fields |
| Edit any record, delete a record | Admins |
Give a role above user | Admins and the server only. A role written by anyone else is reverted by onUserRoleChange. |
| Read a per-user Storage folder | The person and admins. The person's own uploads there are allowed by the app, in storage.app.rules. |
Write avatars/{uid}/ | The person, images under 5 MB |
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| A new admin still sees "unauthorized" | Their token has the old claims. Signing out and in again refreshes it. |
| Claims look wrong on many accounts | Each person's claims are set again from their record the next time they open the site signed in. To re-apply every account at once, call the syncAllUserRoles callable while signed in as an admin; there is no button for it. |
| People leaves out someone who is in All | Their record has no by: it was made before Arc CMS recorded how an account was made, and Firestore leaves such a record out. The page fixes this itself with fillAccountSources; if it stays, deploy the functions and choose People again. |
| People or App accounts shows nothing, and the browser console asks for an index | The indexes for these filters are in firestore.indexes.json: deploy them (firebase deploy --only firestore:indexes) and wait for them to build. Sorting by another column than Joined needs an index of its own, as it does with Detached accounts. |
| "For your security, sign in again, then delete your account." | The last sign-in is more than 10 minutes old. Press Sign in again, then delete. |
| An admin has no Delete account section | Admins cannot delete themselves. Another admin deletes them under Users. |
| Deleted a user, but their sign-in still exists | The record was marked host or shared: the sign-in belongs to another app and is kept, without Arc CMS claims. |
| Add User says "An ArcCMS user with this email already exists." | A record already has that address. Edit that record instead. |