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-srccalls, 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 beforeauthenticate()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_minutesat 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-Onlyfirst so a missingconnect-src/frame-srcdirective surfaces in reports instead of manifesting as a shopper-facing challenge timeout in production.
Test it
See Test your integration for 3DS scenario coverage.Related
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.