Call your backend only. Use verifyUrl as returned — do not build it, do not append to it, and do not navigate to it.

Start verify

A small helper, then a normal handler:
The form submit leaves the SPA, so there is nothing to clean up — no router navigation, no state to persist.

The landing page

After verification the browser arrives on your registered returnUrl with a plain GET carrying ?session_id=…&state=…. Neither value is sensitive and neither proves anything — the verification is finished on your server, which reads GET /session/{id} with its own credentials. The tidiest shape in an SPA is to point returnUrl at a small server route that does exactly that and then 303s into the app on a route of your choosing. If you prefer a routed SPA page, the component only asks your own API:
There is no callback route in the SPA, no secret query params to read, and no postMessage listener — the SPA never handles verification data. More: Frontend overview · Backend overview