# Email verification links

> Verify an email before continuing an explicit guest request.



Use the same public challenge and verification endpoints for a single-use email
link. Configure `emailLinkReturnPath` in `createKismetGuestAuthNextHandlers` to a
fixed, same-origin HTTPS callback path, then call
`createKismetGuestAuthBrowserClient().startEmailLink({ email, continuation })`.
The optional continuation is application-owned context (maximum 1,024 characters),
retained server-side with the expiring challenge. Keep credentials, personal data and offer
codes out of it. It is not an API authorization grant.

The email carries `challengeId` and a random proof in the callback URL fragment.
The callback must immediately remove the fragment with `history.replaceState`,
then call `completeEmailLink({ challengeId, token })`. This returns the verified
guest identity and the original continuation; credentials stay in the HttpOnly
session. Do not run analytics or third-party scripts on the callback page, log the
fragment, or put it in query parameters. A newly requested link works in another
browser or device within five minutes, on the same registered site and exact
configured callback. The callback must initialize its own canonical Kismet session
through the site's normal identity integration. The SDK does not copy the source
browser's identity or invent a replacement session. `CANONICAL_SESSION_REQUIRED`
means identity initialization has not finished; it occurs before link consumption.
Expired links, replays, different origins and changed callbacks are refused.

Only after verification may the application resume the guest's explicit request,
using its original disclosure and idempotency key. Do not interpret signing in as
marketing subscription consent. An offer continuation can request a separate
code email through the public offers API; retries preserve the original key and
source attribution. A marketing signup must retain the explicit consent originally
shown. Return paths must be sanitized same-site paths, never arbitrary redirects.

When the original request includes offer attribution, retain its enrollment ID
and idempotency key. The SDK stores short-lived verification evidence in the
encrypted server session and sends it only from that verified destination
session. The API validates the recipient, installation, environment and origin
before resolving the original enrollment. This does not change the destination
browser's identity or bypass consent and enrollment expiry. Complete the resumed
capture within 15 minutes of verification. Never expose this proof in browser
JSON, URLs or logs, and never drop attribution or rotate keys to bypass an error.

This requires the reviewed v0.7.33 API extension. Existing requests without
attribution remain compatible. Browser callers pass only
`attribution: { enrollmentId }`; the same-origin handler supplies the canonical
session and any verified evidence. Direct server integrations can use the optional
`verificationProof` field only with evidence returned from their own portable
verification, retaining all normal offer permissions and consent checks.

TEST real mail still requires the existing, expiring `realEmailSignIn` staging
permission for the exact registered origin. Without it the challenge is generic
and suppressed; a magic link is never replaced with a deterministic TEST code.
Roll out API support before enabling the SDK option. Existing OTP login is
unchanged. Existing links issued before portable-link support retain their original
same-browser binding until expiry. For that compatibility an edge relay must permit
the `__Host-kismet-email-link` cookie in both
directions, require Secure, HttpOnly, Path=/ and SameSite=Lax, and never cache auth
responses or the callback. Existing `/auth/challenge` and `/auth/verify` routes
are reused; no additional credential or private API is needed.
