---
name: siwa-openfort
version: 0.2.0
description: >
  Openfort backend wallet integration for SIWA authentication.
---

# SIWA Openfort Signer

Sign SIWA messages using Openfort's backend wallets.

## Install

```bash
npm install @buildersgarden/siwa @openfort/openfort-node
```

## Create Signer

```typescript
import { createOpenfortSiwaSigner } from "@buildersgarden/siwa/signer";

const signer = await createOpenfortSiwaSigner({
  apiKey: process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!,
  walletSecret: process.env.OPENFORT_WALLET_SECRET!,
  accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,
});
```

The wallet address is fetched automatically from Openfort.

## From Existing Client

If you already have an Openfort client instance:

```typescript
import Openfort from "@openfort/openfort-node";
import { createOpenfortSiwaSignerFromClient } from "@buildersgarden/siwa/signer";

const client = new Openfort(process.env.OPENFORT_PROJECT_PUBLISHABLE_KEY!, {
  walletSecret: process.env.OPENFORT_WALLET_SECRET!,
});

const signer = await createOpenfortSiwaSignerFromClient({
  client,
  accountId: process.env.OPENFORT_BACKEND_WALLET_ACCOUNT_ID!,
});
```

---

## SIWA Authentication Flow

The authentication flow consists of two steps:

> **Note:** The URLs below (`api.example.com`) are placeholders. Replace them with your own server that implements the SIWA verification endpoints. See the [Server-Side Verification](https://siwa.id/skills/server-side/skill.md) skill for implementation details.

1. **Get a nonce** from the server's `/siwa/nonce` endpoint
2. **Sign and verify** by sending the signature to `/siwa/verify`

### Step 1: Request Nonce

```typescript
const nonceRes = await fetch("https://api.example.com/siwa/nonce", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    address: await signer.getAddress(),
    agentId: 42,
    agentRegistry: "eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e",
  }),
});
const { nonce, nonceToken, issuedAt, expirationTime } = await nonceRes.json();
```

### Step 2: Sign and Verify

```typescript
import { signSIWAMessage } from "@buildersgarden/siwa";

const { message, signature, address } = await signSIWAMessage(
  {
    domain: "api.example.com",
    uri: "https://api.example.com/siwa",
    agentId: 42,
    agentRegistry: "eip155:84532:0x8004A818BFB912233c491871b3d84c89A494BD9e", //According to the chain
    chainId: 84532,
    nonce,
    issuedAt,
    expirationTime,
  },
  signer,
);

// Send to server for verification
const verifyRes = await fetch("https://api.example.com/siwa/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message, signature, nonceToken }),
});

const { receipt, agentId } = await verifyRes.json();
// Store the receipt for authenticated API calls
```

## Sign Authenticated Request (ERC-8128)

```typescript
import { signAuthenticatedRequest } from "@buildersgarden/siwa/erc8128";

const request = new Request("https://api.example.com/action", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ action: "execute" }),
});

const signedRequest = await signAuthenticatedRequest(
  request,
  receipt, // from SIWA sign-in
  signer,
  84532,
);

const response = await fetch(signedRequest);
```

## Environment Variables

```bash
OPENFORT_PROJECT_PUBLISHABLE_KEY=your-openfort-api-key
OPENFORT_WALLET_SECRET=your-wallet-secret
OPENFORT_BACKEND_WALLET_ACCOUNT_ID=your-account-id
```
