Skip to main content
threeDS.authenticate() and threeDS.resume() fail in one of two shapes: a rejected promise (a flow-level error — CSP, cancellation, a stale token) or a resolved decline ({status} other than AUTHENTICATED/ATTEMPTED, which isn’t an error at all). Telling these apart decides whether you retry the authentication or restart the checkout.
TL;DR: authenticate()/resume() rejects or resolves to a non-authenticated status → tell a flow error (retry the authentication) apart from an issuer decline (don’t auto-retry).

When this happens

  • The shopper cancels a challenge in progress, or the challenge window expires before they complete it.
  • Your Content Security Policy blocks the SDK’s connect-src/frame-src calls, so a completed challenge can’t be confirmed.
  • The card token from an earlier elements.submit() lapsed (about 30 minutes) or doesn’t match the session before authenticate() runs.
  • The 3DS provider itself is unreachable, or the gateway rejects the reference at charge time because it’s unknown, reused, or bound to a different amount/card.

What you see

What to do

1

Branch on rejection vs. resolution first

A catch means the flow broke (fix the integration or let the shopper retry the authentication itself). A resolved non-authenticated status means the issuer declined — don’t automatically retry the same authentication; see Authentication results for the full status table and the server action for each.
2

Check CSP before assuming a provider outage

three-ds:challenge-timeout is most often a missing connect-src/frame-src directive, not an actual provider outage — see Content Security Policy: troubleshooting.
3

Re-bind and re-authenticate on a stale token

A three-ds:card-token-invalid rejection, or a charge-time three-ds:card-token-mismatch, both mean the token that was authenticated no longer matches what you’re charging — call elements.submit() again for a fresh token, then authenticate() again, rather than retrying the charge alone.
4

Never reuse a ref across charges

three-ds:ref-invalid/ref-expired at charge time means the reference is single-use and already consumed, or too old — re-authenticate for a new ref rather than resending the same charge body with a new request_id.

Prevent it

  • Keep ttl_minutes at 30 or less for a 3DS checkout, matching the card token’s own lifetime — see Token lifetime.
  • Ship your CSP as Content-Security-Policy-Report-Only first so a missing connect-src/frame-src directive surfaces in reports instead of manifesting as a shopper-facing challenge timeout in production.

Test it

See Test your integration for 3DS scenario coverage.

3DS with Elements

The authenticate-then-charge flow these failures interrupt.

Authentication results

Every status, SDK error, and gateway error, with the remedy for each.
Last modified on September 15, 2026