Keyshare Export
Export reconstructs the full private key of an MPC wallet by combining the client's keyshare with the server's. Use it to move a wallet out of MPC — for example, into another wallet ecosystem.
Once the private key is exported, the MPC security guarantees are gone. The key exists in one place, on the client, and whoever holds it controls the wallet.
This is not the same operation as backup and recovery, which moves the client's encrypted keyshare in and out of storage and never reconstructs a private key.
Why it goes through auth-svc
The cloud node exposes its export endpoint without authentication. It has no notion of users — it holds keyshares indexed by key_id, and it hands the encrypted share to anyone who asks for one.
auth-svc mirrors each of the node's export URLs one-to-one and puts three checks in front of them:
- A valid JWT access token.
- The token's
scopeclaim containsexport:keyshare. - The authenticated user owns the wallet named by
key_idin the request body.
Only then does auth-svc forward the request to the node and relay the response. The exported share is encrypted end-to-end to a public key the client generates, so auth-svc never sees key material in the clear.
Endpoints
The path encodes the signature scheme. The request and response bodies are identical for all three.
| Scheme | Endpoint |
|---|---|
| ECDSA | POST /v3/ecdsa/export |
| EdDSA | POST /v3/eddsa/export |
| Taproot | POST /v3/taproot/export |
All three require Authorization: Bearer <access_token> with the export:keyshare scope. See POST /v3/ecdsa/export for the full contract.
Configuration
auth-svc needs to know where the node is:
PROXY_UPSTREAM_URL=http://localhost:8080
Point it at the duo server. The docker-compose stacks set this for you — docker-compose.all.yml uses http://duo-server:8080.
If PROXY_UPSTREAM_URL is unset, auth-svc starts with a warning and every export request fails with 100411.
auth-svc is the authenticated front door, not a firewall. The node's own export path stays open, so a client that can reach the node directly can skip every check above and export any key_id it can guess.
In production, the cloud node must not be reachable from the public internet on its export path. Terminate traffic at a reverse proxy that allows /v3/*/export only from auth-svc, or keep the node on a private network where auth-svc is its only ingress. The boilerplate's compose stacks do not do this for you — they put every service on one Docker network for local development.
Granting the scope
export:keyshare is a permission on your Auth0 API, granted like the other boilerplate scopes — see Auth0 setup. Because it authorizes handing over a full private key, treat it as the most sensitive scope in the set: grant it to the specific client that performs export rather than to every application, and request it only in the token that runs the export flow.
For an end-to-end run with the demo client, see Authenticated Keyshare Export.