Authenticate Humans and Map Identity Across Three Planes
Authenticate a person once where appropriate, but authorize and revoke that person independently in the provider, hosted-runtime, and generated-application planes.
Run it in the public monorepo
This course is built around the public Zheta Kubernetes Lab monorepo. The excerpt below is runnable source, not pseudocode.
Source: services/shared/auth.py
if claims.get("iss") != issuer or claims.get("aud") != audience or int(claims.get("exp", 0)) <= int(time.time()):
raise PermissionError("expired or wrong-scope bearer token")
if not claims.get("sub") or not claims.get("org"):
raise PermissionError("bearer token lacks tenant identity")
return Identity(str(claims["sub"]), str(claims["org"]))
Code to reality
- Declared intent
- Derive actor and tenant authority only from a signed, scoped, unexpired identity token.
- Interpreter
- The shared authentication adapter verifies cryptographic and semantic claims before MVC dispatch.
- Software effect
- Accepted requests carry an immutable actor and organization identity; invalid requests stop at the boundary.
- Hardware effect
- Signature verification consumes service CPU but denied calls allocate no downstream runtime or data resources.
- Observable evidence
- Positive tenant access and wrong-signature, wrong-audience, and cross-tenant denials identify the boundary.
Start with the people and the result they need
The source tables below remain the detailed contract. Begin with these customer paths:
- D10-UC-01
- Person: Organization administrator
- Job: Grant a colleague provider project access and a separate generated-app role
- Observable result: Colleague can edit an app specification and view authorized app-domain records through distinct sessions
- D10-UC-02
- Person: Generated-app tenant administrator
- Job: Revoke an app user's role without removing their provider account
- Observable result: App-domain request is denied after revoke; provider project read remains allowed
Turn each customer job into a testable story
Now turn each customer job into a story with a result that an engineer can check:
- D10-US-01
- Story: As an organization administrator, I want explicit plane-local grants for one enterprise subject, so that authentication convenience does not…
- Observable acceptance: Subject maps to separate provider principal, runtime operator principal if approved, and app user; each token has a distinct audience
- D10-US-02
- Story: As a generated-app tenant administrator, I want app roles independently revocable, so that app data access can stop without changing provider…
- Observable acceptance: Revoked app session fails; provider read succeeds; runtime access remains absent unless separately granted
Add real state and observable proof
Finally trace each story through the system that owns its state and the evidence that proves the outcome:
- D10-FLOW-01
- Trigger: Administrator invites colleague to a project and app tenant
- Responsible systems: Enterprise IdP, Identity and Organization service, Runtime Gateway, generated-app identity adapter
- Authoritative state: Provider membership store and generated-app user/role store
- Owned record: ProviderMembership
- Observable evidence: Actor, enterprise subject, mapping/grant IDs, audiences, resources, expected/observed results, environment, timestamp, traces
- Failure signal: Unknown subject, wrong token audience, absent mapping, or role denial
- D10-FLOW-02
- Trigger: App admin revokes app role and colleague retries with app and provider sessions
- Responsible systems: Generated-app identity/authorization service and Audit Evidence
- Authoritative state: Generated-app grant/session state; provider membership remains separately authoritative
- Owned record: GeneratedAppUserGrant
- Observable evidence: Revocation ID, denied app trace, provider positive-control trace, runtime denial, immutable evidence ID
- Failure signal: Session survives revoke, provider grant changes unexpectedly, or runtime permission appears
The enterprise problem and today’s slice
Enterprise problem: Reusing one role or token across platform administration, runtime operations, and generated-app data turns organization membership into unintended access to deployments and customer records.
Whole-course context: Workload and delegated connector grants are separate design records rather than implemented authorities; today establishes the provider identity baseline before collaboration and publication.
Today’s slice: Design three plane-local principal mappings and inspect the provider-plane JWT identity implemented today; hosted-runtime operator and generated-app user grants are not yet implemented.
End-of-day evidence: A five-minute provider token and tests for signature, issuer, audience, expiry, subject, and organization prove the implemented boundary; plane-local grants and independent revocation remain explicit missing evidence.
Still unsolved: Sharing invitations, publication approval, release promotion, AWS federation, and production incident roles remain later slices.
Customer use cases
Single sign-on can establish who a person is, but each plane must decide what that person may do. These use cases create explicit mappings and revoke only one plane.
| Use case ID | Actor | Customer job | Success outcome | Denial or recovery evidence |
|---|---|---|---|---|
| D10-UC-01 | Organization administrator | Grant a colleague provider project access and a separate generated-app role | Colleague can edit an app specification and view authorized app-domain records through distinct sessions | Provider token at generated-app API is denied while correct app session succeeds |
| D10-UC-02 | Generated-app tenant administrator | Revoke an app user's role without removing their provider account | App-domain request is denied after revoke; provider project read remains allowed | Revocation trace, denied app request, and unaffected provider positive control |
Actor-centred user stories
An identity mapping is not permission inheritance. These stories require independent grant IDs, audiences, policy owners, and revocation results.
| Story ID | Use case IDs | User story | Observable acceptance conditions |
|---|---|---|---|
| D10-US-01 | D10-UC-01 | As an organization administrator, I want explicit plane-local grants for one enterprise subject, so that authentication convenience does not collapse authorization boundaries | Subject maps to separate provider principal, runtime operator principal if approved, and app user; each token has a distinct audience |
| D10-US-02 | D10-UC-02 | As a generated-app tenant administrator, I want app roles independently revocable, so that app data access can stop without changing provider employment or project membership | Revoked app session fails; provider read succeeds; runtime access remains absent unless separately granted |
End-to-end product flows
The colleague signs in through an enterprise identity provider, then each product surface exchanges that identity for a plane-specific session. No surface accepts another plane's token audience.
| Flow ID | Use case IDs | Path | Trigger | Numbered steps | Terminal evidence |
|---|---|---|---|---|---|
| D10-FLOW-01 | D10-UC-01, D10-UC-02 | Happy | Administrator invites colleague to a project and app tenant | 1. Identity provider authenticates subject.; 2. Organization service creates provider grant.; 3. App admin creates app-user mapping and role.; 4. Each issuer creates scoped session.; 5. Colleague performs one action in each allowed plane. | Actor, enterprise subject, mapping/grant IDs, audiences, resources, expected/observed results, environment, timestamp, traces |
| D10-FLOW-02 | D10-UC-01, D10-UC-02 | Denied | App admin revokes app role and colleague retries with app and provider sessions | 1. App grant becomes revoked.; 2. App session is invalidated.; 3. App request is denied.; 4. Provider project read succeeds.; 5. Runtime operation remains denied. | Revocation ID, denied app trace, provider positive-control trace, runtime denial, immutable evidence ID |
The administrator begins a provider-plane relationship. That invitation alone cannot create a generated-app user or hosted-runtime operator.
System design derived from the flows
One identity provider may authenticate the person, but separate policy decision points authorize each audience. Explicit mapping records connect opaque subject IDs without merging stores.
| Use case ID | Entry point | Responsible services | Authoritative store | Failure evidence |
|---|---|---|---|---|
| D10-UC-01 | Forge Studio invite and generated-app admin action | Enterprise IdP, Identity and Organization service, Runtime Gateway, generated-app identity adapter | Provider membership store and generated-app user/role store | Unknown subject, wrong token audience, absent mapping, or role denial |
| D10-UC-02 | Generated-app role revoke | Generated-app identity/authorization service and Audit Evidence | Generated-app grant/session state; provider membership remains separately authoritative | Session survives revoke, provider grant changes unexpectedly, or runtime permission appears |
The enterprise subject can map to three principals, but each mapping is optional and each plane issues or accepts only its own audience and grants.
Data model and ownership
A shared users table would let provider administrators rewrite generated-app roles. Each plane stores its own principal and grant, joined only by opaque subject references.
Generated-application database: Not created in this runnable slice — the generated-application user, role, session, and predicate records below are the target ownership contract, while current code persists provider project collaborators only.
| Record or entity | Store and owner | Primary key | Foreign key or opaque reference | Tenant key | Material constraint | Lifecycle and deletion | Use case IDs |
|---|---|---|---|---|---|---|---|
| ProviderMembership | Control-plane PostgreSQL, owned by Identity and Organization service | membership_id | Opaque enterprise subject and project IDs | organization_id | Role scoped to provider resources; token audience cannot access runtime/app APIs | Invited, active, suspended/revoked; retained for provider audit then deleted | D10-UC-01, D10-UC-02 |
| GeneratedAppUserGrant | Generated-app PostgreSQL, owned by generated-app identity service | app_user_grant_id | Opaque enterprise subject reference; local user and role FKs | app_tenant_id | App role and session independently revocable; every data predicate uses app tenant/user | Invited, active, revoked; sessions invalidated; exported/deleted under app policy | D10-UC-01, D10-UC-02 |
The two durable grants can refer to the same enterprise subject while retaining different owners, tenants, audiences, lifecycles, and revocation evidence.
Prove independent revocation
Inspecting token claims cannot prove every API rejects the wrong audience. The current implementation has one provider audience, forge-control-plane, and derives its value when minting a short-lived local token; it cannot prove independent runtime or generated-app revocation. Read the exact development-token tool in scripts/mint-local-token.py.
claims = encode({"sub": os.getenv("ACTOR", "owner@acme.test"), "org": os.getenv("ORGANIZATION_ID", "acme"), "iss": "zheta-forge", "aud": "forge-control-plane", "exp": int(time.time()) + 300})
signed = f"{header}.{claims}"
signature = base64.urlsafe_b64encode(hmac.new(secret.encode(), signed.encode(), hashlib.sha256).digest()).decode().rstrip("=")
print(f"{signed}.{signature}")
| Declared intent | Interpreter | Software effect | Hardware effect | Evidence |
|---|---|---|---|---|
| Mint one five-minute development token for the provider control plane | Python serializes claims and signs them with the configured HMAC secret; verify_bearer validates them | Produces a bearer token carrying one actor, organization, issuer, audience, and expiry; it creates no membership, runtime operator, or app-user record | Local CPU performs serialization and HMAC; no durable state or AWS resources change | AuthenticationTest proves signature and provider-scope checks; independent three-plane mappings and revocations remain required implementation evidence |
Decision rules
Share authentication only where it reduces login friction; never share authorization implicitly. Every cross-plane mapping is explicit, least-privilege, audited, and independently revocable, and every API validates issuer, audience, tenant, resource, and current grant state.