--- id: netkingdom-iam-profile type: standard title: "NetKingdom IAM Profile v0.2" domain: netkingdom status: accepted version: "0.2" created: "2026-05-22" updated: "2026-05-22" scope: core-platform supersedes: - the-custodian/canon/standards/iam-profile_v0.1.md adr: - docs/adr/ADR-0011-iam-profile-ownership-and-version-governance.md --- # NetKingdom IAM Profile v0.2 ## 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 and platform-boundary claims; - 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:platform` is distinct from tenant planes such as `tenant:coulomb`. - 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: ```text GET /.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 `S256` is 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 `agent` object with `id` and `mode`. - `agent.mode` is `autonomous` or `delegated`. - Delegated agents MUST identify the delegating actor using `actor_sub` or an equivalent `act.sub` claim. - 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:coulomb` | | `principal_type` | string | `human`, `service`, or `agent` | | `groups` | array | Group memberships, possibly empty | | `roles` | array | Coarse identity roles, 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 | ### Role Claim The canonical role claim is `roles`, an array of strings. 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. Suggested identifiers: ```text tenant:platform tenant:coulomb tenant:sandbox: tenant:customer: ``` `tenant:platform` is the platform control-plane tenant. Tenant administration for `tenant:coulomb` or later tenants 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. ## 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. 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` | | Roles | `roles` | | 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 `localhost` or `127.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 `emergency` role. - 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.2 when it passes the executable conformance suite in: ```text tools/iam-profile-conformance/ ``` The suite validates: - discovery document completeness; - PKCE `S256` advertisement 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; - 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. ## 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`, and `assurance`; - 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.