<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Administration on back(d)</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/</link><description>Recent content in Administration on back(d)</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://fernandezvara.github.io/backd/docs/operate/administration/index.xml" rel="self" type="application/rss+xml"/><item><title>Command-line administration</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/cli/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/cli/</guid><description>&lt;p&gt;The &lt;code&gt;backd&lt;/code&gt; binary is also the command-line client for administering a realm. &lt;code&gt;backd user&lt;/code&gt; and &lt;code&gt;backd apikey&lt;/code&gt; don&amp;rsquo;t touch MongoDB: they call the realm&amp;rsquo;s &lt;a href="../admin/"&gt;admin API&lt;/a&gt; on a running &lt;code&gt;backd&lt;/code&gt;, as an administrator. They never need database credentials, and every change they make goes through the same checks as any other admin request, including &lt;a href="../../../build/configuration/realm/#network-restrictions"&gt;network restrictions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Two commands write to MongoDB directly instead: &lt;code&gt;backd bootstrap&lt;/code&gt;, which creates a realm&amp;rsquo;s first administrator, and &lt;code&gt;backd secret rotate-key&lt;/code&gt;, which re-encrypts every realm&amp;rsquo;s &lt;a href="../../../build/functions/secrets/"&gt;secrets&lt;/a&gt; under a new master key (see &lt;a href="../admin/#secrets"&gt;Secrets&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>Admin API</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/admin/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/admin/</guid><description>&lt;p&gt;The admin API manages the users and API keys of a realm. &lt;a href="../../../build/auth/users/"&gt;&lt;code&gt;backd user&lt;/code&gt;&lt;/a&gt; and &lt;a href="../../../build/auth/api-keys/"&gt;&lt;code&gt;backd apikey&lt;/code&gt;&lt;/a&gt; are command-line clients of it (see &lt;a href="../cli/"&gt;Command-line administration&lt;/a&gt;), and server-side services can call it directly. It lives under &lt;code&gt;/v1/{realm}/_admin&lt;/code&gt; in every realm with &lt;code&gt;auth: enabled&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every request needs one of the realm&amp;rsquo;s &lt;a href="../../../build/auth/api-keys/"&gt;API keys&lt;/a&gt; with the &lt;code&gt;admin&lt;/code&gt; role, acting as itself, or the session of a user holding one of the realm&amp;rsquo;s &lt;a href="../../../build/configuration/realm/#roles"&gt;admin roles&lt;/a&gt;:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Credential&lt;/th&gt;
 &lt;th&gt;Answer&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;API key with the &lt;code&gt;admin&lt;/code&gt; role&lt;/td&gt;
 &lt;td&gt;Allowed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Session of a user holding an admin role (&lt;code&gt;admin: true&lt;/code&gt; in &lt;code&gt;realm.yaml&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;Allowed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Session of a user whose admin role opens only some &lt;a href="#admin-rights"&gt;areas&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Allowed for those areas; &lt;code&gt;403 forbidden&lt;/code&gt; naming the missing one for the rest&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;API key with the &lt;code&gt;data&lt;/code&gt; role&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;403 forbidden&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;None, or an invalid key&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;401 unauthenticated&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Session of a user without an admin role&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;403 forbidden&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;X-Backd-On-Behalf-Of&lt;/code&gt; with any credential&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;400 invalid_header&lt;/code&gt;: admin calls never act as another user&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class="hd-hint hd-hint--danger"&gt;
 &lt;p class="hd-hint-title"&gt;&lt;i class="ph ph-x-circle hd-icon" aria-hidden="true"&gt;&lt;/i&gt;
Danger&lt;/p&gt;</description></item><item><title>Admin UI</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/admin-ui/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/admin-ui/</guid><description>&lt;p&gt;The admin UI is a web interface for realm administrators and developers. It is a client of the &lt;a href="../admin/"&gt;Admin API&lt;/a&gt; and nothing more: it can do nothing the CLI can&amp;rsquo;t, and every call it makes is authenticated, network-checked and audited by the server like any other. This page is the start of its guide; each area of the interface (users, keys, secrets, audit, functions, data, configuration) is added to it as the area ships.&lt;/p&gt;</description></item><item><title>Audit trail</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/audit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/audit/</guid><description>&lt;p&gt;Each realm with &lt;code&gt;auth: enabled&lt;/code&gt; keeps an &lt;strong&gt;audit trail&lt;/strong&gt;: one record per security-sensitive action or event, with who did it, to what, when and from where. It answers questions such as &amp;ldquo;who gave Bob the admin role?&amp;rdquo; or &amp;ldquo;which key created this user?&amp;rdquo;. Records can be read, but not changed or deleted: they expire after the realm&amp;rsquo;s retention period.&lt;/p&gt;
&lt;h2 id="what-is-recorded"&gt;What is recorded&lt;a class="hd-anchor" href="#what-is-recorded" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Action&lt;/th&gt;
 &lt;th&gt;When&lt;/th&gt;
 &lt;th&gt;Details&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.create&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator (or &lt;code&gt;backd bootstrap&lt;/code&gt;) creates a user&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;password&lt;/code&gt; (whether one was set), &lt;code&gt;roles&lt;/code&gt; (seeded from &lt;code&gt;realm.yaml&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.signup&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user signs up&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;invited&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.password&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator sets a user&amp;rsquo;s password&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.password_change&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user changes their own password&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.verify_email&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator marks an email as verified, or not; or a user verifies it with the link in their email&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;verified&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.password_reset&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user sets a new password with a reset link&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;verified_address&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.email_changed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user&amp;rsquo;s address changes: confirmed by the new address, or set by an administrator&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;by&lt;/code&gt; (&lt;code&gt;self&lt;/code&gt; or &lt;code&gt;admin&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.email_change_reverted&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;The old address undid a change&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.purged_unverified&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A worker deletes accounts that never verified their address&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;count&lt;/code&gt;, &lt;code&gt;older_than&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;push.test&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator sent a &lt;a href="../../../build/push/records/#the-test-send"&gt;test push&lt;/a&gt; to a user&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;send&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;device.removed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator removes a user&amp;rsquo;s push device&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;platform&lt;/code&gt;, &lt;code&gt;device&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.claimed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A link or code verified an address that was never verified, and took the account away from whoever made it: password, providers, second factor and sessions are removed&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;methods&lt;/code&gt;, &lt;code&gt;mfa&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;function.invoke_manual&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator runs a function by hand (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;as&lt;/code&gt; (the user&amp;rsquo;s &lt;strong&gt;id&lt;/strong&gt;, never their email, or null)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;files.versions.regenerate&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator runs &lt;a href="../../../build/files/file-fields/#after-you-change-a-declaration"&gt;&lt;code&gt;backd files regenerate&lt;/code&gt;&lt;/a&gt; (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;version&lt;/code&gt;, &lt;code&gt;missing_only&lt;/code&gt;, &lt;code&gt;job_id&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;storage.reconcile&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator runs &lt;a href="../../storage-maintenance/#reconciling"&gt;&lt;code&gt;backd storage reconcile&lt;/code&gt;&lt;/a&gt; (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;orphans&lt;/code&gt; (how many were found), &lt;code&gt;deleted&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;storage.check&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator runs a &lt;a href="../../providers/storage/#checking-it"&gt;storage check&lt;/a&gt; (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;); never the keys or anything stored&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ok&lt;/code&gt;, &lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;bucket&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;data.check&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator starts a &lt;a href="../../../build/configuration/validation/#finding-documents-that-no-longer-match"&gt;schema check&lt;/a&gt; (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;); the target is &lt;code&gt;data:&amp;lt;database&amp;gt;/&amp;lt;collection&amp;gt;&lt;/code&gt;, &lt;code&gt;data:&amp;lt;database&amp;gt;&lt;/code&gt; or &lt;code&gt;data:*&lt;/code&gt;; never the report&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;collections&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt;, &lt;code&gt;job_id&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;schedule.pause&lt;/code&gt;, &lt;code&gt;schedule.resume&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator pauses or resumes a function&amp;rsquo;s schedule (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;); only a change is recorded; the target is &lt;code&gt;schedule:&amp;lt;database&amp;gt;/&amp;lt;function&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;none&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;triggers.gap_resolve&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator closes a &lt;a href="../../change-feed/#seeing-and-repairing-what-the-dispatcher-did"&gt;gap of the trigger dispatcher&lt;/a&gt; (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;, &lt;code&gt;backd triggers resolve&lt;/code&gt;); the target is &lt;code&gt;trigger-gap:&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;none&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;triggers.rescan&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An operator runs &lt;code&gt;backd triggers rescan&lt;/code&gt; for a collection; the actor is &lt;code&gt;cli&lt;/code&gt;; the target is &lt;code&gt;&amp;lt;database&amp;gt;/&amp;lt;collection&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;trigger&lt;/code&gt;, &lt;code&gt;since&lt;/code&gt;, &lt;code&gt;scanned&lt;/code&gt;, &lt;code&gt;queued&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;job.cancel&lt;/code&gt;, &lt;code&gt;job.rerun&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator cancels a job, or queues a finished one again (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;); the target is &lt;code&gt;job:&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;function&lt;/code&gt;; for a re-run also &lt;code&gt;new_job&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.disable&lt;/code&gt;, &lt;code&gt;user.enable&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator disables or re-enables a user&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.delete&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator erases a user (the tombstone is made; the data work is in the job)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;job_id&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.erased&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;The erase job finished, or failed for good&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;job_id&lt;/code&gt; and &lt;code&gt;counts&lt;/code&gt; per &lt;code&gt;database/collection/operation&lt;/code&gt;; &lt;code&gt;needs_attention&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt; when it failed. Never content&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.delete_account&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user deletes their own account (it is deactivated, not erased)&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;user.networks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user&amp;rsquo;s &lt;a href="../../../build/configuration/realm/#network-restrictions"&gt;network restrictions&lt;/a&gt; change, through the API or from &lt;code&gt;realm.yaml&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;admin_networks&lt;/code&gt;, &lt;code&gt;login_networks&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;identity.apple_revoked&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Apple revoked a user&amp;rsquo;s tokens after their account was erased or deleted, or Apple was unlinked&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;identity.linked&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A provider account is linked to a user, automatically or by the user; also when a provider sign-up creates the user&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;identity.unlinked&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user (or an administrator) removes a sign-in method&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;by&lt;/code&gt; (&lt;code&gt;self&lt;/code&gt; or &lt;code&gt;admin&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;identity.signin_refused&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A provider sign-in for an account that can&amp;rsquo;t sign in (the app is only told &lt;code&gt;signin_refused&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;reason&lt;/code&gt; (&lt;code&gt;disabled&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt;, &lt;code&gt;erased&lt;/code&gt;, …)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;role.add&lt;/code&gt;, &lt;code&gt;role.remove&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A role is assigned or taken away, through the API or from &lt;code&gt;realm.yaml&lt;/code&gt; seeds&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;role&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;data.transfer&lt;/code&gt;, &lt;code&gt;data.assign_org&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A document is moved to another organization, or a job gives a collection&amp;rsquo;s documents without one an organization (admin data route)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;database&lt;/code&gt;, &lt;code&gt;collection&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;to&lt;/code&gt; / &lt;code&gt;org&lt;/code&gt;, &lt;code&gt;job_id&lt;/code&gt;; never content&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.create&lt;/code&gt;, &lt;code&gt;org.update&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An organization is created (by a user or an administrator) or renamed&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;by&lt;/code&gt;, &lt;code&gt;creator&lt;/code&gt; / &lt;code&gt;fields&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.member_add&lt;/code&gt;, &lt;code&gt;org.member_remove&lt;/code&gt;, &lt;code&gt;org.member_leave&lt;/code&gt;, &lt;code&gt;org.roles&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A member is added without an invitation, removed, leaves, or has roles changed&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;user&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt;, &lt;code&gt;by&lt;/code&gt; / &lt;code&gt;added&lt;/code&gt;, &lt;code&gt;removed&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.team_create&lt;/code&gt;, &lt;code&gt;org.team_update&lt;/code&gt;, &lt;code&gt;org.team_delete&lt;/code&gt;, &lt;code&gt;org.team_member_add&lt;/code&gt;, &lt;code&gt;org.team_member_remove&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A team is made, changed or deleted, or someone joins or leaves it&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;team&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt; / &lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.invitation_create&lt;/code&gt;, &lt;code&gt;org.invitation_link&lt;/code&gt;, &lt;code&gt;org.invitation_accept&lt;/code&gt;, &lt;code&gt;org.invitation_revoke&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An organization invitation is made, given a new link, accepted or revoked&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;invitation&lt;/code&gt;, &lt;code&gt;binding&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt;, &lt;code&gt;teams&lt;/code&gt;, &lt;code&gt;sent&lt;/code&gt; / &lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.require_mfa&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An organization turns its second-factor requirement on or off&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.delete&lt;/code&gt;, &lt;code&gt;org.deleted&lt;/code&gt;, &lt;code&gt;org.reactivate&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An organization is deleted (access ends), its cleanup ends, or it is brought back&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;by&lt;/code&gt;, &lt;code&gt;job_id&lt;/code&gt; / &lt;code&gt;counts&lt;/code&gt; (documents removed per collection; never content) / &lt;code&gt;slug&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;org.claims&lt;/code&gt;, &lt;code&gt;org.owner_assign&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Claims are replaced; a manager is assigned&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;keys&lt;/code&gt; / &lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;apikey.create&lt;/code&gt;, &lt;code&gt;apikey.revoke&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An API key is created or revoked&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;role&lt;/code&gt;, &lt;code&gt;networks&lt;/code&gt;, &lt;code&gt;expires_at&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;invitation.create&lt;/code&gt;, &lt;code&gt;invitation.revoke&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An invitation is created or revoked&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;bound_to_email&lt;/code&gt; (whether it is), &lt;code&gt;expires_at&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;invitation.sent&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An invitation is emailed to its address&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;expires_at&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;admin.login&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A user holding an admin role logs in&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;data.create&lt;/code&gt;, &lt;code&gt;data.update&lt;/code&gt;, &lt;code&gt;data.delete&lt;/code&gt;, &lt;code&gt;data.restore&lt;/code&gt;, &lt;code&gt;data.purge&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;A document is written through the &lt;a href="../admin/#data"&gt;admin data route&lt;/a&gt; (a batch audits each operation)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;database&lt;/code&gt;, &lt;code&gt;collection&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;; the target is &lt;code&gt;doc:&amp;lt;database&amp;gt;/&amp;lt;collection&amp;gt;/&amp;lt;id&amp;gt;&lt;/code&gt;; never content&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;session.revoke&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An administrator ends a user&amp;rsquo;s session (&lt;a href="../admin/"&gt;admin API&lt;/a&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;session&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;admin.refused&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;An admin API request is refused: by a network restriction, or because the administrator&amp;rsquo;s roles don&amp;rsquo;t open the &lt;a href="../admin/#admin-rights"&gt;area&lt;/a&gt; or hold the rights of the user or role involved&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;reason&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;realm.bootstrap&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;backd bootstrap&lt;/code&gt; creates the realm&amp;rsquo;s first administrator&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;role&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Failed logins aren&amp;rsquo;t recorded here: they are &lt;a href="../../../build/auth/sessions/#brute-force-protection"&gt;throttled&lt;/a&gt; and counted, and every request is in the access log.&lt;/p&gt;</description></item><item><title>Deleting and erasing users</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/erasure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/erasure/</guid><description>&lt;p&gt;&lt;code&gt;backd&lt;/code&gt; separates two things people call &amp;ldquo;deleting an account&amp;rdquo;:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;What&lt;/th&gt;
 &lt;th&gt;Who&lt;/th&gt;
 &lt;th&gt;Effect&lt;/th&gt;
 &lt;th&gt;Reversible&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Deactivate&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;the user (&lt;code&gt;DELETE /_auth/me&lt;/code&gt;, with their password), or an administrator (&lt;code&gt;PATCH /_admin/users/{id}&lt;/code&gt; with &lt;code&gt;disabled&lt;/code&gt;, &lt;code&gt;backd user disable&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;the user is disabled and every session ends; &lt;strong&gt;all data is kept&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;yes: an administrator reactivates (&lt;code&gt;backd user enable&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Erase&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;an administrator (&lt;code&gt;DELETE /_admin/users/{id}&lt;/code&gt;, &lt;code&gt;backd user delete --yes&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;the user becomes a tombstone, and the policies of your collections are applied (below)&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;no&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;aside class="hd-hint hd-hint--note"&gt;
 &lt;p class="hd-hint-title"&gt;&lt;i class="ph ph-note hd-icon" aria-hidden="true"&gt;&lt;/i&gt;
Note&lt;/p&gt;</description></item><item><title>Compliance with backd</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/compliance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/compliance/</guid><description>&lt;p&gt;Apps that handle personal data usually have to answer four questions: &lt;em&gt;what do you hold about me&lt;/em&gt;, &lt;em&gt;did I agree to this&lt;/em&gt;, &lt;em&gt;stop using my data for that&lt;/em&gt; and &lt;em&gt;delete me&lt;/em&gt;. &lt;code&gt;backd&lt;/code&gt; builds the mechanisms once; the decisions stay yours.&lt;/p&gt;
&lt;aside class="hd-hint hd-hint--warning"&gt;
 &lt;p class="hd-hint-title"&gt;&lt;i class="ph ph-warning hd-icon" aria-hidden="true"&gt;&lt;/i&gt;
Not legal advice&lt;/p&gt;
 &lt;code&gt;backd&lt;/code&gt; gives you tools, not conclusions. Which law applies to you, the legal basis of each use of data, the texts people accept, how long you keep each thing and how fast you must answer a request are decisions for you and your lawyers. Nothing here, and nothing &lt;code&gt;backd&lt;/code&gt; does by default, is a statement that you comply.
&lt;/aside&gt;

&lt;h2 id="what-backd-provides-and-what-stays-yours"&gt;What backd provides, and what stays yours&lt;a class="hd-anchor" href="#what-backd-provides-and-what-stays-yours" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Need&lt;/th&gt;
 &lt;th&gt;What backd gives you&lt;/th&gt;
 &lt;th&gt;What is still yours&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Knowing what is held about a person&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;A personal data scope per collection (&lt;code&gt;personal_data:&lt;/code&gt;), a report of it (&lt;code&gt;backd compliance scope&lt;/code&gt;), and the system data it adds; the same model as erasure&lt;/td&gt;
 &lt;td&gt;Declaring what exempts a collection, and checking that collections mixing several people&amp;rsquo;s data are narrowed with &lt;code&gt;fields&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;A copy of the data&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;The scope and the per-user reads you build on (&lt;code&gt;GET /_admin/users/{id}/owned&lt;/code&gt;, consent history); the export package itself is planned&lt;/td&gt;
 &lt;td&gt;Answering the request within your legal deadline, and verifying who asks&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Consent&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Versioned texts, records that name the exact words (a hash), withdrawal, re-acceptance, rules and email/push gating&lt;/td&gt;
 &lt;td&gt;The texts, which consents you need and why, and what each is used for&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Erasure&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;A tombstone, per-collection policies, reduced consent records, &lt;a href="../erasure/"&gt;retention&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;The policies you declare, backups, and data held outside &lt;code&gt;backd&lt;/code&gt; (your function&amp;rsquo;s calls to other services)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Retention&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;audit.retention&lt;/code&gt;, &lt;code&gt;functions.log_retention&lt;/code&gt;, &lt;code&gt;compliance.consent_retention&lt;/code&gt;, soft-delete retention&lt;/td&gt;
 &lt;td&gt;The periods themselves: they are legal decisions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Minors&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Nothing: age checks and parental consent belong to the app&lt;/td&gt;
 &lt;td&gt;Whether you need them; they can be recorded as &lt;a href="../../../build/auth/consents/#recording-what-the-app-cant-see"&gt;consents&lt;/a&gt; or by functions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="what-counts-as-a-persons-data"&gt;What counts as a person&amp;rsquo;s data&lt;a class="hd-anchor" href="#what-counts-as-a-persons-data" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A user&amp;rsquo;s data is, by default, &lt;strong&gt;the documents whose &lt;code&gt;_meta.owner&lt;/code&gt; is that user&lt;/strong&gt; (whatever their &lt;code&gt;on_owner_delete&lt;/code&gt; action), the documents where their id or email is listed in a &lt;code&gt;pull&lt;/code&gt; field of an &lt;a href="../erasure/"&gt;erase policy&lt;/a&gt;, and the files those documents hold, plus the account itself: identities, sessions, devices, second-factor status, consents, audit records about them and the function invocations they made. Credentials, tokens, secrets and other people&amp;rsquo;s details are never part of it.&lt;/p&gt;</description></item><item><title>Security model</title><link>https://fernandezvara.github.io/backd/docs/operate/administration/security/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/operate/administration/security/</guid><description>&lt;p&gt;This page summarizes how &lt;code&gt;backd&lt;/code&gt; protects data in realms with &lt;code&gt;auth: enabled&lt;/code&gt;, and what the operator is responsible for. To report a vulnerability, see &lt;a href="https://github.com/fernandezvara/backd/blob/main/SECURITY.md"&gt;&lt;code&gt;SECURITY.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="who-can-do-what"&gt;Who can do what&lt;a class="hd-anchor" href="#who-can-do-what" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Caller&lt;/th&gt;
 &lt;th&gt;Proves identity with&lt;/th&gt;
 &lt;th&gt;Can&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Anonymous&lt;/td&gt;
 &lt;td&gt;nothing&lt;/td&gt;
 &lt;td&gt;What &lt;a href="../../../build/auth/rules/"&gt;access rules&lt;/a&gt; allow &lt;code&gt;user == nil&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;User&lt;/td&gt;
 &lt;td&gt;session token (&lt;code&gt;bds_…&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;What access rules allow that user; manage their own account and sessions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Server-side service&lt;/td&gt;
 &lt;td&gt;API key (&lt;code&gt;bdk_…&lt;/code&gt;) with the &lt;code&gt;data&lt;/code&gt; role&lt;/td&gt;
 &lt;td&gt;Everything in the realm&amp;rsquo;s data; act as a user with &lt;code&gt;X-Backd-On-Behalf-Of&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Management tooling&lt;/td&gt;
 &lt;td&gt;API key with the &lt;code&gt;admin&lt;/code&gt; role&lt;/td&gt;
 &lt;td&gt;The same, plus the &lt;a href="../admin/"&gt;admin API&lt;/a&gt;: users, roles, invitations, API keys&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Administrator&lt;/td&gt;
 &lt;td&gt;session of a user holding an &lt;a href="../../../build/configuration/realm/#roles"&gt;admin role&lt;/a&gt;, for example through &lt;a href="../cli/"&gt;&lt;code&gt;backd login&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;What access rules allow that user, plus the admin API&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Operator&lt;/td&gt;
 &lt;td&gt;access to &lt;code&gt;CONFIG_DIR&lt;/code&gt; and MongoDB&lt;/td&gt;
 &lt;td&gt;Everything, including creating a realm&amp;rsquo;s first administrator with &lt;a href="../cli/#the-first-administrator"&gt;&lt;code&gt;backd bootstrap&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Credentials belong to one realm and are unknown in every other realm. Invalid, expired or revoked credentials are always refused (&lt;code&gt;401&lt;/code&gt;), never downgraded to anonymous access.&lt;/p&gt;</description></item></channel></rss>