feat: identify the authenticated account in the userinfo claims

This commit is contained in:
2026-09-19 10:54:06 +02:00
parent 2cb4871268
commit ec83ad598f
5 changed files with 241 additions and 5 deletions
+23 -2
View File
@@ -379,7 +379,7 @@ Responses:
OIDC-style claims for the authenticated user. The response contains only the claims covered by the granted scopes:
- always: `email`
- always: `sub` (string), `email`
- scope `id`: `person_id`, `address_id`
- scope `roles`: `roles` (array; only the roles that actually grant something are exported — the implicit baseline role is stripped, and so are the `*_PENDING` markers of roles the BusPro CRM claims but nobody has approved yet, see `docs/buspronet-schema/crm-selection-queries.md#from-claim-to-role`)
- scope `profile`: `profile` object:
@@ -394,7 +394,28 @@ OIDC-style claims for the authenticated user. The response contains only the cla
}
```
Note: `profile.communication.email` comes from the CRM address record and is **not necessarily** the login email — a single address can hold several contacts. Use the top-level `email` claim for identity.
##### Identifying the account: match on `sub`
A BusPro address record holds several email addresses (private and business, say), and BusPro
accepts **any** of them as a login. Each one is a **separate MyE&P account with its own roles**
that is intended, not a duplicate: administrative roles are reserved for the company address, so
the same person signing in privately is a Teamer:in or Kund:in and signing in with their
`@ep-reisen.de` address is an administrator.
All of those accounts report the **same** `person_id` and `address_id`, and the same
`profile.communication.email` — that value is the first contact address on the BusPro record and
is **not necessarily** the one signed in with. So:
- **`sub`** — opaque, stable, unique per MyE&P account. The only claim that identifies an account.
Match your local user on it and store it.
- **`email`** — the address this session actually authenticated with. Distinct per account, but
treat it as a display and contact value; it is not the account key.
- **`person_id` / `address_id`** — the BusPro person behind the account. Shared between that
person's accounts, so they identify a *human*, never an account. Do not match on them.
Do not derive staff status from an email domain. MyE&P decides who is a member of staff and
exports the result as `ROLE_EMPLOYEE` in the `roles` claim; re-deriving it from `email` or from
`profile.communication.email` will disagree with MyE&P in both directions.
`400 {"message": "...", "code": "..."}` when the upstream lookup fails or rejects the credentials.