Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
19 KiB
| id | type | title | domain | status | owner | revision | last_reviewed | review_interval | version | created | updated | scope | supersedes | adr | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| netkingdom-iam-profile-v0.3 | standard | NetKingdom IAM Profile v0.3 | netkingdom | accepted | net-kingdom | accepted-1 | 2026-08-22 | 6m | 0.3 | 2026-07-23 | 2026-08-22 | core-platform |
|
|
NetKingdom IAM Profile v0.3
Minor version. Per ADR-0011's versioning rule, this adds an optional claim and clarifies non-normative guidance — no required claim, validation rule, or previously-issued token is invalidated. Existing v0.2 implementations remain conformant;
tenant_rolesand the revised Tenant Claim guidance are additive.
Purpose
The NetKingdom IAM Profile is the provider-neutral OIDC contract that identity implementations issue and applications consume.
It defines:
- OIDC discovery and endpoint requirements;
- Authorization Code + PKCE for human login;
- service-account and workload identity token requirements;
- human, service, and agent principal representation;
- tenant, tenant-grouping, and platform-boundary claims;
- tenant capability roles and their carrying mechanism;
- explicit assurance evidence;
- the identity-to-authorization claim contract consumed by flex-auth;
- local-development and emergency-access behavior;
- executable conformance expectations.
Applications target this profile, not a concrete identity provider. key-cape is the lightweight implementation. Keycloak is the expanded-mode implementation. Both are interchangeable at the application and authorization boundary when they conform to this document.
Ownership
NetKingdom owns the core/platform profile. See ADR-0011.
Downstream systems may define extension scopes, roles, resource names, and tenant policy vocabularies. Those extensions are not part of the core profile unless a future version explicitly adopts them. Extension vocabularies must map back to the core claims in this document before flex-auth or applications consume them.
Design Principles
- Consumers trust signed OIDC tokens, not provider-specific sessions.
- Identity providers assert identity and authentication evidence; they do not make final resource authorization decisions.
- The same profile works in lightweight key-cape mode and expanded Keycloak mode.
- Tenancy is explicit.
tenant:platformis distinct from tenant planes such astenant:coulomband from later tenants grouped per ADR-0013. - A tenant's onboarding grouping (ADR-0013) and its capability roles (ADR-0014) are independent axes. Neither is encoded in the other; a tenant's roles may change without renaming its identifier.
- Human, service, and agent principals are distinguishable.
- Assurance evidence is explicit enough for flex-auth policy.
- Local-development issuers are useful but never accepted by production.
- Emergency access is auditable, time-bounded, and reviewable.
Discovery Contract
Every IAM Profile implementation MUST expose OIDC discovery at:
GET <issuer>/.well-known/openid-configuration
The discovery response MUST include:
| Field | Requirement |
|---|---|
issuer |
Exact issuer identifier used in tokens |
authorization_endpoint |
Required for human Authorization Code + PKCE |
token_endpoint |
Required for token exchange and service accounts |
jwks_uri |
Required for signature validation |
userinfo_endpoint |
Required when userinfo is supported by the flow |
scopes_supported |
MUST include openid; SHOULD include profile and email |
response_types_supported |
MUST include code |
grant_types_supported |
MUST include authorization_code; MUST include client_credentials or a documented workload-token exchange for service identities |
id_token_signing_alg_values_supported |
MUST include the implementation signing algorithm; RS256 is required for v0.2+ conformance |
code_challenge_methods_supported |
MUST include S256 |
The response SHOULD include end_session_endpoint where logout is
supported and claims_supported listing the core claims below.
Consumers MUST discover endpoints and key material from the issuer metadata instead of hardcoding provider-specific paths.
Required Flows
Human Interactive Flow
Human users authenticate with Authorization Code + PKCE.
Required properties:
- PKCE with
S256is mandatory for browser and CLI clients. - Implicit flow is not part of the profile.
- MFA or equivalent strong assurance is mandatory for privileged, destructive, platform-root, and emergency access in production.
- Access tokens are short-lived.
- Refresh tokens are allowed only for trusted clients with explicit rotation and revocation.
Service Account Flow
Service-to-service traffic uses client credentials or a deployment's documented workload identity token-exchange equivalent.
Required properties:
- Service subjects are stable and named for service plus environment.
- Secrets or workload credentials are delivered through the credential-management standard, not plaintext configuration.
- Tokens include an audience that identifies the target service.
- Tokens carry
principal_type: service. - Service accounts receive only required scopes and roles.
- Credentials are rotated and never shared between environments.
Agent Principal Flow
Agents are automation principals that may act autonomously or under delegated authority.
Required properties:
- Tokens carry
principal_type: agent. - Tokens include an
agentobject withidandmode. agent.modeisautonomousordelegated.- Delegated agents MUST identify the delegating actor using
actor_subor an equivalentact.subclaim. - Agent tokens MUST carry the tenant they operate within.
- Agent tokens MUST include assurance evidence for both the agent credential and any delegated human authority when policy needs it.
Core Claims
Access tokens accepted by production consumers MUST provide the following claims after provider mapping or normalization:
| Claim | Type | Meaning |
|---|---|---|
iss |
string | OIDC issuer URL or issuer identifier |
sub |
string | Stable subject identifier unique within iss |
aud |
string or array | Intended audience; MUST include the receiving service |
exp |
number | Expiry timestamp |
iat |
number | Issued-at timestamp |
nbf |
number | Not-before timestamp, recommended for production tokens |
jti |
string | Token identifier, recommended for audit and replay controls |
tenant |
string | Tenant identifier such as tenant:platform or tenant:friendly:binky |
principal_type |
string | human, service, or agent |
groups |
array | Group memberships, possibly empty |
roles |
array | Coarse identity roles for the subject, possibly empty |
scope or scp |
string or array | Granted OAuth scopes |
assurance |
object | Authentication and credential assurance evidence |
Recommended human claims:
| Claim | Meaning |
|---|---|
preferred_username |
Human-readable username |
email |
Contact identity |
name |
Display name |
Recommended service claims:
| Claim | Meaning |
|---|---|
azp or client_id |
Authorized client/service identifier |
service |
Object naming the service and environment |
Recommended agent claims:
| Claim | Meaning |
|---|---|
agent.id |
Stable agent identifier |
agent.mode |
autonomous or delegated |
actor_sub or act.sub |
Delegating subject for delegated agents |
Optional claims (new in v0.3):
| Claim | Type | Meaning |
|---|---|---|
tenant_roles |
array | Cached tenant capability roles (PLTF/IAM/VEN/CUS), possibly empty. See "Tenant Roles" below — this is a point-in-time cache, not the authoritative source. |
Role Claim
The canonical subject-level role claim is roles, an array of strings.
This is distinct from tenant_roles (below) — a subject's own coarse
identity roles are not the same fact as which capability roles the
subject's tenant holds.
Expanded-mode Keycloak deployments may also expose provider-native roles
such as realm_access.roles, but conforming tokens consumed by flex-auth
or applications MUST either emit roles directly or pass through a
normalizing adapter that produces roles.
Scope Vocabulary
The core profile defines only OAuth/OIDC base scopes:
| Scope | Meaning |
|---|---|
openid |
Required for OIDC login |
profile |
Basic profile claims |
email |
Email claim where appropriate |
offline_access |
Refresh-token capable access where explicitly allowed |
Hub-, application-, and resource-specific scopes such as hub:*,
ops:*, fin:*, or storage actions are downstream extensions. They are
valid only when the consuming system defines them and maps them to
flex-auth resource/action semantics.
Tenant Claim
tenant is required for every token accepted by profile consumers.
Tenant identifiers follow tenant:<grouping>:<name>, where <grouping> is
one of the taxonomy ratified by ADR-0013 at identifier creation:
trial - test/trial/showcase tenants only
friendly - known, easily reached, tolerant of experimentation/instability
single - one-person business entities (freelance consultants)
small - up to 10 employees at time of onboarding (attoo)
medium - up to 100 employees (attoo)
large - up to 1000 employees (attoo)
enterprise - 1001+ employees (attoo)
consumer - private individuals
family - a legal family
community - a non-legal group of people
association - a legal association of people
agentic - financially enabled AI entities
tenant:platform and tenant:coulomb remain reserved, ungrouped
identifiers outside this taxonomy: tenant:platform is the platform
control-plane tenant, not a business entity being onboarded; tenant:coulomb
is the first internal/reference tenant established by ADR-0006, predating
this taxonomy. Tenant administration for tenant:coulomb or any grouped
tenant must never imply platform-root authority.
Subjects may have access to multiple tenants, but a token used for a request MUST identify the tenant context for that request. If a client needs to switch tenant context, it obtains a new token or uses an approved token-exchange flow that records the target tenant.
The grouping segment is an immutable record of the tenant's
onboarding-time onboarding-risk / entity-shape classification. It remains
vocabulary-valid but becomes historical if the tenant's classification later
changes. The authoritative current grouping is the grouping field held by
tenant-engine; consumers MUST NOT split tenant and treat its middle segment
as current policy input. Changing current grouping never renames the tenant.
Neither the historical segment nor current grouping gates which capability
roles (below) a tenant may hold — see Tenant Roles.
Tenant Roles
Tenant capability roles are a separate fact from the grouping above and
from the subject-level roles claim: PLTF, IAM, VEN, CUS
(ratified by ADR-0014), non-exclusive — a tenant may hold several
simultaneously, and holding one does not require or restrict any grouping.
Source of truth: tenant-engine
(canon/standards/tenant-engine-boundary-contract_v0.1.md), not this
profile and not any token. tenant-engine records role grants/revocations,
their link (if any) to a plan/subscription, and emits domain events on
change.
Carrying mechanism — hybrid, not claim-only:
key-cape(or Keycloak) MAY stamp a cachedtenant_rolesclaim onto an issued token at issuance time, sourced fromtenant-engine.- Consumers MAY trust the cached claim for ordinary, non-privileged decisions.
- Consumers MUST NOT trust the cached claim for privileged, destructive,
platform-root, secret, credential-vending, or otherwise `assurance.level
= aal2
-class decisions. Those decisions **MUST** querytenant-engine` live for current role state before authorizing the action. - This bounds staleness for ordinary actions to the issuing token's
lifetime (5-30 minutes for service/agent tokens, see Token Lifecycle)
while guaranteeing freshness exactly where a stale grant (e.g.
VENsurviving a plan cancellation) would matter most.
trial-grouped tenants may hold any capability role without restriction —
the grouping exists to showcase, test, and explore every role. Safety for
trial tenants is enforced through tenant-engine-owned resource
guardrails (spend limits, entity/action counts — reserved, not yet
specified), not through role gating.
Assurance Evidence
The canonical assurance claim is assurance.
It is an object with these fields:
| Field | Type | Meaning |
|---|---|---|
level |
string | aal0, aal1, aal2, aal3, or break_glass |
methods |
array | Authentication methods, e.g. pwd, otp, webauthn, client_secret, workload_identity, upstream_mfa |
mfa |
boolean | Whether the authentication included multiple factors or equivalent upstream evidence |
source |
string | Provider of the evidence, e.g. key-cape, keycloak, privacyidea, entra, local-identity |
at |
number | Authentication time, recommended |
Level meanings:
| Level | Meaning |
|---|---|
aal0 |
Local/dev or unauthenticated bootstrap evidence; never production privileged |
aal1 |
Single-factor or service credential evidence |
aal2 |
MFA or equivalent strong upstream assurance |
aal3 |
Phishing-resistant or hardware-backed assurance |
break_glass |
Time-bounded emergency access with post-event review |
Privileged, destructive, platform-root, secret, credential-vending, and
emergency flows require aal2 or stronger unless a policy explicitly
permits a narrower service or workload identity path. Emergency access
MUST use break_glass and short token lifetimes. This is the same
threshold class that gates when tenant_roles MUST be re-validated live
against tenant-engine rather than trusted from the token — see Tenant
Roles.
Provider-native claims such as acr and amr may be present, but
consumers use assurance as the normalized profile claim.
Identity To Authorization Contract
flex-auth consumes IAM Profile tokens as normative identity input. flex-auth MUST NOT re-derive identity, tenant, group, role, or assurance facts from provider-specific session state.
The profile guarantees these inputs for authorization decision envelopes:
| Decision input | Source claim |
|---|---|
| Subject | sub |
| Issuer | iss |
| Audience | aud |
| Tenant | tenant |
| Principal type | principal_type |
| Groups | groups |
| Subject roles | roles |
| Tenant capability roles | tenant_roles (cached); tenant-engine live lookup required for high-stakes decisions |
| Scopes | scope or scp |
| Assurance | assurance |
| Authorized client | azp or client_id, where present |
| Agent/delegation context | agent, actor_sub, or act, where present |
| Token lifetime/audit ids | iat, nbf, exp, jti, where present |
Authorization decisions are made by flex-auth and its delegated PDP adapters. Identity providers may assert roles or scopes, but those claims are inputs to policy, not final permission to act on a resource.
Token Lifecycle
Recommended production defaults:
| Token | Lifetime | Notes |
|---|---|---|
| Human access token | 5-15 minutes | Short-lived bearer token |
| Refresh token | 8-12 hours | Rotated and revoked on logout or suspicion |
| Service token | 5-30 minutes | Reissued by client credentials or workload identity |
| Agent token | 5-30 minutes | Shorter when delegated or platform-scoped |
| Emergency token | 5-15 minutes | Requires incident/review record |
Consumers MUST reject expired tokens and tokens with invalid issuer,
audience, signature, nbf, or algorithm. Clock skew tolerance SHOULD be
small, normally no more than 60 seconds.
JWKS material may be cached, but consumers MUST tolerate key rotation by
refreshing JWKS when a token uses an unknown kid.
Local Development Profile
A local file-backed provider may be used for development, tests, and bootstrap contexts where the full platform is unavailable.
It MUST:
- expose OIDC discovery;
- issue signed JWTs;
- support deterministic test users and service accounts;
- use local-only issuer URLs or a clearly local issuer identifier;
- mark tokens as local/development through issuer, audience, or assurance evidence;
- be rejected by production consumers.
Production consumers MUST reject:
- issuer
local-identity; http://issuers;- loopback issuers such as
localhostor127.0.0.1; - tokens with
assurance.level: aal0; - tokens where the environment marks the issuer as local/dev.
Emergency And Break-Glass Access
Emergency access is allowed only as a break-glass path.
Requirements:
- Emergency identities are disabled by default.
- Activation requires an incident, decision, or human-recorded review reference.
- Tokens are short-lived and carry the
emergencyrole. - Tokens carry
assurance.level: break_glass. - Every emergency action emits an audit/progress/incident event.
- Emergency access is reviewed after use and then disabled again.
Emergency access MUST NOT bypass audit logging or flex-auth policy.
Conformance
An implementation conforms to IAM Profile v0.3 when it passes the executable conformance suite in:
tools/iam-profile-conformance/
The suite validates:
- discovery document completeness;
- PKCE
S256advertisement and rejection of authorization requests that omit a code challenge; - JWKS structure and key ids;
- token issuer, audience, expiry,
nbf,iat, and RS256 signature; - tenant, principal type, groups, roles, scopes, and assurance claim shape;
tenant_rolesclaim shape when present (array of ratified role strings);- agent and delegated-agent claim shape;
- local-development issuer rejection in production mode.
Conformance must be runnable against both key-cape lightweight issuers
and Keycloak expanded-mode issuers. Implementations may add provider
adapters, but the token consumed by applications and flex-auth must match
the core claim contract above. tenant_roles conformance does not require
an implementation to emit the claim (it is optional); when emitted, it
must match the ratified vocabulary.
Validation Checklist
A service or implementation is profile-ready when:
- it reads OIDC discovery rather than hardcoding endpoints;
- it validates issuer, audience, expiry,
nbf, algorithm, and signature; - it refreshes JWKS on unknown
kid; - it supports Authorization Code + PKCE for human login;
- it supports service-account or workload identity tokens;
- it emits
tenant,principal_type,groups,roles,scope/scp, andassurance; - it uses the ADR-0013 grouping vocabulary for new tenant identifiers;
- if it consumes
tenant_roles, it treats the claim as a cache and re-validates live againsttenant-enginebefore anyaal2-class decision; - it maps provider-native claims into the canonical core claims;
- it rejects local-development issuers in production;
- it logs emergency access with a durable audit trail;
- flex-auth receives identity facts from the profile, not from provider-specific sessions.