Key Pair Claim
The keyPair
claim instructs the user's wallet to generate a new cryptographic key pair for a specific purpose. This is a powerful feature for creating new decentralized identifiers (DIDs) on behalf of the user, scoped to your application. Common uses include creating application-specific accounts, performing key rotations for security, or generating temporary session keys.
Upon successful generation, the wallet securely transmits the new secret key back to your application, allowing you to act on behalf of this new identity.
Use Cases#
- Application-Specific Accounts: Generate a dedicated DID for each user within your application, isolating their identity and data from their primary wallet account.
- Key Rotation: Enhance security by allowing users to generate a new key pair and migrate their permissions or assets from an old one.
- Session Keys: Create temporary keys for specific, time-limited sessions without compromising the user's main wallet keys.
Parameters#
The keyPair
claim is configured with the following parameters:
Parameter | Type | Description |
---|---|---|
|
| Required. Must be |
|
| Required. A clear message displayed to the user in their wallet explaining why a new key pair is needed. |
|
| Required. A user-friendly name for the new key pair, which will be visible in the user's wallet (e.g., |
|
| Optional. If |
|
| Optional. The DID of an existing account to migrate from. This is used for key rotation workflows, where the new key pair will replace the old one. |
|
| Optional. An object that specifies the cryptographic properties of the key pair to be generated. |
targetType
Properties#
The targetType
object allows you to define the exact specifications for the new key pair.
Parameter | Type | Default | Description |
---|---|---|---|
|
|
| The role of the new key, such as |
|
|
| The cryptographic key algorithm to use (e.g., |
|
|
| The hash algorithm to use for generating the DID (e.g., |
|
|
| The encoding format for the keys (e.g., |
Example: Generating a New Application Account#
This example demonstrates how to request a new application
key pair from the user's wallet and how to handle the response to store the new credentials securely.
1. Requesting the Key Pair#
First, define the keyPair
claim in your handler. This configuration specifies the details of the key you need, including a custom description and an application-specific role.
// From a DID Connect handler file
module.exports = {
action: 'derive-key-pair',
claims: {
// Request a new key pair from the wallet
keyPair: async ({ extraParams }) => {
const { sessionDid, rotate, declare } = extraParams;
// In a real application, you would fetch user data to determine rotation logic
// const user = await User.ensureOne({ did: sessionDid });
let migrateFrom = '';
if (rotate) {
// Example: migrateFrom = user.generatedApps[0].address;
console.log('Key rotation requested for user:', sessionDid);
}
return {
mfa: true, // Require multi-factor authentication for this sensitive operation
description: 'Please generate a new key-pair for our application.',
moniker: 'test-application',
declare: typeof declare === 'undefined' ? true : !!JSON.parse(declare),
migrateFrom,
targetType: {
role: 'application',
hash: 'sha3',
key: 'ed25519',
encoding: 'base58',
},
};
},
},
// ... onAuth callback defined below
};
2. Handling the Wallet's Response#
After the user approves the request in their wallet, the onAuth
callback receives the newly generated key pair, including the secret key. It is critical to handle this secret key securely.
The following onAuth
function demonstrates how to reconstruct the wallet from the secret key and store its credentials after encrypting a sensitive piece of information.
// Continuing from the handler file above
const { types, Hasher } = require('@ocap/mcrypto');
const AES = require('@ocap/mcrypto/lib/crypter/aes').default;
const { fromSecretKey } = require('@ocap/wallet');
const { fromBase58, toBase58 } = require('@ocap/util');
// ...
module.exports = {
// ... claims definition
onAuth: async ({ claims, extraParams }) => {
const keyPairClaim = claims.find(x => x.type === 'keyPair');
if (!keyPairClaim || !keyPairClaim.secret) {
throw new Error('Key pair generation failed or was declined.');
}
// Reconstruct the application wallet from the secret key provided by the user's wallet
const appWallet = fromSecretKey(fromBase58(keyPairClaim.secret), {
role: types.RoleType.ROLE_APPLICATION,
});
console.log('New application DID generated:', appWallet.address);
console.log('Paired with user DID:', keyPairClaim.userDid);
// IMPORTANT: Securely handle the new key pair.
// Here, we derive a password and use it to encrypt a message.
// In a real application, you would encrypt and store the secret key itself.
const password = Hasher.SHA3.hash256(Buffer.concat([fromBase58(keyPairClaim.secret), fromBase58(appWallet.address)]));
const encryptedData = AES.encrypt('some secret data', password);
// Store the new app's public details and encrypted data in your database
// For example:
// const user = await User.ensureOne({ did: extraParams.sessionDid });
// user.generatedApps = [
// { address: appWallet.address, publicKey: toBase58(appWallet.publicKey), encrypted: encryptedData },
// ];
// await User.update(user);
return {
successMessage: `You have generated a new app DID: ${appWallet.address}`,
};
},
};
Wallet Response Payload#
When the onAuth
callback is invoked, the claims
array will contain an object with the following structure for the keyPair
claim:
{
"type": "keyPair",
"description": "Please generate a new key-pair for our application.",
"moniker": "test-application",
"userDid": "zNKpCN82hT5yDm3xw1T5s7z39v2jea2tiW6o",
"secret": "zsk2hS5nRHG8j2W9fT8o5bE7f...",
"publicKey": "zpub2hS5nRHG8j2W9fT8o5bE7f...",
"targetType": {
"role": "application",
"hash": "sha3",
"key": "ed25519",
"encoding": "base58"
},
"meta": {}
}
Security Warning: The
secret
field contains the private key for the new DID. This is highly sensitive information. Always handle it with extreme care, encrypt it at rest, and never expose it in client-side code or logs.
After successfully generating a key pair, you might need to derive a symmetric key for data encryption. Proceed to the Encryption Key Claim documentation to learn more.