Identity and Access

Table of Contents

1. Summary

Access control in this system is decided in two places, and knowing which is which is the point of reading the cluster in order. The application decides what an authenticated actor is allowed to ask for, through roles and permissions. The database decides what rows that actor may see at all, through row-level security. The second is the backstop: a bug in the first is contained by it, which is why both exist.

Between those two sits the awkward case that generates most of the subtlety here — a service acting on behalf of a user rather than as itself. Read the cluster as: what an identity is, what a role grants it, how a service borrows one, and what the database enforces regardless.

2. Reading order

2.1. What an identity is

Identity and Access Management — start here. The identity lifecycle, authentication against authorisation, and the vocabulary the rest of the cluster uses. The authentication and authorisation distinction is worth slowing down on: almost every access bug is one being mistaken for the other.

2.2. What a role grants

Role-Based Access Control — roles compose permissions, users are assigned roles. Read second, because it is the concrete model the abstract vocabulary above resolves to, and it is what the application layer actually consults.

Book Access and Permissions — the same model applied to the entity where it matters most. Useful as the worked example: the allowed-currency set that constrains what may be booked shows permissions doing real domain work rather than guarding a screen.

2.3. How a service acts for a user

Service-to-Service Auth Patterns — what happens when one service must call another, and the choice between a service acting as itself and acting for the caller.

Internal Actor Impersonation — the pattern we use: a service self-mints a short-lived token impersonating a specific end user. Read it straight after the patterns note, because it is the one we chose from among them, and read both before touching any service-to-service call.

2.4. What the database enforces regardless

PostgreSQL Row-Level Security — the database mechanism, described before any project-specific use of it. Deliberately last: it is the backstop, and it is easier to see why the backstop is shaped as it is once the application-level model above is clear. An agent changing a query that crosses a tenant boundary should have read this page first.

2.5. What a person does with it

User Journeys — everything above says what the system enforces. This one records what a person is trying to do, written from the goal rather than from the entity. Read it when the question is "what should this screen do" rather than "what does this entity hold". Each journey document also lists the operations and subjects its steps need, so the distance between the design and the server shows up as a table rather than as a surprise during the build.

3. Reading it in reverse

There is one case for inverting the order. If you are debugging a query that returns fewer rows than expected, start at row-level security and work upwards: the database is the layer most likely to be silently filtering, and it does so by design rather than by error.

4. See also

  • Knowledge — the index this structure note hangs from.
  • Zettelkasten — what a structure note is and why the order is authored rather than computed.

Emacs 29.3 (Org mode 9.6.15)