--- id: netkingdom-iam-profile-v0.4 type: standard title: "NetKingdom IAM Profile v0.4" domain: netkingdom status: proposed owner: net-kingdom created: "2026-09-27" updated: "2026-09-27" scope: core-platform supersedes: - canon/standards/iam-profile_v0.3.md adr: - docs/adr/ADR-0011-iam-profile-ownership-and-version-governance.md - docs/adr/ADR-0016-mfa-user-preference-and-workload-step-up.md related: - NK-WP-0042 --- # NetKingdom IAM Profile v0.4 Everything in v0.3 stands unchanged except where this document says otherwise. v0.3 remains `accepted` and normative; this document adds the workload-requested step-up contract as a proposed amendment (`NK-WP-0042-T01`). It does not require any workload to request MFA; ADR-0016's default — MFA is a user preference — is unchanged, and the enrollment/recovery usability gate in ADR-0016 §4 still applies before any workload turns a requirement on. ## Workload-Requested Step-Up (proposed) ADR-0016 lets a workload require AAL2 for all or part of its features instead of leaving MFA to user preference. This section defines the OIDC-level request and the no-factor refusal contract so every issuer implements the same interface. **key-cape owns the implementation**; this profile owns the interface, per NK-WP-0042-T01. ### Requesting step-up - **Whole-client requirement.** A workload that requires AAL2 for all of its sign-ins registers this at the client, unchanged from the existing lightweight-mode client configuration (`mfaRequired` / P06 semantics). This subsection does not change that path. - **Per-request step-up.** A workload that requires AAL2 only for a protected feature sends `acr_values` on the authorization request, containing one of the `assurance.level` values this profile already defines: `aal2` or `aal3`. The issuer MUST treat a recognized `assurance.level` value in `acr_values` as a request for that floor. - `max_age` MAY be combined with `acr_values` to also force a fresh interactive login. `max_age` MUST NOT be used alone to request strength: it bounds session age, not factor count. A request carrying only `max_age` gets a fresh login at whatever assurance the user already holds, not an implied AAL2. - A request MUST NOT use a provider-native `acr` value as a substitute for the profile's `assurance.level` vocabulary. Provider-native `acr`/`amr` claims remain informational (Assurance Evidence, v0.3). ### No-factor refusal If the requested floor is `aal2` or higher and privacyIDEA (or the issuer's equivalent authoritative factor source) reports no active factor for the user, the issuer MUST NOT silently issue a token at a lower `assurance.level`. It MUST do one of: - **Inline enrollment detour:** present the enrollment flow itself and, on completion, resume and complete the original authorization request; or - **Explicit refusal:** fail the authorization request with an OAuth-shaped error distinct from a generic `access_denied` (e.g. `error=mfa_required`), so the requesting client can route the user to enrollment itself. Silent issuance of `assurance.level: aal1` (or omission of `assurance`) in response to an `acr_values` request for `aal2`/`aal3` is nonconforming. This governs the machine contract only; which of the two options a given workload presents, and the exact enrollment/recovery UX, is `NK-WP-0042-T02`'s open agreement with user-engine (U06) and a pilot workload — this profile does not decide it. ### Reaching flex-auth No new claim is introduced. The outcome is carried by the existing `assurance.level` claim on the issued token (Assurance Evidence, v0.3): a workload's per-request requirement is satisfied, refused, or detoured before a token is issued, and flex-auth continues to read the issued `assurance.level` exactly as the Identity To Authorization Contract table already specifies. flex-auth MUST NOT infer a "requested vs. granted" distinction from any other claim; there is only the token that was issued. ### Non-goals - This does not lower the IAM Profile v0.3 floor: privileged, destructive, platform-root, secret, credential-vending, and emergency flows still require `aal2` or stronger regardless of workload opt-in (ADR-0016 §3). - This does not specify the enrollment/recovery user experience (NK-WP-0042-T02) or which workloads turn step-up on (ADR-0016 §4). - This does not add a Keycloak-specific or privacyIDEA-specific mechanism; `acr_values` is the profile-level, provider-neutral request.