Proposed (STA-814). It applies 0207
decision 1 to the action pipeline. Linear STA-814.
Context
ADR 0207 requires a recent strong authentication for L3 and L4 actions, and@stackra/identity already maps a token’s
amr to an assurance level and checks its age (requireAssurance). Nothing carried the token’s amr and auth_time
into an action call, and no action could say it needs a step-up, so each handler would have checked it by hand.
Decision
- The call carries its assurance.
CallOptions.assurance(amr,authTime,level) is filled by the transport from the verified token, never from input; the pipeline hands it toctx.assurance. It is absent without an interactive session (a job, an API key). Action({ stepUp: AssuranceLevel.Aal2 })names the level an action needs.AssuranceLevelin@stackra/actions/contractshas the same codes as identity’s, because actions depends on neither identity nor iam.- A
StepUpCheckport decides, right after the permission. The bound driver wrapsrequireAssurance, so the window isIdentityConfig.stepUpMaxAgeMinutes(configuration). A refusal isstep_up_required. - It fails closed. An action that declares
stepUpwith noStepUpCheckbound is an error, like a missingAccessControl. An action that declares none never asks.
Consequences
- The identity service or app binds a
StepUpCheckdriver overrequireAssurance; every transport fillsCallOptions.assurance. - A handler that needs the facts (an audit field, a risk score) reads
ctx.assurance.
Enforcement
packages/application/actions/src/core/services/__tests__/action-pipeline.service.test.ts (step-up order, refusal,
fail closed); packages/application/actions/src/contracts/__tests__/index.test.ts.