2. Members
Turn authentication on: sign-up, sessions, roles, and an account page with password change and account deletion.
Chapter 1’s realm was open to anyone on localhost. Now members sign up and sign in — and the app learns who you are: your gallery, your assets, your account page.
The realm grows
Replace config/shelf/realm.yaml:
auth:
strategies:
password: [password]
signup: open
roles:
admin:
description: "Operators: users, invitations and API keys"
admin: true
users:
- operator@shelf.example
curator:
description: Publishes assets and manages share links (chapter 5)
users:
- curator@shelf.example
auth— turns authentication on: users, sessions and roles exist; anonymous callers get401. Itsstrategieslist the ways to sign in;password: [password]is email and password, the only one this tutorial needs for now.signup: open— anyone may create an account (alternatives:invite,closed). It is open only for this chapter and the next: chapter 4 closes it, and from then on every new member needs an invitation — which only an existing administrator can create.roles:—adminis the operator role (admin: truegrants the admin API);curatormatters from chapter 5. Theusers:lists are seed assignments: when someone signs up with a listed address, the role attaches. A shortcut for local stacks — never keep seeded users in a real realm.
Apply, and create the three accounts
docker compose logs --since 1m backd | grep 'config reloaded' # backd follows config/: it loaded the change
Open http://localhost:8080 and sign up (any password of 12 or more characters; the demo stack sends no email yet and account.require_verified_email is off, so nothing needs verifying — the verify-email and welcome messages only appear once chapter 10 wires email) as each of:
| Why you need it | |
|---|---|
operator@shelf.example | the administrator: chapter 4 invites with it, chapters 10 and 12 use the Admin view |
curator@shelf.example | the curator: publishes assets from chapter 5 on |
| your own address | a plain member, to see what the rules refuse |
Do it now. Once chapter 4 sets signup: invite, a new address can’t sign up without an invitation, and nobody can create an invitation without an administrator — so an operator who hasn’t signed up yet would lock you out (the way back is backd-server bootstrap, but it is easier not to need it). Log out between accounts (Log out in the nav), or use a private window for each.
backd-server bootstrap --realm shelf --email you@example.com is how a real deployment creates its first admin, and the way out of that lock-out.
Signing in
The app’s Sign in button now does something: backd.auth.signup() or .login() returns a session the client keeps in localStorage (storage: localStorageStorage('shelf') — it survives reloads). backd.auth.me() on load restores it. A token in localStorage is readable by any script on the page, so a real app guards against XSS — or uses HttpOnly session cookies, which the client supports with cookies: true.
What the app gains
- Nav state:
backd.auth.me()at load; sign-in button ↔ email + log out. - My assets:
assets.list({ where: { "_meta.owner": user.id } })—_metafields are queryable like any other. - Account page:
backd.auth.changePassword()works now; email change and password reset are visible but disabled — they need the email stack of chapter 10. - Delete my account:
backd.auth.deleteAccount()deactivates — your email stays registered, your documents stay. Actual erasure is an admin action that applies each collection’s policy (Deleting and erasing users):
Create config/shelf/main/assets/collection.yaml, and the same file for shares, then restart:
# What happens when an administrator erases a member: their assets go with
# them (and so do their share links, from the same file in shares/).
on_owner_delete:
action: delete
action: delete says a member’s assets — and their share links — go with them. The blog example shows the alternative (anonymize). collection.yaml is where a collection’s policy lives: this chapter puts its erase policy in it, chapter 3 adds the access rules, and chapter 13 the file fields.
You should see
GET /v1/shelf/main/assetswithout a session answers401— the chapter-1 curl now needs a sign-in first.- Signing up and reloading keeps you signed in; Log out ends it.
operator@shelf.exampleandcurator@shelf.exampleexist, with the password you chose, next to your own account — and the operator’s session hasroles: ["admin"](backd.auth.me()).- My assets lists only what you created; the account page changes your password and the new one signs in.
- Deleting your account signs you out; signing up again with the same address says it’s taken (deactivated, not gone).
Next: chapter 3 — the rules: of each collection decide who may touch what.