# Backend identity contracts (https://docs.open-e2ee.dev/relay/backend-identity.md)



Reviewed: 2026-10-22.

Your application can retain its existing authentication. Its backend verifies the session or intended API token, checks current member eligibility, and issues the [Relay-specific ES256 assertion](https://docs.open-e2ee.dev/relay/custom-token.md). A provider token does not grant Relay account-management authority.

## Evidence levels [#evidence-levels]

The [Better Auth recipe](https://docs.open-e2ee.dev/relay/better-auth.md) has a local real-provider test path and an explicit actual-Relay verifier path. Their recorded results must accompany acceptance. They do not prove a hosted provider deployment.

The other rows below describe backend contracts from primary provider documentation. They are not tested vendor adapters or native Relay profiles. Hosted acceptance remains unverified for every row.

| Existing login     | Backend verification                                                                                                                  | Stable mapping and standing                                                                                                                          | Evidence                                                                                                                                                         |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Better Auth        | Actual server `auth.api.getSession` with the cookie cache disabled.                                                                   | Stateful session revocation plus current application membership in a server-selected tenant.                                                         | Local recipe tests; hosted unverified.                                                                                                                           |
| WorkOS AuthKit     | Supported sealed-session helper and its authentication result.                                                                        | Map the verified user in the intended Organization. Check current application membership; cached role claims alone are insufficient.                 | [Documented contract](https://workos.com/docs/reference/authkit/session-helpers); hosted unverified.                                                             |
| Auth0              | Current server `Auth0Client.getSession`; validate intended API tokens when that is the application's contract.                        | Qualify the immutable provider subject by issuer/tenant, then check current application membership.                                                  | [Documented contract](https://auth0.github.io/nextjs-auth0/classes/server.Auth0Client.html); hosted unverified.                                                  |
| Supabase Auth      | Supported server verification; use `getUser` when current user data is needed. Do not authorize from embedded `getSession` user data. | Map the verified user to the application tenant. Check current standing separately. `getUser` alone does not guarantee immediate session revocation. | [Documented contract](https://supabase.com/docs/guides/auth/server-side/creating-a-client); hosted unverified.                                                   |
| Amazon Cognito     | Supported verifier checks issuer, expiry, `token_use`, and the applicable access `client_id` or ID-token `aud`.                       | Qualify the user by pool/issuer. Check current application membership and disablement policy.                                                        | [Documented contract](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html); hosted unverified. |
| Microsoft Entra ID | Validate the exact API audience, intended tenant, and actor.                                                                          | A tenant-qualified user mapping must distinguish users from service principals. `tid` or `oid` possession alone grants no membership.                | [Documented contract](https://learn.microsoft.com/en-us/entra/identity-platform/claims-validation); hosted unverified.                                           |
| Okta               | Supported backend verifier with the intended issuer and API audience.                                                                 | Qualify the subject by issuer. Check current application eligibility.                                                                                | [Documented contract](https://developer.okta.com/docs/guides/validate-access-tokens/nodejs/main/); hosted unverified.                                            |
| Keycloak           | Supported backend verification or confidential-client introspection under the application's policy.                                   | Qualify the subject by realm/issuer and intended audience. Check current application eligibility.                                                    | [Documented contract](https://www.keycloak.org/securing-apps/oidc-layers); hosted unverified.                                                                    |

Do not forward an ordinary ID token, API access token, or arbitrary JWKS URL as a Relay assertion. The configured custom-token profile accepts its exact issuer, audience, algorithm, subject claim, and public keys.

## Own the member mapping [#own-the-member-mapping]

Assign an opaque, immutable, non-reassigned local member ID. The Better Auth broker signs `JSON.stringify([tenantId, memberId])` under its configured issuer. This encoding qualifies the subject by tenant and preserves delimiter boundaries. Preserve the tuple and encoding for existing accounts. Never use a matching email as proof that two provider accounts belong to one member.

Link multiple providers only after authenticating both accounts and checking application authorization. Preserve the application member ID when a phone number, username, display name, or login provider changes. Refuse tenant substitutions. Deny guest issuance unless an explicit supported member policy covers those guests.

A verified session identifies the caller. Your current membership store decides eligibility. Select the tenant from trusted application routing or server configuration. Do not let a body field choose a different tenant, signing profile, or member.

## Own assurance and keys [#own-assurance-and-keys]

Each provider path must identify the actual authentication event that supports recent or step-up assurance. A refreshed token, session extension, or cached claim cannot supply missing authentication evidence. If the backend lacks that evidence, refuse the requested assurance.

Keep the Relay assertion signing key separate from provider credentials, device authentication keys, and Signal identity keys. Retain verification-key overlap for outstanding assertions and clock tolerance. Test key removal before rollout. Key removal does not revoke existing Relay device proofs.

## Loss of membership and provider events [#loss-of-membership-and-provider-events]

Refuse new assertions when the authoritative session or application membership is no longer valid. Existing devices require a supported privileged lifecycle operation to stop identified access. Recovery replaces encryption identity and is not a disable operation. A sender identity cannot cancel anonymous capabilities that do not contain it.

The customer lifecycle procedure awaits the supported backend and CLI surface. This issuance recipe does not expose private controls or service credentials. Customer suspension/resume acceptance remains open.

This recipe includes no provider event adapter. Before adding one, specify signature verification, issuer/tenant binding, event ordering, deduplication, exact member mapping, retries, and reconciliation. Do not infer current standing from delivery order or an event's absence. Preserve the exact unresolved lifecycle attempt across a lost response.

## Application acceptance [#application-acceptance]

1. Verify two different members receive distinct Relay bindings.
2. Verify repeat authentication preserves one member's binding.
3. Refuse missing, expired, revoked, disabled, and foreign-tenant sessions.
4. Verify a retained session-cache cookie cannot bypass revocation.
5. Refuse recovery assurance without actual authentication evidence.
6. Verify phone and username changes preserve the member mapping.
7. Test encrypted exchange between real devices before rollout.
8. Complete customer lifecycle acceptance when its supported surface exists.

The SDK package does not include these provider adapters or their dependencies. Use supported provider libraries on your backend. The application remains responsible for its membership, authentication evidence, signing keys, and deprovisioning policy.
