Files
portal/docs/getting-started.md
T
Bendik Aagaard LynghaugandClaude Opus 5.5 641c5f1bd3
Test / test (pull_request) Successful in 51s
Docs: getting started, bringing your people in
From an empty Kanidm to everyone at their own desk: what in the content
decides who needs an account, the four things Kanidm needs for portal,
the first person, what happens at start, how everyone after comes in
from the desks, what the people who ask the questions can do, and what
each failure looks like.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
2026-09-29 18:02:02 +02:00

6.6 KiB

Getting started: bringing your people in

A site is run by a handful of people: whoever answers for each question it asks, and whoever works each desk. This is how they get in - from an empty Kanidm to everyone signed in at their own desk - without anyone handing out passwords or running an admin tool per person.

The idea in one line: the content says who is involved, and portal makes their accounts. A page names who is responsible for it; a directory is gated on a group; a desk may invite into groups. Portal reads that and does the rest at start.

What you need

  • A content repo, and a portal instance running it (Operations has adding a site).
  • A Kanidm of the site's own. Group names below are exactly the ones the content uses, with no prefix; that is only safe when the Kanidm serves this site alone.
  • Mail: mail: { from } in site.yaml, and gdo on the host. Without it accounts are still made, but nobody hears about them.

1. Say who is involved, in the content

Three things in the content decide who needs an account:

content who what they get
responsible: { name, contact } on a page the person answering for that question an account, and a mail saying they are listed as responsible for asking it
qualifies: styret on a page or _section.yaml members of that group the pages and desks under it
invite: { group: kasserer } on a desk page the desk's own group the right to bring people into kasserer

The desk whose group may invite into the most groups is the site's most privileged one; on a vel that is the board. Portal works that out from the content (see step 4).

2. Set up Kanidm for portal

Portal needs four things from Kanidm. The tomtervel/infrastructure repo's kanidm-setup.sh does all of them and is a good starting point; by hand, as idm_admin:

K="kanidm -D idm_admin -H https://id.example.no"

# An onboarding account: may create people and issue a first password
# link, nothing more. pii_read lets an invite find someone who already
# has an account by their email instead of making a second one.
$K service-account create portal-onboarding "Portal onboarding" idm_admin
$K group add-members idm_people_on_boarding portal-onboarding
$K group add-members idm_people_pii_read portal-onboarding

# One group per `qualifies:` in the content, managed by that account:
# adding a member to a group takes the right to manage it.
for g in styret kasserer trafikk; do
  $K group create "$g" portal-onboarding
done

# The sign-in client. Everyone in this Kanidm may sign in; what they
# see comes from their groups, in the `groups` claim.
$K system oauth2 create portal "My site" https://site.example.no
$K system oauth2 add-redirect-url portal https://site.example.no/auth/callback
$K system oauth2 update-scope-map portal idm_all_persons openid profile email
for g in styret kasserer trafikk; do
  $K system oauth2 update-claim-map portal groups "$g" "$g"
done
$K system oauth2 update-claim-map-join portal groups array

# The onboarding token, read-write, shown once: into portal's env.
$K service-account api-token generate portal-onboarding portal --readwrite

Then portal's environment:

variable value
KANIDM_URL https://id.example.no
OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET the client above (show-basic-secret)
KANIDM_API_TOKEN the onboarding token

3. Name the first person

Someone has to be first: every later person is invited from a desk, and on an empty Kanidm there is no desk anyone can open yet.

variable value
SEED_ADMIN_EMAIL the first person's address
SEED_ADMIN_NAME their name, as it should appear (optional)
SEED_GROUP a group to put them in, if not the most privileged one (optional)
RESPONSIBLE_GROUP a group every responsible person joins, e.g. redaktor (optional)

4. Start portal

At start, portal:

  1. Invites the first person into SEED_GROUP, or the most privileged group, and mails them the one-time link. Once: it is remembered in the portal_seed bucket, so restarts and upgrades never send a second link.
  2. Makes an account for everyone named responsible who has none, and mails them that they are listed as responsible for asking those questions, with their link. With RESPONSIBLE_GROUP they all join it; someone who already had an account is added without a mail.

Kanidm may still be starting beside portal, so a failed attempt is tried again, a minute apart. The log says what happened, per person.

5. The rest come in from the desks

From here nobody touches Kanidm:

  • At a desk, whoever may invite fills in a name and an address. Portal makes the account, adds them to the group, and mails the link. The invites sent are listed on that desk.
  • A decision can be the invitation. A state with grants: group in aggregates.yaml puts the person a case is about into that group when the case arrives there - an approved committee application that is the membership.
  • A new page with a new responsible person gets them an account at the next start.

6. What the people who ask the questions can do

Signed in, a person a page names as responsible sees a card at the foot of their own pages to suggest a change. The server checks it is really them; the suggestion is kept (portal_edit_suggestions), announced (portal.edits.suggested), and mailed to the site's inbox with them as reply-to, so answering it answers them.

Their group can also be the way into other tools. The vel's redaktor group signs in to the project Gitea with the same account: a second OAuth2 client scoped to that group alone.

When it does not work

what you see why
an invite fails with 403 setting mail a portal before 0.5.4 set the address in a second call; the onboarding account may create but not modify
an invite fails with 404 adding to a group the group is not managed by portal-onboarding: group set-entry-manager <group> portal-onboarding
Item not found setting the login page's name or logo those are system settings only admin may change, not idm_admin - or the CLI and server versions differ
accounts are made but nobody is mailed site.yaml has no mail.from, or gdo is not running on the host
someone responsible never got a mail they already had an account (they are only added to RESPONSIBLE_GROUP), or their contact is not an email address
the first person was invited twice it cannot be, per address and group; changing SEED_ADMIN_EMAIL or SEED_GROUP invites the new pair