Skip to content

Built-in WebAuthn step-up primitive (default StepUpService) for credential-altering operations #335

Description

@devondragon

Summary

Ship a built-in WebAuthn step-up primitive so consumers get step-up re-authentication out of the box, rather than having to implement the StepUpService SPI themselves.

Background

The security concern from SUF-02 (#328) is already closed: POST /user/setPassword now requires a StepUpService when one is provided and is disabled by default otherwise (shipped in #334). This ticket is the enhancement — a default, framework-provided step-up implementation — not a security gap.

Spring Security provides the WebAuthn login assertion flow (/webauthn/authenticate/options, /login/webauthn), but not a step-up assertion (prove presence while already authenticated, bound to a specific action). That flow is what this ticket builds.

Proposed design (to be refined)

  • Challenge endpointPOST /user/stepup/webauthn/options (authenticated): generate a PublicKeyCredentialRequestOptions (allowCredentials = the user's registered passkeys) and store a challenge server-side bound to {userId, action, rpId, origin, expiry (short, e.g. 2 min)} — session attribute or a short-lived table.
  • Verification — the client performs navigator.credentials.get(...) and posts the assertion to POST /user/stepup/webauthn (or includes it on the target request). A default StepUpService bean verifies the assertion against the stored challenge via Spring Security's WebAuthnRelyingPartyOperations, checks binding + expiry, and marks step-up satisfied (e.g. a short-lived session flag keyed by action).
  • WiringsetPassword (and any future credential-altering ops) already consult StepUpService; the default bean plugs in via @ConditionalOnMissingBean(StepUpService.class) so a consumer override still wins.
  • Config — enable/disable flag; challenge TTL; which actions require step-up.
  • Fallbacks — for users without a passkey (e.g. OAuth-only), decide: no default step-up available (endpoint stays disabled / consumer must supply their own), or an alternative factor.

Open questions

  • Challenge storage: session vs short-lived DB table (multi-node)?
  • Single-use step-up token vs session flag; binding granularity per action.
  • Client contract: separate verify endpoint vs assertion carried on the target request.
  • Docs + a reference frontend snippet in the demo app.

Scope / effort

Feature-scale (new endpoints, challenge lifecycle, verification, tests, docs, demo wiring). Warrants its own design pass before implementation.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions