Service accounts
A service account is an identity for a machine rather than a person: an integration, a reporting job, an AI support agent. It has its own roles, it keeps working when colleagues leave, and it can be capped at read-only no matter which tokens are created for it.
Why not a personal token?
A personal access token acts as the colleague who created it. That's fine for trying things out, but not for something that keeps running:
- When the colleague leaves or loses a role, the integration stops working, or it quietly gains access when they are promoted.
- Everything the integration does is logged as the colleague's own work.
- You can't give the integration less than the colleague has.
A service account fixes all three. It has exactly the roles you give it, nothing it does is attributed to a colleague, and its access level decides once and for all whether any of its tokens may write.
A service account signs in with API tokens only. It has no password and can't open the admin.
Create a service account
Service accounts are managed by super admins:
- In the admin, open Einstellungen → Integrationen → API and choose Service-Accounts verwalten.
- Choose Neuer Service-Account and fill in:
- Name: how admins recognise it, for example "Support-Agent". The name appears in logs and on comments the account writes.
- Beschreibung: what the account is for and who is responsible for it.
- Zugriff: Nur lesen or Lesen und schreiben. See Access level.
- Rollen: which sections of the admin the account can see. See Roles.
- On the account's page, create a token under Tokens. Give it a label, choose its Zugriff, and set an expiry date. Lesen und schreiben is only offered when the account's own access level allows writing, and a disabled account can't get new tokens.
- Copy the token. It starts with
svc-and is shown this one time only.
Roles
A service account gets the same roles as a colleague. They decide which endpoints it can use (see Permissions):
| Role | Admin label | Unlocks |
|---|---|---|
ROLE_ADMIN | Admin | offers, editions, hosts, attendances, accounts, consents, comments, sent messages, search |
ROLE_PARTICIPANTS_ADMIN | Teilnehmer:innen | participants, and the names of an account's participants; only together with Admin |
ROLE_PAYMENTS_ADMIN | Zahlungen | receipts, debtors, and an account's debtor; only together with Admin |
ROLE_SUPER_ADMIN | Super-Admin | everything: includes Admin, Teilnehmer:innen and Zahlungen, plus creating admin accounts and changing admin roles |
ROLE_HOST | Veranstalter:innen | editions and offer categories only, see below |
A new service account gets the role Admin and the access level Nur lesen. Add Teilnehmer:innen or Zahlungen only when its job needs participants or payments: every role opens more personal data to its tokens. Both count only together with Admin or Super-Admin, and the admin won't save them without one of the two.
Host users see the offers of the hosts they are members of. A service account is not a member of any host, so with Veranstalter:innen alone it sees no offers and no hosts. The same goes for any service account without Admin: even the published offers only come back without a token. Give it Admin if it needs offers.
A service account always belongs to exactly one tenant. The global admin role of multi-tenant installations can't be given to it.
Access level
The access level is the ceiling for every token the account holds:
read(Nur lesen): every token of the account can only read, even one that was created with write access before the account was restricted. A read-only service account can't change anything, but it reads everything its roles allow.write(Lesen und schreiben): tokens can read and, if they were created with write access, also write.
Changing the access level takes effect on the next request of every token.
Create one from the command line
On the server, ferienpass:api:service-account creates a service account and its first token in one go. That's useful for provisioning an integration without a browser, or for a new tenant where no super admin has signed in yet.
A read-only reporting job with one role and an expiring token
bin/console ferienpass:api:service-account "Auswertung" --tenant=elmsbrueck \
--role=ROLE_ADMIN --valid-until="+90 days" \
--description="Monthly report on attendances"
A read-only account that also reads participants
bin/console ferienpass:api:service-account "Statistik" --tenant=elmsbrueck \
--role=admin --role=participants_admin
- Name
name- Type
- argument
- Description
A name admins recognise the account by. Required.
- Name
--tenant- Type
- string
- Description
The tenant (its slug). Required on multi-tenant installations; run
ferienpass:tenant:listto see them.
- Name
--access- Type
- string
- Description
read(default) orwrite.
- Name
--role- Type
- string
- Description
A role to grant, repeatable. Accepts
ROLE_ADMINor justadmin. Defaults toROLE_ADMIN.participants_adminandpayments_adminneedadminnext to them; the command refuses them otherwise.
- Name
--description- Type
- string
- Description
What the account is for.
- Name
--token-name- Type
- string
- Description
A label for the first token.
- Name
--valid-until- Type
- string
- Description
Expiry of the first token, as a date (
2027-01-01) or relative (+90 days). Without it, the token doesn't expire.
- Name
--no-token- Type
- flag
- Description
Create the account only, and create tokens in the admin later.
The command prints the token once. Store it like a password.
Manage tokens
A service account can hold several tokens, for example one per environment. On the account's page you see when each token was last used (to within five minutes), and you can:
- Revoke a token. It stops working immediately. Do this when a token is no longer needed or may have leaked, and to rotate a token: create the new one, switch the integration over, then revoke the old one.
- Disable the account. All its tokens are refused with
401(Service account disabled) until you enable it again. Use this to pause an integration without losing its setup. - Delete the account. Deletes it together with all its tokens.
End-to-end encryption
Where a tenant encrypts the personal data of its participants end to end, a service account sees their names only as pseudonyms until it holds a key of its own. The integration makes the key itself and registers it; a super admin confirms it in an emoji comparison and decides what it reads: every participant, or the children of one host. See End-to-end encryption.
On the service account's page, super admins find the key under Verschlüsselung: whether there is none, one waiting or one confirmed, its fingerprint and key ID, what it reads and who confirmed it. Schlüssel widerrufen takes it back at once, and deleting the service account does so too.
What a service account leaves behind
fepli names a service account where a record keeps a name as text. Records that point to a person's account don't name it:
- Comments it writes show its name as
authorName. - Consents it revokes show its name as
revokedBy. - Host invitations it sends name it in the e-mail; their
invitedByisnull. While an edition asks hosts to sign a confidentiality declaration, it can't invite anyone to register a new host for that edition (409): a service account can't sign. - Receipts it records have no
recordedBy, because that field points to a person's account. TheirrecordedByNamereads{name} (Service-Account). - Changes it makes to attendances appear in the attendance's history in the admin as
{name} (Service-Account). Attendances it creates count as entered by the team (createdByAdmin). - Offer workflow transitions it applies (publish, cancel, …) appear in the offer's history in the admin as
{name} (Service-Account). - Each of these keeps the name the service account had at the time.
- Nobody gets the e-mails about the participant list of offers it creates; who gets them is chosen in the admin, under Listen-Empfänger:innen. Like every new offer, they take their contact from the first host's profile unless you send
contact(Create an offer).