Passkeys provide a secure way to authorize actions on Privy server wallets. This guide shows how to integrate your existing passkey implementation as an authorization mechanism for Privy server wallets, combining modern authentication with powerful onchain actions.

Overview

Authorization keys provide a way to ensure that actions taken by your app’s wallets can only be authorized by an explicit user request. When you specify an owner of a resource, all requests to update that resource must be signed with this key. This security measure verifies that each request comes from your authorized passkey owner and helps prevent unauthorized operations.

Setting up passkeys

If you need a passkey implementation set up for your application, we recommend using the WebAuthn standard, which provides phishing-resistant, passwordless authentication.

Creating and registering server wallets with passkey authorization

Follow these steps to create a server wallet and register it with a user’s passkey for authorization.

  1. Retrieve the user’s passkey P-256 public key and send it to your backend.

  2. From your backend, call the Privy API to create a wallet with that P-256 public key as the owner. You can do this via the Privy SDK (below) or by hitting the Privy API directly.

const passkeyP256PublicKey = 'your-p256-public-key';

const privy = new PrivyClient('your-app-id', 'your-app-secret');

const wallet = await privyClient.wallets.create({
  owner: {
    publicKey: passkeyP256PublicKey
  }
});
  1. Associate the returned wallet ID with the user on your backend for use in future requests.

Sending transactions with passkey authorization

Below are the steps necessary to create a transaction request, have the user sign it with their passkey, and submit the signed request to Privy:

  1. On your client, create you desired transaction request body.

  2. Format the request body in preparation for signing. You can do this manually or using the Privy SDK (below).

import {formatRequestForAuthorizationSignature} from '@privy-io/server-auth/wallet-api';

const input: WalletApiRequestSignatureInput = ...;
const serializedPayload = formatRequestForAuthorizationSignature(input);
  1. Sign the formatted transaction request with the user’s passkey.

  2. Send the signature and transaction request to your backend.

  3. Send the transaction request with the signature to the Privy API.

That’s it! Whenever a user registers a passkey for your app, they will then have access to a provisioned server wallet for secure and flexible transaction signing and sending. 🎉