Public integration guide / agent-readable

Connect EVP identity evidence to XCIM consent.

This production-tested guide tells a coding agent exactly how to integrate a product with Emabled. EVP or OAuth establishes identity evidence. Emabled-hosted XCIM consent records the person's explicit communication choices, returns immediately to the product, and issues a signed, revocable receipt asynchronously.

Agent instruction: preserve this separation.

Do not treat an EVP token, OAuth access token, OAuth ID token, or successful login as consent. Do not invent an email-reply flow. Only the explicit action on the Emabled-hosted Consent Manifest can grant the requested purposes. Identity must happen once; Hosted Consent must not start a second provider login after the application already supplied valid identity evidence.

01 / Quick start

Choose the identity path, then create one XCIM session.

Use the capability endpoint before selecting a path. Keep both profiles when your product wants progressive enhancement and reliable fallback.

Check availability
GET https://api.emabled.com/v1/capabilities
ProfileUse whenWhat the agent must do
evp-01Capability status is experimental and the verifier origin has a valid Origin Trial token.Render the EVP email/token fields on the same origin as the token, then submit the token for Emabled validation.
oidc-01EVP is unavailable, unsupported, or the product requires OAuth today.Use the reviewed authorization-code relay and vendor backchannel. Keep the client secret on the vendor backend.
BothRecommended for production pilots.Send ["evp-01", "oidc-01"]; Emabled selects the available path without weakening consent.
Create an EVP-first session with OAuth fallback
POST https://api.emabled.com/v1/consent-sessions
Authorization: Bearer <vendor-token>
Idempotency-Key: <unique-request-key>
Content-Type: application/json

{
  "issuance_profile": "evp_hosted_consent",
  "requested_recipient": "person@example.com",
  "manifest_id": "urn:xcim:manifest:your-product-v3",
  "return_uri": "https://app.example.com/xcim/complete",
  "evp_delivery_mode": "vendor_origin_handoff",
  "evp_nonce": "<32-byte base64url server challenge>",
  "identity_profiles": ["evp-01", "oidc-01"],
  "exchange_endpoint_id": "oxe_your_reviewed_endpoint"
}

Choose one presentation mode: omit evp_delivery_mode for an Emabled-hosted EVP form, or send vendor_origin_handoff when your reviewed HTTPS origin owns the Origin Trial token. EVP-only sessions send identity_profiles: ["evp-01"] and omit exchange_endpoint_id. If the request includes oidc-01, the exchange endpoint must already be reviewed and active. Generate the EVP nonce as exactly 32 cryptographically random bytes encoded as unpadded base64url (43 characters); a UUID is not a valid substitute.

02 / Browser handoff

Redirect the browser; never simulate the hosted page.

Read hosted_consent_uri from the response and navigate the top-level browser to it. Emabled validates the supplied identity evidence, presents the frozen manifest, records the decision and redirects immediately. Receipt signing continues asynchronously.

YOUR BACKENDCreate sessionStore session ID and an opaque recovery ID.
EMABLEDHosted ConsentIdentity once, then explicit purposes.
YOUR RETURN URIResume immediatelyPoll status or process a webhook server-side.
The return URL is terminal and exact.

Register the complete HTTPS return URI in Emabled. It is where Emabled sends the top-level browser after the consent decision. It is not Google's OAuth callback, not an access-token receiver, and not the EVP issuance endpoint. Do not trust a registration ID, email, receipt ID or success flag supplied only in its query string; recover the pending operation from server-side state.

03 / EVP path

The Origin Trial token belongs to the page origin.

The token must be issued for the exact HTTPS origin that serves the email form. A token for partners.lmgram.com cannot activate EVP on consent.emabled.com. Third-party Origin Trials are not currently supported.

Emabled-hostedToken origin: https://consent.emabled.com

Use this only when live capabilities report delivery_modes.emabled_hosted as available and Emabled serves the EVP form.

Vendor-hostedToken origin: https://your-app.example

Use vendor_origin_handoff after that exact origin has an active consent_presentation_delegate domain binding. The raw token travels only from the browser to your backend and then to Emabled.

Current Origin Trial interaction. The complete native EVP form must be present in the initial HTML response. Install the one-time nonce before enabling the email field, then let the person select the address from Chrome's email suggestion UI. The selected address must belong to a verified email provider signed in within that same Chrome profile; being signed in as a different account does not attest the typed address. The official browser checkmark is the observable success signal. Typing, pasting, restoring, moving the address into a later form, or setting it in JavaScript does not produce EVP evidence in the current trial. Missing evidence is an availability result, not an identity rejection. Offer OAuth only when your reviewed OIDC exchange endpoint is active.
Required form fields on the verifier origin
<input name="email-address" type="email" autocomplete="email">
<input type="hidden" name="token"
       nonce="<evp_handoff.nonce>"
       autocomplete="email-verification-token">
Vendor backend relay
POST https://api.emabled.com/v1/consent-sessions/<session_id>/identity-evidence/evp
Authorization: Bearer <token with identity-evidence:submit>
Content-Type: application/json

{
  "nonce": "<evp_handoff.nonce>",
  "token": "<browser-populated EVP token>"
}
  1. Prepare before the email interaction.Create a short-lived, single-use preparation on your backend. Generate a 32-byte base64url nonce and an unrelated opaque preparation ID. Render the same nonce on the hidden EVP field before the person selects an email; never generate or replace it in browser JavaScript.
  2. Keep one email control in one native form.The address requested by signup and the address verified by Chrome must be the same control. Do not ask for it twice, clone it, move it to a second screen, or inject the verifier form after page load.
  3. Bind without destroying browser evidence.Once the field is locally valid, bind the preparation to the normalized address and create the Emabled session using the already-rendered nonce. Changes to the address invalidate the preparation. A repeated request must be idempotent or replace only an expired preparation.
  4. Put the Origin Trial token on the same response as the form.Do not use a token issued for another host, subdomain, port, or protocol. The response must carry the public Origin-Trial header for that exact origin.
  5. Post the native form to your own backend.Submit natively so Chrome can populate the token. JavaScript must not read, log, persist or forward the raw token. Your backend consumes the preparation once, verifies the selected email, then relays the token to Emabled over the authenticated backchannel.
  6. Redirect to hosted_consent_uri after verification.Identity evidence only unlocks the frozen manifest. The person must still make the explicit XCIM purpose decision.
  7. Fall back when EVP is unavailable.Use the configured OAuth/OIDC path or your product's non-XCIM continuation policy. Never silently downgrade to email reply verification.

04 / OAuth path

Keep OAuth standard and keep secrets server-side.

For oidc-01, Emabled starts the reviewed authorization-code relay. The vendor exchanges the code with its own provider client and returns only the signed ID token and required metadata. OAuth is supported independently of EVP; it is both a fallback and a valid primary integration.

Do

  • Register Emabled's callback URI in the vendor OAuth client.
  • Validate exact state, nonce, PKCE, issuer, audience, time, and email policy.
  • Return only the provider-signed ID token through the signed backchannel.
  • Keep client secrets, access tokens, and refresh tokens in the vendor backend.

Do not

  • Send a native Google access token to Emabled.
  • Use a GIS popup callback as if it were an OAuth return URL.
  • Let a vendor endpoint mark identity or consent as verified.
  • Start a second login after the provider flow already returned.
Google Identity Services popup applications.

A GIS JavaScript popup callback is not a redirect URI. You may keep the popup for your application's own login, then pass the provider-signed ID token only through an Emabled-reviewed first-party or backchannel binding. If that binding is not provisioned, create or use a Web OAuth client that supports the Emabled authorization-code callback. Never send a Google access token to Emabled and never replace your internal token-receiving API endpoint with the XCIM return URI.

Callback vocabulary
Google OAuth callback  https://id.emabled.com/oidc/callback/google
XCIM return URI       https://your-app.example/xcim/complete
Hosted Consent       https://consent.emabled.com/s/<session_id>
Receipt query         https://api.emabled.com/v1/receipts/<receipt_id>

05 / Reference lifecycle

Use server state to join the whole flow.

The production-tested pattern separates the browser's navigation state from the server's security state. It survives refreshes, cross-origin redirects, delayed receipts and a return that happens after a local preparation deadline.

Vendor implementation outline
// 1. Initial page response
preparation = createSingleUsePreparation()
nonce = base64url(randomBytes(32))         // exactly 43 chars
renderNativeEvpForm(preparation.id, nonce) // form exists in initial HTML

// 2. Valid email selection / blur
bind(preparation.id, normalize(email))
session = emabled.createConsentSession({ requested_recipient: email, evp_nonce: nonce })
store(preparation.id, session.id, session.hosted_consent_uri)

// 3. Native form POST populated by Chrome
consumeOnce(preparation.id)
emabled.submitEvpEvidence(session.id, nonce, browserToken)
redirect(session.hosted_consent_uri)

// 4. Exact return URI
pending = recoverFromHttpOnlyCookieOrOpaqueRecoveryId()
poll(emabledSessionId)                     // same-origin BFF recommended
verifyReceiptAndCurrentPermission()
materializeAccountOrRequestedOperation()

Persist server-side

  • Opaque preparation/recovery ID.
  • Normalized email commitment and pending payload.
  • Emabled session ID and exact hosted URI.
  • Expiry, one-time consumption and terminal status.

Browser state

  • Secure HttpOnly same-origin cookie as the primary binding.
  • Opaque recovery ID in session storage only when refresh recovery is needed.
  • No raw EVP token, provider token, receipt JWS or email in query parameters.
  • Use a same-origin completion endpoint so secure cookies are sent reliably.

06 / Completion contract

Return immediately; verify the receipt server-side.

The browser return is a UX handoff and must not remain on Hosted Consent waiting for cryptography. Open the product shell immediately, then complete the security-sensitive operation only after the signed receipt is available and valid.

Read session status
GET https://api.emabled.com/v1/consent-sessions/<session_id>

// The decision can be terminal before receipt issuance finishes:
{
  "status": "accepted",
  "identity_verified": true,
  "receipt_id": null
}
StatusAgent action
accepted + no receiptTreat as receipt_pending. Keep the terminal decision recoverable, return the UI to the product and retry with bounded polling or a webhook. Do not expire an already accepted decision because local pending time elapsed.
accepted + receiptVerify the receipt JWS and current permission state, then materialize the account or protected operation idempotently.
identity_unavailable / identity_failedOffer OAuth fallback if configured or return to the product without claiming XCIM consent.
identity_mismatchDo not issue access or grant the requested purpose for the original address. Ask the user to choose the correct identity or cancel.
cancelled / expiredStop the XCIM branch. The product may continue only under its own independent policy.
Receipt verification requirements.

Verify Ed25519 against Emabled's current JWKS; bind receipt_id, application ID, manifest ID/hash, identity evidence and the expected permission; then query current revocation/permission state. An XCIM receipt may intentionally contain expires_at: null. Treat null as no receipt expiry and validate an expiry only when the field is present and non-null. Accept the serialization published by the receipt endpoint, including flattened JWS JSON when returned.

07 / Production troubleshooting

Diagnose the boundary that actually failed.

Do not restart the whole identity flow for every error. Preserve terminal decisions and use safe diagnostics that never log an email, nonce, token, receipt payload or browser evidence.

SymptomLikely cause and fix
No official Chrome checkmarkThe requested address is not verified in the active Chrome profile, the person typed/pasted instead of selecting it, the form or nonce arrived too late, the form was injected or moved, contact-info verification is disabled, or the Origin Trial token does not match the exact origin.
Checkmark appears but Emabled rejects evidenceStart a fresh preparation and complete its native POST within the advertised session lifetime. Emabled measures EVP freshness from challenge creation, allows the configured clock skew, and still validates issuer signature, exact origin, nonce, browser key binding, token expiry and a maximum evidence age of five minutes.
invalid_request creating the sessionConfirm a 32-byte unpadded base64url nonce (43 characters), reviewed source/domain binding, active manifest, exact return URI and enabled capability.
EVP succeeds but Hosted Consent does not openConfirm the native POST consumed the same preparation once, email and nonce match, and the vendor backend submitted evidence with the scoped identity-evidence:submit credential.
Decision button appears stuckQuery the session before asking the person to click again. The decision may already be terminal. Confirm the exact registered return origin is allowed by Hosted Consent's form-action CSP and let Emabled redirect directly.
receipt_pending lasts unexpectedlyKeep polling without discarding accepted consent. Check worker database grants, KMS permissions and operation-level gRPC status. Encryption for stored identity evidence and the asserted-recipient receipt projection must use independent ciphertexts with their own authenticated contexts.
Return says invalid registrationUse a same-origin completion/BFF endpoint, a secure HttpOnly cookie and an opaque recovery ID. Cross-origin fetches do not send the pending cookie unless explicitly configured and should not be the default.
Second login shows provider picker or consent againReuse the application's authenticated session and existing terminal XCIM state. Start a new provider flow only for a new/expired identity operation or a materially changed manifest.

08 / Agent checklist

Definition of done.

A coding agent can use this list as the acceptance gate before opening a pull request or deployment.

Need a reviewed vendor setup?

Use the Emabled console to register sources, domains, OAuth bindings, return URLs, and exchange endpoints. For Origin Trial enablement on a custom vendor origin, contact support@weare14inc.com before deploying.