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:

RoleMay
adminEverything, including the whole admin area (/admin/...).
userTheir 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

  1. The first admin comes from the setup wizard on a fresh install: see Create the first admin.

  2. 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 (user unless 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).

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:

  1. Access: removes the Arc CMS claims and ends every session, before anything else, so a failure later never leaves a removed admin an admin.

  2. Firestore: every subcollection under users/{docId} at any depth, the person's Feedback, and their in-app Notifications.

  3. Storage: the per-user folder users/{docId}/ (under the install's upload folder, if it has one) and the profile photos in avatars/{uid}/.

  4. Sign-in: the Firebase Auth account, unless another app owns or shares it (authOwner is host or shared), plus the email_lookup entry, 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).

  5. Event: user.deleted on the event bus, with userId (the Auth uid) and data.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

What it stores

WhereWhat
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/usersSign-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_adminMarks 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:

FunctionDoes
adminCreateUserCallable, admins: Add User.
adminSetPasswordCallable, admins: Edit, Update Password.
deleteMyAccountCallable: the person deletes their own account. Never a locked app account: its app deletes it (App accounts).
refreshMyClaimsCallable: puts the claims back on the caller's token at sign-in.
claimFirstAdminCallable: the setup wizard's first admin, once.
syncAllUserRolesCallable, admins: re-applies every account's claims from its record.
fillAccountSourcesCallable, 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.
onUserRoleChangeOn every record write: applies the default role to a sign-up, and keeps the claims in step with the role and the block.
onUserCreated, onUserCreateWelcomeEmailOn a new record: the email lookup, the admin alert (not for an app account) and user.signed_up event, and the welcome email.
onUserDeletedOn a deleted record: the cleanup above.

See Cloud Functions and Data model.

Who can do what

ActionWho
Read a users recordThe person themselves, and admins
Create a recordAdmins and the server. Every sign-up creates its record on the server.
Edit own recordThe person, except role, uid, isActive, status, authOwner, email, phone, phoneVerified, the detach fields and the plan and credit fields
Edit any record, delete a recordAdmins
Give a role above userAdmins and the server only. A role written by anyone else is reverted by onUserRoleChange.
Read a per-user Storage folderThe 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

SymptomCause 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 accountsEach 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 AllTheir 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 indexThe 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 sectionAdmins cannot delete themselves. Another admin deletes them under Users.
Deleted a user, but their sign-in still existsThe 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.