E2eiEnrollment handle (exposed as RustyE2eIdentity in the lower-level crate). You must hold onto this handle for the entire enrollment session and pass it to the final completion step.
Prerequisites
Before starting enrollment:- The PKI environment must be set up. Register the ACME root CA with
e2ei_register_acme_caand any intermediate CAs withe2ei_register_intermediate_ca_pem. - You must know the client ID in Wire format (
wireapp://<user-b64url>!<device-hex>@<domain>), the user’s display name, and the user’s Wire handle.
Full enrollment flow
Create an enrollment handle
Call Parameters:
e2ei_new_enrollment on the transaction context. This generates the ACME account keypair and the MLS signing keypair internally.| Parameter | Type | Description |
|---|---|---|
client_id | ClientId | Wire client identifier (user UUID + device hex + domain) |
display_name | String | Human-readable name shown in the app |
handle | String | Wire user handle |
team | Option<String> | Wire team slug, if applicable |
expiry_sec | u32 | Requested certificate lifetime in seconds |
ciphersuite | Ciphersuite | MLS ciphersuite determining the signature algorithm |
TypeScript (WASM) and Kotlin/Swift (UniFFI) clients access the same logic through their respective FFI wrappers. The method names and parameter order match the Rust API.
Fetch the ACME directory
Make a
GET request to the ACME directory endpoint and pass the JSON response body to acme_directory_response.Get the first nonce
Make a
HEAD request to the new-nonce URL from the directory. The nonce is in the Replay-Nonce response header.Every subsequent ACME request consumes the nonce from the previous response’s
Replay-Nonce header. Keep track of the latest nonce after each call.Create a new order
Submit an order that specifies both the device identifier and the user identifier.The response contains two authorization URLs in
new_order.authorizations. The order of the two authorization URLs is not guaranteed — you must check the identifier.type field of each authorization to determine which is wireapp-device and which is wireapp-user.Fetch authorizations and challenges
Post to each authorization URL to retrieve the associated challenge.The
E2eiAcmeAuthorization::User variant also provides a keyauth string. You must pass this value and the challenge’s target URL to the OIDC authorization request so the IdP embeds them in the ID token.Fetch a nonce from the Wire server
Before creating the DPoP token, fetch a fresh nonce from the Wire backend. This nonce prevents replay attacks against the access-token endpoint.
Create the DPoP token
Generate a DPoP JWT that binds the Wire backend nonce, the ACME challenge token, and the client identity.The DPoP token is a
dpop+jwt signed with the ACME account keypair. Its aud claim is the ACME challenge URL and its htu is the Wire access-token endpoint.Get an access token from the Wire server
Exchange the DPoP token for a Wire access token by posting to the access-token endpoint. Include the DPoP token in the The access token is a
DPoP request header.at+jwt signed by a Wire backend key that the ACME server trusts. It embeds the original DPoP token as the proof claim.Complete the DPoP challenge
Submit the access token to the ACME server to satisfy the A successful response has
wire-dpop-01 challenge."status": "valid" for the challenge.Complete the OIDC challenge
Initiate an OIDC Authorization Code + PKCE flow with the organization’s identity provider. The authorization request must include the
keyauth and acme_aud values from the earlier authorization step using the OIDC claims parameter.After the user authenticates, extract the ID token from the IdP’s token response and submit it to the ACME server.Finalize the order (submit CSR)
Generate and submit a CSR to the ACME server’s finalize URL. CoreCrypto constructs the CSR automatically from the enrollment keypair.
Fetch the certificate chain
Fetch the issued certificate chain from the URL provided in the finalize response.The response body is a PEM-encoded certificate chain (end-entity certificate followed by any intermediate certificates).
Complete enrollment
Pass the PEM certificate chain to CoreCrypto. Use Credential rotation on an existing client:
e2ei_mls_init_only for fresh installs (the MLS client has not been initialized yet) or save_x509_credential for credential rotation on an existing client.Fresh install:After
e2ei_mls_init_only or save_x509_credential returns, the enrollment handle is consumed. Do not reuse it. Start a new enrollment if you need to renew the certificate.CRL distribution points
Bothe2ei_mls_init_only and save_x509_credential return a set of CRL distribution point URLs found in the certificate chain. You should fetch each CRL and register it: