Skip to content

IS-11327 Apply Result-pattern error handling to EBF and BankID runners#195

Draft
aleixsuau wants to merge 1 commit into
feature/IS-11327/webauthn-error-handlingfrom
feature/IS-11327/ebf-bankid-error-handling
Draft

IS-11327 Apply Result-pattern error handling to EBF and BankID runners#195
aleixsuau wants to merge 1 commit into
feature/IS-11327/webauthn-error-handlingfrom
feature/IS-11327/ebf-bankid-error-handling

Conversation

@aleixsuau
Copy link
Copy Markdown
Contributor

@aleixsuau aleixsuau commented May 21, 2026

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

Follow-up to the WebAuthn portion of IS-11327 (PR #194). Brings runExternalBrowserFlow and runBankIdAuthentication onto the same ClientOperationResult discriminated-union contract so client-operation failures flow through useHaapiStepper().error.app like WebAuthn's.

Test plan

  1. Apply
    ebf-verification.patch

  2. There is a harness inside runExternalBrowserFlow that short-circuits each failure branch + supplies mock copy (BE hasn't shipped step.metadata.viewData.error.clientOperation.externalBrowserFlow.{launch,resume} yet). Change it to emulate each error.

  3. Start a fresh OAuth flow:

    https://localhost:8443/dev/oauth/authorize?client_id=client-one&response_type=code&redirect_uri=https://localhost:7777/client-one/cb1&scope=openid&state=test
    
  4. Pick openid-wallet1

  5. Click the button**"The authentication process needs to use an external browser"**.

Toggle each branch

Edit EBF_HARNESS_FAILURE_MODE at the top of src/haapi-stepper/feature/actions/client-operation/operations/external-browser-flow/external-browser-flow.ts:

Mode What's exercised
'LAUNCH' window.open returns null → launch-error branch → "External browser flow could not start…"
'RESUME_BAD_ORIGIN' opens about:blank, dispatches a message with attacker origin → resume-error branch (origin guard)
'RESUME_BAD_DATA' opens about:blank, dispatches a message with non-string data → resume-error branch (type guard)
'ABORT' opens about:blank, fires onAbort() → resume-error branch (abort handler)
null production behaviour

What to confirm

  • The step renderer stays mounted after each failure (user-driven retry).
  • The toast text matches the mode (launch vs resume copy).
  • No JS errors in the console — failures route through the resolved ClientOperationResult, never escape to the ErrorBoundary.
  • Network panel shows no popup-launch fetch under LAUNCH mode (runner short-circuits before window.open).

Bring runExternalBrowserFlow onto the same ClientOperationResult contract that
WebAuthn established: always resolves, with { clientOperationData } on success
or { clientOperationError } on a catalogued failure. Three failure paths
(window.open returns null, unexpected origin/non-string data in the resume
message, abort signal) synthesise a HaapiStepperError via getHaapiStepperError
so the stepper surfaces them inline via useHaapiStepper().error.app, with copy
resolved from step.metadata.viewData.error.clientOperation.externalBrowserFlow.
{ launch | resume } — two keys mirroring Velocity's launch-error and
external-flow-end templates.

The EBF runner also fixes a latent listener+popup leak in the previous code:
the unexpected-origin/data branch now goes through cleanup instead of leaving
the message listener registered and the popup open.

runBankIdAuthentication adopts the contract too, but narrowed to the
success-only branch (Promise<{ clientOperationData }>) — the LWA's BankID
launcher has no client-side catchable failures today (anchor.click is fire-
and-forget; the real BankID failures land on the next polling step). When a
client-side failure mode eventually lands, widen to the full union and
introduce currentStep then.

File-layout follow-up: external-browser-flow.ts moves into its own
subdirectory with sibling typings.ts and index.ts barrel, matching the
webauthn/ and bankid/ conventions.

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.

1 participant