# 🛡️ Security & Authentication

TunnelSats provides two primary ways to authenticate your requests. Understanding which one to use depends on whether you are building a centralized service or a privacy-first Nostr integration.

---

## 🔑 1. API Keys (Bearer Token)

API Keys are the simplest way to authenticate and are recommended for most backend integrators.

* **Format:** `sk_live_[random_string]`
* **Header:** `Authorization: Bearer sk_live_...`

### Best Practices
* **Never expose your API key in client-side code (Frontend).**
* Store keys in environment variables (`.env.local`).
* Rotate your keys immediately if you suspect a leak.

---

## 💜 2. Nostr Auth (NIP-98)

For users who want to stay anonymous or integrate directly with the Nostr ecosystem, we support **NIP-98 (HTTP Authentication for Nostr)**.

### How it works
1. Create a "Kind 27235" event.
2. Sign it with your Nostr Private Key (nsec).
3. Base64-encode the signed event JSON.
4. Pass it in the header as: `Authorization: Nostr [base64_encoded_event]`

### Generation Script (Bash + nostr-tool)

```bash
#!/bin/bash
PRIV_KEY="<your_nsec_hex>"
URL="https://tunnelsats.com/api/public/v1/subscription/list"
METHOD="GET"

# 1. Create Event
EVENT=$(nostr-tool event -p "$PRIV_KEY" -k 27235 -u "$URL" -m "$METHOD")

# 2. Base64 Encode
TOKEN=$(echo "$EVENT" | base64 -w 0)

# 3. Request
curl -s -X $METHOD "$URL" \
  -H "Authorization: Nostr $TOKEN"
```

---

## 🔒 3. Rate Limiting Strategy

Our API uses a tiered rate-limiting system to protect the network.

* **Bearer Auth:** Higher limits (linked to your account status).
* **NIP-98 Auth:** Standard public limits.
* **Unauthenticated:** Low limits (per IP).

### Handling 429 Responses
When you receive an `ERR_RATE_LIMIT_EXCEEDED` (429), your application MUST stop polling for at least the number of seconds specified in the `Retry-After` header.

```javascript
const response = await fetch('/api/public/v1/subscription/list', {
  headers: { 'Authorization': `Bearer ${process.env.TS_API_KEY}` }
});

if (response.status === 429) {
  const waitSeconds = response.headers.get('Retry-After') || 30;
  console.warn(`Rate limited. Waiting ${waitSeconds}s...`);
  await new Promise(r => setTimeout(r, waitSeconds * 1000));
  // Retry logic...
}
```
