> For the complete documentation index, see [llms.txt](https://docs.0xpass.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.0xpass.io/guides-and-examples/quickstarts-and-examples/passkey-account.md).

# Passkey Account

This quick start guide will walk you through how to quickly get setup with the Passport SDK, register and authenticate users, and start signing messages and transactions. You can skip to the [#complete-setup](#complete-setup "mention"), and then follow the section step-by-step where each code snippet will be explained. You can also quickly pull the completed repository here <https://github.com/0xpass/passport-quickstart> and follow along.

### Project setup

First we'll setup a Next.js project, with tailwind, we can do this with the following command, and walk through the configuration wizard, making sure to chose the app-router, and tailwind.

```bash
npx create-next-app@latest
```

### Setup and Dependencies

Firstly, we'll ensure we have all the requires dependencies. So we're going to install the Passport SDK **`@0xpass/passport`** to interact with Passport protocol, and `viem` for blockchain interactions. We'll also install some helper packages **`@0xpass/passport-viem`** to seamlessly use **`Passport`** with **`viem`**, and finally **`@0xpass/webauthn-signer`** to handle our passkey registration and authentication.

{% tabs %}
{% tab title="npm" %}

```bash
npm install @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}
{% endtabs %}

Firstly let's setup a **`usePassport`** hook, which gives us an easy way to access our **`Passport`** instance.&#x20;

```typescript
import { useRef } from "react";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { Network, Passport } from "@0xpass/passport";

export function usePassport(scopeId: string) {
  const signerRef = useRef<WebauthnSigner | null>(null);
  const passportRef = useRef<Passport | null>(null);

  if (!signerRef.current) {
    signerRef.current = new WebauthnSigner({
      rpId: process.env.NEXT_PUBLIC_RP_ID!,
      rpName: "0xPass",
    });
  }

  if (!passportRef.current) {
    passportRef.current = new Passport({
      scopeId: scopeId,
      signer: signerRef.current,
      network: Network.TESTNET,
    });
  }

  return {
    passport: passportRef.current,
    signer: signerRef.current,
  };
}
```

Now in our **`page.tsx`** we can setup our state variables for, tracking registering, and authenticating users. We'll also use our **`Passport`** and **`WebauthnSigner`** instances, from the hook we just created. as well as our Alchemy url and a fallback provider, which we'll make use of when we want to signMessages with our **`WalletClient`**.

```typescript
"use client";
import { useState } from "react";
import { createPassportClient } from "@0xpass/passport-viem";
import { http } from "viem";
import { mainnet } from "viem/chains";
import { usePassport } from "./hooks/usePassport";

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);
  const [signMessageLoading, setSignMessageLoading] = useState(false);
  const [message, setMessage] = useState("");
  const [messageSignature, setMessageSignature] = useState("");
  const [authenticatedHeader, setAuthenticatedHeader] = useState({});
  const [address, setAddress] = useState<string>();

  const alchemyUrl = process.env.NEXT_PUBLIC_ALCHEMY_URL!;
  const fallbackProvider = http(alchemyUrl);

  const userInput = {
    username: username,
    userDisplayName: username,
  };

  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");
```

We use a **`useRef`** so that a new instance of **`WebauthnSigner`** and **`Passport`** aren't re-created during re-renders.

Next up we're going to setup our **`WalletClient`** with viem,  our functions to register and authenticate users, as well as sign messages.

So we set up the functions for these as follows, we setup the **`register` , `authenticate`** and **`signMessage`** functions, as well as our **`createWalletClient`** function which allows us to set up client to use any **`viem`** functionality.&#x20;

```typescript
  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [authenticatedHeader, address] = await passport.authenticate(
        userInput
      )!;
      setAuthenticatedHeader(authenticatedHeader);
      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }

  async function createWalletClient() {
    return await createPassportClient(
      authenticatedHeader,
      fallbackProvider,
      mainnet
    );
  }

  async function signMessage(message: string) {
    try {
      setSignMessageLoading(true);
      const client = await createWalletClient();
      const [address] = await client.getAddresses();
      const response = await client.signMessage({
        account: address,
        message,
      });

      setMessageSignature(response);
      setSignMessageLoading(false);
    } catch (error) {
      console.error(error);
    }
  }
```

### Complete Setup

Now with all of this setup we can setup our UI too, so the overall setup looks as below. In the final part of our setup, we've created the UI layer to interact with the above functions. We have buttons to register and authenticate, which dynamically interact with the state, to show loading states, as well as authenticated states, and finally when a message is signed, the user is also able to see the signed message signature.

```typescript
"use client";
import { useState } from "react";
import { createPassportClient } from "@0xpass/passport-viem";
import { http } from "viem";
import { mainnet } from "viem/chains";
import { usePassport } from "./hooks/usePassport";

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);
  const [signMessageLoading, setSignMessageLoading] = useState(false);
  const [message, setMessage] = useState("");
  const [messageSignature, setMessageSignature] = useState("");
  const [authenticatedHeader, setAuthenticatedHeader] = useState({});
  const [address, setAddress] = useState<string>();

  const alchemyUrl = process.env.NEXT_PUBLIC_ALCHEMY_URL!;
  const fallbackProvider = http(alchemyUrl);

  const userInput = {
    username: username,
    userDisplayName: username,
  };

  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");

  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [authenticatedHeader, address] = await passport.authenticate(
        userInput
      )!;
      setAuthenticatedHeader(authenticatedHeader);
      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }

  async function createWalletClient() {
    return await createPassportClient(
      authenticatedHeader,
      fallbackProvider,
      mainnet
    );
  }

  async function signMessage(message: string) {
    try {
      setSignMessageLoading(true);
      const client = await createWalletClient();
      const [address] = await client.getAddresses();
      const response = await client.signMessage({
        account: address,
        message,
      });

      setMessageSignature(response);
      setSignMessageLoading(false);
    } catch (error) {
      console.error(error);
    }
  }

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2 bg-white text-black">
      <div
        className={`text-2xl font-bold mb-8 ${
          authenticated ? "text-green-500" : "text-red-500"
        }`}
      >
        {authenticated ? "Authenticated" : "Not authenticated"}
      </div>
      <div className="text-center">
        <h1 className="text-3xl font-bold underline">
          Passport Protocol Quickstart
        </h1>
        <p className="mt-2 text-lg">
          This is a quickstart guide for the Passport Protocol SDK.
        </p>

        <div className="flex flex-col mt-4 space-y-4">
          {authenticated ? (
            <>
              <div className="flex flex-col space-y-4">
                <div className="flex items-center justify-between">
                  <div className="font-bold">Address</div>
                  <div>{address}</div>
                </div>
              </div>

              {messageSignature && (
                <div className="flex flex-col space-y-4 max-w-[60ch] break-words">
                  <div className="font-bold">Message Signature</div>
                  <div>{messageSignature}</div>
                </div>
              )}

              <input
                value={message}
                onChange={(e) => setMessage(e.target.value)}
                className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                placeholder="Message to sign"
              />
              <button
                onClick={async () => await signMessage(message)}
                disabled={signMessageLoading}
                className="border border-1 rounded p-2 border-black mb-4 ml-2"
              >
                {signMessageLoading ? "Signing..." : "Sign Message"}
              </button>
            </>
          ) : (
            <div className="mb-12 flex flex-col space-y-2 mt-8">
              <input
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                placeholder="Enter unique username"
              />
              <button
                className="border border-1 rounded p-2 border-black mb-4 ml-2"
                onClick={async () => {
                  if (authenticateSetup) {
                    await authenticate();
                  } else {
                    await register();
                  }
                }}
                disabled={registering || authenticating}
              >
                {authenticateSetup
                  ? authenticating
                    ? "Authenticating..."
                    : "Authenticate"
                  : registering
                  ? "Registering..."
                  : authenticating
                  ? "Authenticating..."
                  : "Register"}
              </button>

              <span
                onClick={() => setAuthenticateSetup(!authenticateSetup)}
                className="cursor-pointer"
              >
                {authenticateSetup
                  ? "Register a Passkey?"
                  : "Already have a passkey?"}
              </span>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.0xpass.io/guides-and-examples/quickstarts-and-examples/passkey-account.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
