# Getting Started with AuthFetch

Canonical: https://docs.projectbabbage.com/docs/guides/wallet/auth

Learn to build without passwords, empowering users with control over their identities in your app.

_Build password-free, BRC-100-native authentication in a single afternoon._

## Why AuthFetch?

Traditional auth stacks juggle:

* User tables
* Password resets & 2FA
* JWT secrets & session stores

With a BRC-100 wallet, the user already has a **cryptographic key pair** available for app authentication.
AuthFetch lets the browser sign requests with that key; Auth Express Middleware verifies the signature server-side and exposes a **pre-verified `identityKey`** on `req.auth`. No passwords, no cookies, no phishable tokens.

![Layered BSV app architecture showing a wallet-mediated app request flowing through services and returning verified results](https://docs.projectbabbage.com/assets/images/docs/bsv-app-stack.webp)

AuthFetch signs browser requests with the user's wallet identity. Auth Express Middleware verifies those signatures and attaches the verified identity to the request before your route handler runs.

## Prerequisites

| Tool | Why you need it | Link |
|------|-----------------|------|
| **BRC-100 wallet** | Provides the user’s wallet, identity key, and permission prompts | [Getting a Wallet](https://docs.projectbabbage.com/docs/quickstarts/getting-a-wallet) |
| **Node.js 22 or 24 (maintained and patched)** | Runs the TypeScript SDK & Express | [https://nodejs.org](https://nodejs.org) |
| **BSV TypeScript SDK** | WalletClient, AuthFetch, utilities | `npm i @bsv/sdk` |
| **Auth Express Middleware** | Verifies AuthFetch headers server-side | `npm i @bsv/auth-express-middleware` |

> NOTE: All packages are BSV-licensed and published on npm. Always run `npm audit` before shipping to prod.

## High-level flow

1. The browser app connects to the user's BRC-100 wallet.
2. The wallet authenticates the user and exposes an approved identity key.
3. `AuthFetch` signs an HTTP request with wallet-controlled key material.
4. Express receives the request.
5. Auth Express Middleware verifies the signature.
6. Your route handler reads `req.auth.identityKey` and responds.

## Step-by-Step Tutorial

### 1. Initialise your project

```bash
mkdir bsv-auth-demo && cd bsv-auth-demo
npm init -y
npm i express cors @bsv/sdk @bsv/auth-express-middleware
npm i -D typescript ts-node nodemon @types/express
npx tsc --init
```

### 2. Build the client

`src/client/index.ts`

```ts
import { WalletClient, AuthFetch } from '@bsv/sdk'

// 1. Connect to the user's BRC-100 wallet
const wallet = new WalletClient('auto')
await wallet.waitForAuthentication()

// 2. Create an AuthFetch instance
const authFetch = new AuthFetch(wallet)

// 3. Make an authenticated call
async function getProfile() {
  const res = await authFetch.fetch('http://localhost:3000/api/profile', {
    method: 'GET',
  })
  if (res.ok) {
    const data = await res.json()
    console.log('Profile', data)
  } else {
    console.error('Auth failed', await res.text())
  }
}

document
  .getElementById('login-btn')
  ?.addEventListener('click', getProfile)
```

What’s happening?

1. **WalletClient** asks the user's BRC-100 wallet to expose the approved identity to the app.
2. **AuthFetch** signs the HTTP request body + path with the private key.
3. The identity key + signature travel in HTTP headers.

### 3. Create the Express backend

`src/server/index.ts`

```ts
import express from 'express'
import cors from 'cors'
import { ProtoWallet } from '@bsv/sdk'
import { createAuthMiddleware } from '@bsv/auth-express-middleware'

// 1️⃣ Spin up Express
const app = express()
app.use(cors())
app.use(express.json())

// 2️⃣ Inject Auth middleware
const wallet = new ProtoWallet('anyone')
const authMiddleware = createAuthMiddleware({
  wallet,
  allowUnauthenticated: false
})
app.use(authMiddleware)

// 3️⃣ Define an authenticated route
app.get('/api/profile', (req, res) => {
  // If signature fails, middleware already sent 401
  const identityKey = req.auth.identityKey
  console.log('Verified identityKey:', req.auth.identityKey)
  return res.json({
    hello: 'BSV!',
    yourIdentityKey: identityKey,
  })
})

app.listen(3000, () =>
  console.log('API listening on http://localhost:3000')
)
```

Behind the scenes:

* **ECDSA verify** – Confirms the header signature matches the public key of the user.
* On success it attaches `req.auth = { identityKey }`.
* On failure it returns `401 Unauthorized` before your route handler runs.

### 4. Test it end-to-end

1. Start the backend:

   ```bash
   nodemon --exec ts-node src/server/index.ts
   ```

2. Serve your static client (any dev server works, e.g. `vite preview`).

3. Click **Log In**. Open browser dev-tools → *Network* → request headers:

   ```
   X-BSV-Auth-Identity-Key: 023ac9…cd8e
   X-BSV-Auth-Signature: 3044…
   ```

4. Check terminal logs:

   ```
   API listening on http://localhost:3000
   Verified identityKey: 03ab…ff91
   ```

You just authenticated a user **without a database lookup or password**.

## Using `identityKey` as your primary user handle

Because the key is:

* **Globally unique** (only one wallet controls it)
* **Cryptographically provable** (ECDSA)
* **Portable** across all BRC-100 apps/wallets/backends

…it can safely replace `users.id` in most schemas.

```ts
// Example: fetching a user profile by identityKey
const profile = await db.profiles.findOne({ identityKey: req.auth.identityKey })
```

If you need human-readable aliases, store them in a separate table keyed by `identityKey`.

Alternatively, you can gradually adopt the BSV identity stack's [digital certificate and identity resolution](https://docs.projectbabbage.com/docs/guides/wallet/certificates) features.

## Extra Recipes

### 1. Role-based access

```ts
app.post('/api/admin/ban', (req, res, next) => {
  const { identityKey } = req.auth
  if (!ADMIN_KEYS.includes(identityKey)) return res.sendStatus(403)
  next()
})
```

### 2. Pay-per-API-call

The server's private key can be used with WUI to maintain a balance and receive funds from users.

The [Payment Express middleware](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/payment-express-middleware) can be layered on top, so you can [collect micropayment revenue per API call](https://docs.projectbabbage.com/docs/quickstarts/micropayments-in-action).

## Concept Glossary

| Term | TL;DR |
|------|-------|
| **Metanet** | Layered data & identity network atop the BSV blockchain—not a sidechain, not an indexer. |
| **BRC-100 Wallet** | Vendor-neutral wallet API spec implemented by BSV Desktop, BSV Browser, and other compatible wallets. |
| **Identity Key** | Something a user holds in their wallet that servers can easily check and use instead of passwords. |
| **AuthFetch** | Browser helper that signs HTTP requests with the identity key. |
| **Auth Express Middleware** | Server middleware that verifies AuthFetch headers. |

## Next Steps

* 📚 **Read the in-depth API docs** – <https://github.com/bsv-blockchain/auth-express-middleware>
* 🛠 **Fork a demo** – <https://github.com/p2ppsr/marscast>
* 💬 **Join the community** – use the current community links from [Project Babbage](https://projectbabbage.com/Contact).
* 🤝 **Need guidance?** – [Book a 2-week Discovery Sprint](https://projectbabbage.com/Contact) and let our engineers pair-program the pilot with you.

## Troubleshooting

| Symptom | Possible Cause | Fix |
|---------|---------------|-----|
| `401 Unauthorized` | Signature or identity key not provided in header | Make sure you're using AuthFetch and the user has a BRC-100 wallet installed and connected. |
| “Wallet denied permission” | User clicked “deny” | Tell the user to allow your app access, and explain why in a modal. |
| CORS preflight fails | Missing `OPTIONS` handler | `app.use(cors())` before `createAuthMiddleware` |

### You’re now using wallet-native auth

Password dialogs are gone. Phishable shared secrets are gone. Your app is BRC-100-native.

Plug this pattern into any React, Vue, or vanilla site to keep user authentication tied to wallet-controlled keys.
