> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Example Usage

> Complete runnable scripts for the agent wallet flow — email OTP with a human user, fully autonomous private-key sign-in, and external JWT sign-in from your own auth system.

One runnable script per sign-in path, covering the whole flow: session keys → sign in → `authenticateJwt` with the session signer → create and sign with `backUpToDynamic: true` → refresh → re-authenticate at the refresh limit.

> [tab] Email OTP (human user)
>
> This script collects the OTP code on stdin; in production, collect it through your own channel.
>
> ```typescript theme={"system"}
> import readline from 'node:readline/promises';
> import { DynamicEvmWalletClient } from '@dynamic-labs-wallet/node-evm';
> import {
>   createAuthClient,
>   generateSessionKeyPair,
>   signSessionMessage,
> } from '@dynamic-labs-wallet/node';
> import { ThresholdSignatureScheme } from '@dynamic-labs-wallet/core';
>
> const environmentId = process.env.DYNAMIC_ENVIRONMENT_ID!;
>
> // 1. Session key pair — persist privateKeyJwk in your secrets vault.
> const { publicKeyHex, privateKeyJwk } = await generateSessionKeyPair();
>
> // 2. Sign the user in with email OTP, binding the session public key into the JWT.
> const auth = createAuthClient({ environmentId });
> const { verificationUUID } = await auth.email.sendOtp('user@example.com');
>
> const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
> const code = await rl.question('OTP code sent to the user: ');
> rl.close();
>
> const { jwt } = await auth.email.verifyOtp({
>   verificationUUID,
>   code,
>   sessionPublicKey: publicKeyHex,
> });
>
> // 3. Authenticate the wallet client with the JWT and the session signer.
> const client = new DynamicEvmWalletClient({
>   environmentId,
>   enableMPCAccelerator: false, // Set to true only on AWS Nitro Enclave-compatible infrastructure
> });
> await client.authenticateJwt(jwt, {
>   getSessionSignature: (message) => signSessionMessage(message, privateKeyJwk),
> });
>
> // 4. Create a wallet for the user, backed up to Dynamic. First run only —
> // on later runs, load the persisted walletMetadata and externalServerKeyShares
> // instead of creating a new wallet.
> const { walletMetadata, externalServerKeyShares } = await client.createWalletAccount({
>   thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
>   password: process.env.WALLET_PASSWORD,
>   backUpToDynamic: true,
> });
> console.log('Wallet created:', walletMetadata.accountAddress);
> // Persist walletMetadata (durable store) and externalServerKeyShares (secrets vault).
>
> // 5. Sign on the user's behalf.
> const signature = await client.signMessage({
>   message: 'Hello from your agent',
>   walletMetadata,
>   externalServerKeyShares,
>   password: process.env.WALLET_PASSWORD,
> });
> console.log('Signed:', signature);
>
> // 6. Long-running sessions: refresh and persist the replacement JWT.
> try {
>   const refreshedJwt = await client.refreshAuthToken();
>   // Overwrite the stored JWT with refreshedJwt.
> } catch {
>   // Refresh limit (refreshExp) reached or session invalid: repeat step 2,
>   // then authenticateJwt with the new token.
> }
> ```

> [tab] Private key (autonomous agent)
>
> No human in the loop: the agent signing token signs the SIWE message, and re-authentication at the refresh limit reuses the same `signIn` function programmatically.
>
> ```typescript theme={"system"}
> import { DynamicEvmWalletClient } from '@dynamic-labs-wallet/node-evm';
> import {
>   createAuthClient,
>   generateSessionKeyPair,
>   signSessionMessage,
> } from '@dynamic-labs-wallet/node';
> import { ThresholdSignatureScheme } from '@dynamic-labs-wallet/core';
> import { privateKeyToAccount } from 'viem/accounts';
>
> const environmentId = process.env.DYNAMIC_ENVIRONMENT_ID!;
>
> // 1. Session key pair — persist privateKeyJwk in your secrets vault.
> const { publicKeyHex, privateKeyJwk } = await generateSessionKeyPair();
>
> // The agent signing token is the agent's identity — load it from your vault or KMS.
> const agentAccount = privateKeyToAccount(process.env.AGENT_SIGNING_TOKEN as `0x${string}`);
>
> // 2. Sign in with the agent signing token, binding the session public key into the JWT.
> const auth = createAuthClient({
>   environmentId,
>   appOrigin: 'https://yourapp.example.com',
> });
>
> const signIn = () =>
>   auth.wallet.signIn({
>     address: agentAccount.address,
>     signMessage: (message) => agentAccount.signMessage({ message }),
>     sessionPublicKey: publicKeyHex,
>     statement: 'Autonomous agent sign-in',
>   });
>
> const { jwt } = await signIn();
>
> // 3. Authenticate the wallet client with the JWT and the session signer.
> const client = new DynamicEvmWalletClient({
>   environmentId,
>   enableMPCAccelerator: false, // Set to true only on AWS Nitro Enclave-compatible infrastructure
> });
> await client.authenticateJwt(jwt, {
>   getSessionSignature: (message) => signSessionMessage(message, privateKeyJwk),
> });
>
> // 4. Create a wallet for the agent's user, backed up to Dynamic. First run
> // only — on later runs, load the persisted walletMetadata and
> // externalServerKeyShares instead of creating a new wallet.
> const { walletMetadata, externalServerKeyShares } = await client.createWalletAccount({
>   thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
>   password: process.env.WALLET_PASSWORD,
>   backUpToDynamic: true,
> });
> console.log('Wallet created:', walletMetadata.accountAddress);
> // Persist walletMetadata (durable store) and externalServerKeyShares (secrets vault).
>
> // 5. Sign as the agent's user.
> const signature = await client.signMessage({
>   message: 'Hello from your agent',
>   walletMetadata,
>   externalServerKeyShares,
>   password: process.env.WALLET_PASSWORD,
> });
> console.log('Signed:', signature);
>
> // 6. Long-running sessions: refresh; past the refresh limit (refreshExp),
> // sign in again — no human needed.
> try {
>   const refreshedJwt = await client.refreshAuthToken();
>   // Overwrite the stored JWT with refreshedJwt.
> } catch {
>   const { jwt: newJwt } = await signIn();
>   await client.authenticateJwt(newJwt, {
>     getSessionSignature: (message) => signSessionMessage(message, privateKeyJwk),
>   });
> }
> ```

> [tab] External JWT (your auth system)
>
> No human in the loop: your issuer attests to the agent's identity, and re-authentication at the refresh limit exchanges a fresh issuer JWT programmatically. Requires [third-party auth](https://docs.dynamic.xyz/docs/auth/bring-your-own-auth.md) configured for the environment.
>
> ```typescript theme={"system"}
> import { DynamicEvmWalletClient } from '@dynamic-labs-wallet/node-evm';
> import {
>   createAuthClient,
>   generateSessionKeyPair,
>   signSessionMessage,
> } from '@dynamic-labs-wallet/node';
> import { ThresholdSignatureScheme } from '@dynamic-labs-wallet/core';
>
> const environmentId = process.env.DYNAMIC_ENVIRONMENT_ID!;
>
> // 1. Session key pair — persist privateKeyJwk in your secrets vault.
> const { publicKeyHex, privateKeyJwk } = await generateSessionKeyPair();
>
> // 2. Exchange a JWT from your issuer for a Dynamic user JWT, binding the
> // session public key. requestJwtFromYourIssuer is your integration: it
> // returns a fresh JWT signed by your configured external issuer, with a
> // stable sub for this agent — a different sub is a different Dynamic user.
> const auth = createAuthClient({ environmentId });
>
> const signIn = async () =>
>   auth.externalJwt.signIn({
>     jwt: await requestJwtFromYourIssuer(),
>     sessionPublicKey: publicKeyHex,
>   });
>
> const { jwt } = await signIn();
>
> // 3. Authenticate the wallet client with the JWT and the session signer.
> const client = new DynamicEvmWalletClient({
>   environmentId,
>   enableMPCAccelerator: false, // Set to true only on AWS Nitro Enclave-compatible infrastructure
> });
> await client.authenticateJwt(jwt, {
>   getSessionSignature: (message) => signSessionMessage(message, privateKeyJwk),
> });
>
> // 4. Create a wallet for the agent's user, backed up to Dynamic. First run
> // only — on later runs, load the persisted walletMetadata and
> // externalServerKeyShares instead of creating a new wallet.
> const { walletMetadata, externalServerKeyShares } = await client.createWalletAccount({
>   thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
>   password: process.env.WALLET_PASSWORD,
>   backUpToDynamic: true,
> });
> console.log('Wallet created:', walletMetadata.accountAddress);
> // Persist walletMetadata (durable store) and externalServerKeyShares (secrets vault).
>
> // 5. Sign as the agent's user.
> const signature = await client.signMessage({
>   message: 'Hello from your agent',
>   walletMetadata,
>   externalServerKeyShares,
>   password: process.env.WALLET_PASSWORD,
> });
> console.log('Signed:', signature);
>
> // 6. Long-running sessions: refresh; past the refresh limit (refreshExp),
> // exchange a fresh issuer JWT — no human needed.
> try {
>   const refreshedJwt = await client.refreshAuthToken();
>   // Overwrite the stored JWT with refreshedJwt.
> } catch {
>   const { jwt: newJwt } = await signIn();
>   await client.authenticateJwt(newJwt, {
>     getSessionSignature: (message) => signSessionMessage(message, privateKeyJwk),
>   });
> }
> ```

Run any of them with your environment variables set, for example:

```bash theme={"system"}
npx tsx --env-file=.env agent.ts
```

If sign-in or wallet creation fails, check the [console configuration steps in the quickstart](https://docs.dynamic.xyz/docs/node/quickstart.md) first: embedded wallets enabled, chains enabled, and the environment ID correct.

## Related pages

* [Sign In with Email OTP](https://docs.dynamic.xyz/docs/node/agents/sign-in-with-email-otp.md)
* [Sign In with a Private Key](https://docs.dynamic.xyz/docs/node/agents/sign-in-with-a-private-key.md)
* [Sign In with an External JWT](https://docs.dynamic.xyz/docs/node/agents/sign-in-with-an-external-jwt.md)
* [Use Agent Wallets](https://docs.dynamic.xyz/docs/node/agents/use-agent-wallets.md)
* [Storage & Security](https://docs.dynamic.xyz/docs/node/agents/storage-and-security.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.