Security
What Inodra can and cannot do
- Inodra never holds a user key. The ephemeral key is made in your app and stays there.
- Inodra cannot sign for a user. A signature needs the ephemeral private key, which we never see.
- Inodra sees the JWT of each login. It uses the JWT to derive the salt and to make the proof.
How salts work
Inodra derives salts from a master seed and the verified JWT. It does not store them.
- The same user and client ID always give the same salt, so the same address.
- Each Inodra organization has its own key space. The same Google user gets a different address under each organization.
- The network is not an input. A user has the same address on mainnet, testnet, and devnet.
seedVersionin the address response names the version of the derivation. The current version is1.
Salt best practices
- Store the salt with the user record when a user first logs in. It is your record of that user's address.
- Treat the salt as private user data. Do not log it, and do not put it in a URL.
- Keep one OAuth client ID per app across web, iOS, and Android. A different client ID is a different address.
- Do not compute salts yourself. Send the JWT to
/zklogin/addressand use the salt and address it returns.
Where the master seed lives
- The master seed was generated inside an AWS Nitro Enclave.
- It never leaves the enclave in plaintext. No person has seen it.
- AWS KMS releases the seed only to an enclave image that Inodra's release key signed.
- The enclave verifies the JWT itself. It answers one question: the salt for a verified JWT.
- The enclave has no network of its own. It reaches only the four providers' key endpoints, through allow-listed tunnels, and TLS ends inside the enclave.
- On request, Inodra provides the enclave's signed attestation document. It carries the measurements of the running image and the fingerprint of the key that signed it.
- A backup exists only as encrypted shards. Each shard opens only with its own key, and two of the three shards are needed to rebuild the seed.
Residual trust
We state plainly what you still trust:
- The image signing key. The key is offline. A person who holds it could sign a different enclave image. The attestation document would show that the image changed.
- The operator at ceremony time. The seed is created and loaded through the enclave's host machine, and the enclave cannot prove that a key-release message came from AWS KMS. Inodra runs these steps from a fresh boot on a host it controls. Once a seed is loaded, the enclave refuses to load or replace it until it restarts.
- The enclave's host and Inodra's API servers. The host relays each request to the enclave, so it sees the JWT and the salt of each login in transit, as the API servers do. Your app receives the same salt in the address response. Neither the host nor the API servers can reach the master seed or a tenant seed.
- The OAuth provider. The provider controls who can get a JWT for a user. This is true for all zkLogin wallets.
What the salt protects
- The salt hides the link between the OAuth identity and the Sui address.
- A leaked salt links one identity to one address. This is a privacy loss.
- A leaked salt does not allow spending. Spending needs a JWT that is bound to the session nonce, plus the ephemeral private key.
The ephemeral key
- The ephemeral private key plus the proof can sign for the user until
maxEpochpasses. - Keep the key in
sessionStorageor in memory. Do not send it to a server. Do not write it to a log. - Delete the key and the proof when the user logs out.
Session length
maxEpochbounds how long an ephemeral key works. An epoch is about 24 hours.- A shorter session is safer. A stolen ephemeral key stops working when the epoch passes
maxEpoch. - The maximum is the current epoch + 30. We recommend the current epoch + 2.
No lock-in
- Every address response includes the salt. Store salts yourself as users log in, and you can leave at any time.
- The address is a public function of the salt and the JWT claims, computed by the Sui SDK. With the salt, every address stays the same on any salt service and prover.
- Tenant seed export is planned. The enclave will release your organization's tenant seed only with a signed authorization, encrypted to a key you supply. With it you can reproduce the salt of every user, including users who never came back.
API keys in a browser
The two endpoints are safe to call from a browser when the key is restricted:
- Give the key only the zkLogin scope.
- Set allowed origins.
- Set a per-IP rate limit. A proof costs 50 credits, so the limit bounds your cost.
- The client ID list is a second gate. A JWT for another app's client ID gets
403 AUDIENCE_NOT_ALLOWED.
See API Key Security.
The client ID rule
The address depends on the OAuth client ID. Use one shared client ID on web, iOS, and Android, and do not rotate it. See The client ID rule.