Identity, Authentication, and Authorization Boundaries
Start with one Northstar employee opening one supplier record, then place every identity and permission decision at its real owner.
Overview
The enterprise problem and today’s slice
Alice can sign in successfully and still be forbidden from reading supplier S-104. A safe design separates identity (the durable subject being discussed), authentication (evidence that a claimant controls that identity), and authorization (a current decision that this subject may perform this action on this resource).
Today you will trace one request through those boundaries and produce AUTH-R01, a boundary map with a positive request and a same-person/wrong-resource denial. If the entry check cannot distinguish “Alice signed in” from “Alice may read this record,” use this day as the back-route before continuing.
Customer outcome and implementation focus
Northstar needs a denial that identifies the correct boundary without exposing whether a foreign supplier exists. The bounded outcome is a request context that carries verified identity evidence into a separate resource decision; it is not a universal security architecture or proof of production isolation.
Components in focus
The identity service verifies authentication evidence. The policy service decides authorization from current tenant, role, action, and resource state. The API runtime enforces the decision, while PostgreSQL owns memberships and supplier records and an append-only evidence store owns redacted decision receipts.
This five-box path is the course map. Later days keep every ID, label, direction, and edge, then add only the new mechanism being taught.
Trace one request without granting by accident
A valid session supplies identity evidence, not permission. Resolve the tenant and subject from trusted server state, ask policy about the exact action and resource, and enforce before fetching protected data.
type RequestContext = {
subjectId: string;
tenantId: string;
authenticationEventId: string;
};
const decision = await policy.decide({
context,
action: 'supplier.read',
resource: { type: 'supplier', id: 'S-104' },
});
The server interprets this declaration, the policy store supplies current membership and rules, CPU evaluates one decision, and the observable result is an allow or stable denial ID. Neither the browser nor the database row grants access by itself.
HTTP Semantics, RFC 9110 distinguishes authentication challenges from authorization failures at the protocol surface; application policy still needs its own resource-specific decision and privacy-safe response.
Challenge the boundary
Run the unscored worked case first: Alice belongs to Northstar Procurement and reads Northstar supplier S-104. Then keep Alice authenticated but change only the resource tenant. The second request must deny without changing the first path.
The scored check changes one unknown: choose the first boundary that should reject a supplied same-user/wrong-resource trace. Selecting authentication reveals the misconception “login is permission”; replay the case with the authenticated subject held constant and the resource owner changed. Declined checks include protocol trivia, multiple simultaneous faults, and free-form claims that cannot be falsified.
Carry the boundary map forward
Record actor, tenant, action, resource, authentication event, policy version, expected result, observed result, environment, timestamp, and immutable decision ID. AUTH-R01 is consumed by Day 02; no learner mastery or production-security claim follows from this bounded map.