> ## 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.

# Manage Signers

> Grant and revoke the ability to sign with a business-account wallet.

> [!NOTE]
>
> Business Accounts are in **early access**. See [Business Accounts](https://docs.dynamic.xyz/docs/business-accounts/accounts.md) for the model.

A **signer** can approve transactions and messages with a specific wallet. Signing access is separate from [membership roles](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/members-and-roles.md). Adding a signer grants them access; removing one only revokes theirs. The wallet and other signers stay intact.

> [!NOTE]
>
> Only an owner or admin can add signers, and the caller must already be an **active signer** on that wallet. This operation requires [step-up authentication](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/step-up-auth.md).

## Add a signer

`addBusinessAccountSigner` grants signing access to a user and returns a `shareSetId`. Identify them by a known `userId`, or by an `identifier` + `identifierType`. For example, when you provide an email, the user is created if they do not exist yet. If adding the signer requires quorum approval, it returns a pending action instead. Narrow it with `isBusinessAccountActionRequired`.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { addBusinessAccountSigner, isBusinessAccountActionRequired } from '@dynamic-labs-sdk/client/waas';
>
> // Load both values from your secure storage.
> const password = await loadCurrentSignerPassword();
> const targetSignerPassword = await loadTargetSignerPassword();
>
> const result = await addBusinessAccountSigner({
>   businessAccountId: account.id,
>   walletAccount,                 // a WalletAccount the caller can sign with
>   signerType: 'endUser',
>   targetIdentity: { identifier: 'teammate@acme.com', identifierType: 'email' },
>   password,
>   targetSignerPassword,
> });
>
> if (isBusinessAccountActionRequired(result)) {
>   // Quorum not met yet — no share set to use until it's approved.
>   throw new Error('Adding this signer requires approval.');
> }
>
> const { shareSetId } = result;
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useAddBusinessAccountSigner } from '@dynamic-labs-sdk/react-hooks';
>
> const AddSigner = ({ walletAccount, businessAccountId, password, targetSignerPassword }) => {
>   const { mutate, isPending } = useAddBusinessAccountSigner();
>   return (
>     <button
>       disabled={isPending}
>       onClick={() =>
>         mutate({
>           businessAccountId,
>           walletAccount,
>           signerType: 'endUser',
>           targetIdentity: { userId: 'user-123' },
>           password,
>           targetSignerPassword,
>         })
>       }
>     >
>       Add signer
>     </button>
>   );
> };
> ```

**walletAccount** `WalletAccount` *required*

The wallet to add a signer to, from the caller's `getWalletAccounts()`.

**targetIdentity** `\{ userId \} | \{ identifier, identifierType \}` *required*

Who to add: a known `userId`, or an `identifier` (e.g. email) plus its `identifierType`.

**signerType** `'endUser' | 'server'`

Whether the new signer is an end user or a server signer. Only `endUser` is supported today; `server` is coming soon.

**password** `string`

Your password, when your key share is password-encrypted and you have not already unlocked it this session. It unlocks your own key share, and is never applied to the new signer's share.

**targetSignerPassword** `string`

A separate developer-managed value that encrypts the new signer's key share before backup. It is required when wallet passwords are required by your environment, and optional otherwise.

**initialSignerRules** `WaasPolicyRule[]`

Rules that seed the new signer's policy layer at creation time. Build each rule with `buildAllowPolicyRule` or `buildDenyPolicyRule`.

> [!NOTE]
>
> To change the new signer's policy after creation, use the `shareSetId` returned by `addBusinessAccountSigner` with `createPolicy`, or with `upsertSignerPolicyRule` for a layer of declarative rules (see [Declarative rules for business accounts](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/policies/declarative-rules.md)).

## Passwords when adding a signer

A password encrypts one person's key share, not the wallet. `password` and `targetSignerPassword` protect different shares.

1. `password` unlocks your own key share so the reshare can run. If the share is already unlocked for this session, you can omit it.
2. The reshare mints a new key share for the signer you add. Your own share set is untouched.
3. The SDK encrypts the new share locally with `targetSignerPassword`, then sends only the encrypted share to Dynamic for backup.
4. Your application makes `targetSignerPassword` available to the target signer after authentication. They use it to recover their share, then replace it with the password they use for their other wallets by calling `updateWaasPassword` with a wallet-specific `passwordOverrides` entry.

> [!WARNING]
>
> If wallet passwords are required by your environment, omitting `targetSignerPassword` rejects the request before the reshare starts, with the error `A target signer password is required for this environment.` Otherwise, the field is optional and the SDK uses the environment's default encryption instead of a caller-controlled password.

Your application is responsible for generating, protecting, and retrieving `targetSignerPassword`. Derive it per signer, for example from a per-signer salt and a server-side secret held in your backend, and return it only over an authenticated request. Do not reuse the current signer's password. Dynamic's backup service does not receive the raw value. See [Creating a wallet with a developer-provided salt](https://docs.dynamic.xyz/docs/javascript/reference/waas/password-encryption.md#creating-a-wallet-with-a-developer-provided-salt) for a derivation pattern you can reuse.

### Move the new share to the signer's existing password

When the target signer already has password-encrypted wallets, `updateWaasPassword` must decrypt all of the signer's wallets before it can update them. Pass the signer's existing password as `currentPassword`, and identify the newly added wallet with its temporary password in `passwordOverrides`:

```javascript theme={"system"}
import { updateWaasPassword } from '@dynamic-labs-sdk/client/waas';

await updateWaasPassword({
  walletAccount: newlyAddedSignerWallet,
  currentPassword: userPassword,
  newPassword: userPassword,
  passwordOverrides: [
    {
      walletId: newlyAddedSignerWallet.verifiedCredentialId,
      existingPassword: targetSignerPassword,
    },
  ],
});
```

Use the wallet's `verifiedCredentialId` for `walletId`. The update applies to all wallets associated with the signer and leaves them synchronized under `newPassword`. Do not call `setWaasWalletAccountPassword` for the new share because it is already password-encrypted. Keep the temporary password available until the update succeeds, and never log or transmit it through an unsecured channel.

## Remove a signer

`removeBusinessAccountSigner` revokes a signer's access to a wallet. The wallet and every other signer are untouched.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { removeBusinessAccountSigner } from '@dynamic-labs-sdk/client/waas';
>
> await removeBusinessAccountSigner({
>   businessAccountId: account.id,
>   walletId,
>   signerId,
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useRemoveBusinessAccountSigner } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutate } = useRemoveBusinessAccountSigner();
> mutate({ businessAccountId, walletId, signerId });
> ```

> [!WARNING]
>
> You cannot remove the **last active signer** on a wallet because no one could approve transactions afterward. Add another signer, or remove the wallet, first.

## Next steps

> [card] [Members & roles](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/members-and-roles.md)
>
> Administer who can manage the account.

> [card] [Sign transactions](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/signing.md)
>
> Use a signer's share to sign.


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