What you implement
- Encrypt the secret for the invitee’s identity using
encryptPayloadForHandle (or encryptPayloadForIdentity with their public key).
- Encode the result with
encodeWrappedPayloadParam from @ave-id/sdk/client.
- Add it to the Ave sign-in / authorize URL as the query parameter
wrapped_key (see below).
- Read the plaintext after redirect: fragment
unwrapped_secret (base64url of the decrypted bytes), or unwrappedSecretB64 on the embed success payload — not decryptWrappedPayload in your own app.
Ave runs unwrap in the browser after the user consents and unlocks their key. Your server never receives the Ave master key; you only store the wrapped ciphertext until you send the user to Ave.
Where to put wrapped_key
Use buildAuthorizeUrl (or any link to https://aveid.net/signin / /authorize with the same query shape) and pass the encoded blob via extraParams:
import { buildAuthorizeUrl, getIdentityPublicKey } from "@ave-id/sdk";
import {
encryptPayloadForHandle,
encodeWrappedPayloadParam,
} from "@ave-id/sdk/client";
const wrapped = await encryptPayloadForHandle(
new TextEncoder().encode(JSON.stringify({ workspaceKey: "…" })),
{ issuer: "https://aveid.net", handle: "alice" }
);
const wrappedKey = encodeWrappedPayloadParam(wrapped);
const url = buildAuthorizeUrl(
{
clientId: "YOUR_CLIENT_ID",
redirectUri: "https://yourapp.com/callback",
},
{
codeChallenge: challenge,
codeChallengeMethod: "S256",
extraParams: { wrapped_key: wrappedKey },
}
);
window.location.href = url;
| Query param | Value |
|---|
wrapped_key | Output of encodeWrappedPayloadParam(wrapped) — URL-safe base64 over JSON {"encryptedPayload","senderPublicKey"}. Max length 65536 characters. |
Do not send the raw JSON in the query string; always use encodeWrappedPayloadParam.
What you get back
After successful authorization:
| Channel | Plaintext |
|---|
| Full-page redirect | URL fragment includes unwrapped_secret=<base64url> (same encoding style as encodeWrappedPayloadParam input: base64url over raw decrypted bytes). If the secret is too long for a safe fragment (~1800 chars), authorization fails unless embed=1. |
embed=1 | postMessage success payload includes unwrappedSecretB64 (same bytes, base64url string). |
If the app is E2EE-capable, app_key may appear in the same fragment; parse both keys from the hash.
API reference (keys only)
GET /api/signing/public-key/:handle — public key for wrapping.
GET /api/signing/keys/:identityId — envelope (session); used by Ave during unwrap, not for your invite encryption step.
Signing API
decryptWrappedPayload in the SDK
That helper is for local testing or non-Ave environments. Production flows should use wrapped_key → Ave → unwrapped_secret, not client-side unwrap on your origin without the master key.
Model (short)
| |
|---|
| Wrapped blob | Stored in your database until the user visits Ave with wrapped_key. |
E2EE app_key | Separate mechanism — End-to-end encryption. |
FedCM
wrapped_key is not supported on FedCM finalize yet; use the normal redirect flow. Last modified on May 1, 2026