Skip to content

Turnkey Signer

TurnkeySigner is a signer implementation which extends SmartAccountAuthenticator to leverage the Turnkey SDK. It supports features such as authentication, message and typed data signing, and authentication details retrieval.

TurnkeySigner provides implementations for all methods on SmartAccountAuthenticator:

  1. authenticate -- supports user authentication.
  2. getAddress -- gets the address of the smart contract account's connected EOA signer account.
  3. signMessage -- supports message signatures.
  4. signTypedData -- supports typed data signatures.
  5. getAuthDetails -- supports authentication details retrieval.

Install dependencies

TurnkeySigner requires installation of the @turnkey/http and @turnkey/viem dependencies. aa-signers lists them as optional dependencies.

Every request to Turnkey must be signed using a stamper. In this example, we use the WebAuthn stamper from @turnkey/webauthn-stamper.

bash
npm i -s @turnkey/http
npm i -s @turnkey/viem
npm i -s @turnkey/webauthn-stamper
bash
yarn add @turnkey/http
yarn add @turnkey/viem
yarn add @turnkey/webauthn-stamper

Usage

ts
import { TurnkeySigner, TurnkeySubOrganization } from "@alchemy/aa-signers/turnkey";
import { WebauthnStamper } from "@turnkey/webauthn-stamper";
import { http } from "viem";

const turnkeySigner = new TurnkeySigner({
  apiUrl: "api.turnkey.com",
  stamper: new WebauthnStamper({
    rpId: "your.app.xyz",
  }),
});

const authParams = {
  resolveSubOrganization: async () => {
    return new TurnkeySubOrganization({
      subOrganizationId: "12345678-1234-1234-1234-123456789abc",
      signWith: "0x1234567890123456789012345678901234567890",
    })
  },
  transport: http("https://eth-sepolia.g.alchemy.com/v2/ALCHEMY_API_KEY");
};

await turnkeySigner.authenticate(authParams);

const address = await turnkeySigner.getAddress();

const details = await turnkeySigner.getAuthDetails();

const signedMessage = await turnkeySigner.signMessage("test");

const typedData = {
  types: {
    Request: [{ name: "hello", type: "string" }],
  },
  primaryType: "Request",
  message: {
    hello: "world",
  },
};
const signTypedData = await turnkeySigner.signTypedData(typedData);
ts
import {
  TurnkeySigner,
  TurnkeySubOrganization,
} from "@alchemy/aa-signers/turnkey";
import { WebauthnStamper } from "@turnkey/webauthn-stamper";
import { http } from "viem";

const TURNKEY_BASE_URL = "https://api.turnkey.com";

export const createTurnkeySigner = async () => {
  const turnkeySigner = new TurnkeySigner({
    apiUrl: TURNKEY_BASE_URL,
    // API Key, WebAuthn, or Email Auth [stampers](https://docs.turnkey.com/category/api-design)
    // must sign all requests to Turnkey.
    stamper: new WebauthnStamper({
      rpId: "your.app.xyz",
    }),
  });

  await turnkeySigner.authenticate({
    resolveSubOrganization: async () => {
      return new TurnkeySubOrganization({
        subOrganizationId: "12345678-1234-1234-1234-123456789abc",
        signWith: "0x1234567890123456789012345678901234567890",
      });
    },
    transport: http("https://eth-sepolia.g.alchemy.com/v2/ALCHEMY_API_KEY"),
  });

  return turnkeySigner;
};