|
| 1 | +--- |
| 2 | +sidebar_position: 6 |
| 3 | +--- |
| 4 | + |
| 5 | +# wallet-sdk |
| 6 | + |
| 7 | +The **wallet-sdk** is a small TypeScript package that implements the high-level flows for eVault provisioning, platform authentication (signing), and public-key sync. It is **crypto-agnostic**: you supply a **CryptoAdapter** (BYOC – bring your own crypto), and the SDK handles the HTTP and protocol steps. |
| 8 | + |
| 9 | +The [eID Wallet](/docs/Infrastructure/eID-Wallet) uses wallet-sdk with an adapter that delegates to its KeyService, so hardware/software key manager behavior is unchanged. |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +- **Package**: `wallet-sdk` (workspace package under `packages/wallet-sdk/`) |
| 14 | +- **Exports**: `CryptoAdapter` type, `provision`, `authenticate`, `syncPublicKeyToEvault`, and their option/result types |
| 15 | +- **Dependencies**: `jose` (for JWT verification when checking existing keys during sync). Uses the global `fetch` for HTTP |
| 16 | + |
| 17 | +## CryptoAdapter (BYOC) |
| 18 | + |
| 19 | +Implement this interface to plug in your key storage (e.g. KeyService + hardware/software managers): |
| 20 | + |
| 21 | +```typescript |
| 22 | +interface CryptoAdapter { |
| 23 | + getPublicKey(keyId: string, context: string): Promise<string | undefined>; |
| 24 | + signPayload(keyId: string, context: string, payload: string): Promise<string>; |
| 25 | + ensureKey(keyId: string, context: string): Promise<{ created: boolean }>; |
| 26 | +} |
| 27 | +``` |
| 28 | + |
| 29 | +- **getPublicKey**: Return the public key for the given key id and context, or `undefined` if the key does not exist. |
| 30 | +- **signPayload**: Sign the payload with the same key as used for `getPublicKey`. Return the signature string (encoding is up to the adapter, e.g. base64 or multibase). |
| 31 | +- **ensureKey**: Ensure a key exists for the given key id and context; create it if needed. Return `{ created: true }` if a new key was created, `{ created: false }` otherwise. |
| 32 | + |
| 33 | +Contexts used by the eID Wallet include `"onboarding"`, `"pre-verification"`, and `"signing"`. The SDK does not interpret contexts; it only passes them through to the adapter. |
| 34 | + |
| 35 | +## API |
| 36 | + |
| 37 | +### provision(adapter, options) |
| 38 | + |
| 39 | +Provisions an eVault: fetches entropy from the Registry, gets the public key from the adapter, and POSTs to the Provisioner. |
| 40 | + |
| 41 | +**Flow**: |
| 42 | + |
| 43 | +1. `GET {registryUrl}/entropy` → obtain entropy token |
| 44 | +2. `adapter.getPublicKey(keyId, context)` → public key (must exist; ensure key before calling if needed) |
| 45 | +3. `POST {provisionerUrl}/provision` with `{ registryEntropy, namespace, verificationId, publicKey }` |
| 46 | + |
| 47 | +**Options**: `registryUrl`, `provisionerUrl`, `namespace`, `verificationId`, and optionally `keyId` (default `"default"`), `context` (default derived from `isPreVerification`), `isPreVerification`. |
| 48 | + |
| 49 | +**Returns**: `{ success, w3id, uri }`. Throws on HTTP or validation errors. |
| 50 | + |
| 51 | +**Example** (eID Wallet pre-verification): |
| 52 | + |
| 53 | +```typescript |
| 54 | +const result = await provision(globalState.walletSdkAdapter, { |
| 55 | + registryUrl: PUBLIC_REGISTRY_URL, |
| 56 | + provisionerUrl: PUBLIC_PROVISIONER_URL, |
| 57 | + namespace: uuidv4(), |
| 58 | + verificationId, |
| 59 | + keyId: "default", |
| 60 | + context: "pre-verification", |
| 61 | + isPreVerification: true, |
| 62 | +}); |
| 63 | +// result.uri, result.w3id |
| 64 | +``` |
| 65 | + |
| 66 | +### authenticate(adapter, options) |
| 67 | + |
| 68 | +Ensures the key exists and signs the session payload. The **caller** is responsible for sending the signature to the platform (e.g. POST to redirect URL or open deeplink). |
| 69 | + |
| 70 | +**Flow**: |
| 71 | + |
| 72 | +1. `adapter.ensureKey(keyId, context)` |
| 73 | +2. `adapter.signPayload(keyId, context, sessionId)` |
| 74 | +3. Return `{ signature }` |
| 75 | + |
| 76 | +**Options**: `sessionId`, `context`, and optionally `keyId` (default `"default"`). |
| 77 | + |
| 78 | +**Returns**: `{ signature }`. |
| 79 | + |
| 80 | +**Example** (eID Wallet auth): |
| 81 | + |
| 82 | +```typescript |
| 83 | +const { signature } = await authenticate(globalState.walletSdkAdapter, { |
| 84 | + sessionId: sessionPayload, |
| 85 | + keyId: "default", |
| 86 | + context: isFake ? "pre-verification" : "onboarding", |
| 87 | +}); |
| 88 | +// Then POST to redirect URL: { ename, session, signature, appVersion } |
| 89 | +``` |
| 90 | + |
| 91 | +### syncPublicKeyToEvault(adapter, options) |
| 92 | + |
| 93 | +Syncs the adapter’s public key to the eVault: calls `/whois`, optionally skips PATCH if the current key is already present in key-binding certificates (using Registry JWKS), then `PATCH /public-key` if needed. |
| 94 | + |
| 95 | +**Flow**: |
| 96 | + |
| 97 | +1. `GET {evaultUri}/whois` with header `X-ENAME: {eName}` |
| 98 | +2. If `registryUrl` is provided and whois returns key-binding certificates, verify with Registry’s `/.well-known/jwks.json` and skip PATCH if the current public key is already in a valid cert for this eName |
| 99 | +3. `adapter.getPublicKey(keyId, context)` |
| 100 | +4. `PATCH {evaultUri}/public-key` with `{ publicKey }`, headers `X-ENAME` and optional `Authorization: Bearer {authToken}` |
| 101 | + |
| 102 | +The SDK does not read or write `localStorage`; the caller can set a hint (e.g. `publicKeySaved_${eName}`) after a successful sync. |
| 103 | + |
| 104 | +**Options**: `evaultUri`, `eName`, `context`, and optionally `keyId` (default `"default"`), `authToken`, `registryUrl` (for skip-if-present verification). |
| 105 | + |
| 106 | +**Example** (eID Wallet): |
| 107 | + |
| 108 | +```typescript |
| 109 | +await syncPublicKeyToEvault(globalState.walletSdkAdapter, { |
| 110 | + evaultUri: vault.uri, |
| 111 | + eName, |
| 112 | + keyId: "default", |
| 113 | + context: isFake ? "pre-verification" : "onboarding", |
| 114 | + authToken: PUBLIC_EID_WALLET_TOKEN || null, |
| 115 | + registryUrl: PUBLIC_REGISTRY_URL, |
| 116 | +}); |
| 117 | +``` |
| 118 | + |
| 119 | +## Use in the eID Wallet |
| 120 | + |
| 121 | +The eID Wallet: |
| 122 | + |
| 123 | +1. Implements a **CryptoAdapter** by wrapping KeyService in `createKeyServiceCryptoAdapter(keyService)` (see `src/lib/wallet-sdk-adapter.ts`). |
| 124 | +2. Exposes this adapter on GlobalState as `walletSdkAdapter` and passes it into VaultController. |
| 125 | +3. Uses **provision** in the onboarding (pre-verification) and verify (real user) flows instead of inline entropy + provision calls. |
| 126 | +4. Uses **authenticate** in the scan-qr auth and signing flows, then performs the POST or deeplink open in the UI. |
| 127 | +5. Uses **syncPublicKeyToEvault** inside `VaultController.syncPublicKey(eName)` instead of inline whois + PATCH logic. |
| 128 | + |
| 129 | +See [eID Wallet](/docs/Infrastructure/eID-Wallet) for architecture and key manager details. |
| 130 | + |
| 131 | +## References |
| 132 | + |
| 133 | +- [eID Wallet](/docs/Infrastructure/eID-Wallet) – Consumer of wallet-sdk; KeyService and CryptoAdapter |
| 134 | +- [Registry](/docs/Infrastructure/Registry) – Entropy and key-binding certificates |
| 135 | +- [eVault](/docs/Infrastructure/eVault) – Whois and public-key storage |
| 136 | +- [Links](/docs/W3DS%20Basics/Links) – Production URLs (Provisioner, Registry) |
0 commit comments