Skip to content

IS-11252 WebAuthn client operations in the LWA#154

Draft
aleixsuau wants to merge 6 commits intointegration/IS-5161/login-web-appfrom
feature/IS-11252/webauthn-client-operations
Draft

IS-11252 WebAuthn client operations in the LWA#154
aleixsuau wants to merge 6 commits intointegration/IS-5161/login-web-appfrom
feature/IS-11252/webauthn-client-operations

Conversation

@aleixsuau
Copy link
Copy Markdown

@aleixsuau aleixsuau commented May 5, 2026

Jira: https://curity.atlassian.net/browse/IS-11252

Adds full support for webauthn-registration and webauthn-authentication HAAPI client operations, including the any-device-mode where the user picks between platform and cross-platform credentials.

Part 1 — WebAuthn pipeline

1. Format — split the action. formatNextStepData runs each webauthn-registration action through splitWebAuthnRegistrationAction. Any-device-mode with both options becomes two sibling actions, each titled "This device" / "Another device". Single-option and passkeys-mode pass through.

2. Render — one button per option, capability-gated. The default rendering pipeline produces one button per emitted action. useIsClientOperationAvailable disables it when the WebAuthn API is missing, or — for platform-only any-device registration — when no user-verifying platform authenticator is available.

3. Click — run the ceremony. performClientOperation dispatches to runWebAuthnRegistration (calls navigator.credentials.create(), serialises under the matching credential / platformCredential / crossPlatformCredential payload key) or runWebAuthnAuthentication (calls navigator.credentials.get(), serialises under credential). Both honour the AbortSignal and resume the flow via continueActions[0].

Part 2 — Folder refactor (no behaviour change)

feature/actions/client-operation/ reorganized so each operation owns its own folder/file as webauthn.

Test plan

  • passkeys-mode registration — single button, ceremony completes
  • any-device with both options — two buttons; each runs its matching ceremony
  • platform-only on a device without platform authenticator — button disabled
  • cross-platform-only — button always enabled
  • webauthn-authentication — ceremony completes
  • WebAuthn-unsupported browser — WebAuthn buttons disabled; BankID / external-browser-flow unaffected

Follow-ups (separate PRs)

  • Error handling — runners currently throw on user-cancel, hardware error, or server rejection; no mapping to errorActions or in-flow user feedback yet.
  • Auto-triggering — analogous to bankIdAutostart: a config flag to start the ceremony immediately on step entry.

Implements the webauthn-registration and webauthn-authentication HAAPI
client operations, including any-device-mode that may offer the user a
choice between platform and cross-platform credentials.

The feature comes with a folder restructure: per-operation modules live
under a new operations/ subfolder, with the previous client-operations.ts
god-file slimmed to a thin dispatcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Any-device-mode `webauthn-registration` actions split into two siblings
now read e.g. "Register new device (This device)" /
"Register new device (Another device)" instead of just the device label,
preserving the server-supplied original title.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds full HAAPI WebAuthn client-operation support (registration + authentication), including any-device mode that renders separate “platform” vs “cross-platform” choices, and refactors the client-operation implementation into per-operation modules.

Changes:

  • Add WebAuthn registration/authentication runners, plus action-splitting for any-device registration so the UI can render one button per option.
  • Introduce runtime capability gating in the default client-operation UI (disable WebAuthn actions when unsupported / when platform authenticator is unavailable for platform-only any-device registration).
  • Refactor client-operation code into feature/actions/client-operation/operations/* and update imports/exports/tests accordingly.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/login-web-app/src/haapi-stepper/feature/stepper/HaapiStepper.tsx Updates client-operation import to the refactored operations entrypoint.
src/login-web-app/src/haapi-stepper/feature/stepper/HaapiStepper.spec.tsx Updates BankID app opener mocking path after refactor.
src/login-web-app/src/haapi-stepper/feature/stepper/data-formatters/polling-step.ts Uses new BankID operation exports for polling autostart behavior.
src/login-web-app/src/haapi-stepper/feature/stepper/data-formatters/format-next-step-data.ts Adds WebAuthn registration action splitting to emit one action per credential option.
src/login-web-app/src/haapi-stepper/feature/index.ts Re-exports refactored client-operations entrypoint.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/HaapiStepperClientOperationUI.tsx Disables client-operation button based on runtime availability; removes render prop.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/HaapiStepperClientOperationUI.spec.tsx Adds tests for default rendering and WebAuthn any-device split integration.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/useIsClientOperationAvailable.ts New availability hook for capability-gating client-operation actions.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/operations/client-operations.ts New dispatcher for client operations (BankID, external browser flow, WebAuthn).
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/operations/external-browser-flow.ts Extracted external-browser-flow runner and type guard.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/operations/bankid/* Extracted BankID operation (runner, opener, type guard).
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/operations/webauthn/* Implements WebAuthn runners, action splitting helpers, and platform authenticator availability hook.
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/openBankIdApp.ts Removed old BankID opener (moved into operations/bankid).
src/login-web-app/src/haapi-stepper/feature/actions/client-operation/client-operations.ts Removed monolithic client-operations implementation (replaced by per-operation modules).
src/login-web-app/src/haapi-stepper/data-access/types/haapi-action.types.ts Refines WebAuthn registration typing and introduces selected-option enum.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +45
const launchUrl = new URL(action.model.arguments.href);
launchUrl.searchParams.set('for_origin', window.location.origin);

const externalWindow = window.open(launchUrl);
if (!externalWindow) {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +44 to +46
const externalWindow = window.open(launchUrl);
if (!externalWindow) {
reject(new Error('Failed to open external browser window'));
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Copilot AI commented May 5, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • download.cypress.io
    • Triggering command: /usr/local/bin/node node dist/index.js --exec install (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

aleixsuau and others added 3 commits May 5, 2026 11:54
Extract `createMockExternalBrowserFlowAction`, `createMockBankIdAction`,
`createMockWebAuthnRegistrationAction`,
`createMockWebAuthnAnyDeviceBothOptionsAction`, and
`createMockWebAuthnPlatformOnlyAnyDeviceAction` (plus their default-title
constants) from the spec into the shared `util/tests/mocks.ts`, so future
specs can reuse them. The spec drops 114 lines of local helpers and
relies on imports.

`stubPublicKeyCredential` stays in the spec — it's a global-API stub
builder, not a HAAPI-data factory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Consolidate the four WebAuthn tests (enables, disables on API absent,
disables on missing platform authenticator, splits into two buttons)
into one flat `describe('WebAuthn')` block. Each test sets up only what
it needs; a single `afterEach` cleans up `vi.stubGlobal` and the mocked
`useIsWebAuthnPlatformAuthenticatorAvailable` hook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The JSDoc examples in `HaapiStepper.tsx` and `HaapiStepperSelectorUI.tsx`
referenced fields that don't exist on `dataHelpers` (`formActions`,
`selectorActions`, `clientOperationActions`). Updated to the real
`actions.{form,selector,clientOperation}` shape so consumers can
copy/paste them.

Also swapped the example `key` props from `action.kind` / `link.rel`
(neither unique) to `action.id` / `link.id`, matching the production
factory in `defaultHaapiStepperActionElementFactory.tsx`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants