Authentication
How to authenticate with the Etch API.
Overview
Etch uses wallet-based authentication. You don’t need API keys — you authenticate by signing a message with your Solana wallet.
Authentication Flow
Step 1: Request a Challenge
curl -X POST https://etch.film.fun/api/auth/challenge \
-H "Content-Type: application/json" \
-d '{ "wallet": "YOUR_WALLET_ADDRESS" }'Response:
{
"challenge": "Sign this message to authenticate with Etch:\n\nNonce: abc123\nTimestamp: 2026-02-15T12:00:00Z",
"nonce": "abc123",
"expiresAt": "2026-02-15T12:05:00Z"
}Step 2: Sign the Challenge
Sign the challenge message with your wallet. In JavaScript:
import { Connection, Keypair } from "@solana/web3.js";
import nacl from "tweetnacl";
import bs58 from "bs58";
const message = new TextEncoder().encode(challenge);
const signature = nacl.sign.detached(message, wallet.secretKey);
const signatureBase58 = bs58.encode(signature);Step 3: Verify and Get Token
curl -X POST https://etch.film.fun/api/auth/verify \
-H "Content-Type: application/json" \
-d '{
"wallet": "YOUR_WALLET_ADDRESS",
"nonce": "abc123",
"signature": "BASE58_SIGNATURE"
}'Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expiresAt": "2026-02-16T12:00:00Z",
"wallet": "YOUR_WALLET_ADDRESS"
}Step 4: Use the Token
Include the token in all subsequent requests:
curl https://etch.film.fun/api/launches \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Token Expiration
Tokens expire after 24 hours. To refresh:
- Request a new challenge
- Sign and verify again
Code Examples
TypeScript/JavaScript
import { Keypair } from "@solana/web3.js";
import nacl from "tweetnacl";
import bs58 from "bs58";
async function authenticate(wallet: Keypair) {
// 1. Get challenge
const challengeRes = await fetch("https://etch.film.fun/api/auth/challenge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ wallet: wallet.publicKey.toBase58() }),
});
const { challenge, nonce } = await challengeRes.json();
// 2. Sign challenge
const message = new TextEncoder().encode(challenge);
const signature = nacl.sign.detached(message, wallet.secretKey);
const signatureBase58 = bs58.encode(signature);
// 3. Verify and get token
const verifyRes = await fetch("https://etch.film.fun/api/auth/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
wallet: wallet.publicKey.toBase58(),
nonce,
signature: signatureBase58,
}),
});
const { token } = await verifyRes.json();
return token;
}
// Use the token
const token = await authenticate(myWallet);
const launches = await fetch("https://etch.film.fun/api/launches", {
headers: { Authorization: `Bearer ${token}` },
});Python
import requests
from solana.keypair import Keypair
import nacl.signing
import base58
def authenticate(wallet: Keypair) -> str:
# 1. Get challenge
challenge_res = requests.post(
"https://etch.film.fun/api/auth/challenge",
json={"wallet": str(wallet.public_key)}
)
data = challenge_res.json()
challenge = data["challenge"]
nonce = data["nonce"]
# 2. Sign challenge
message = challenge.encode()
signed = wallet.sign(message)
signature = base58.b58encode(signed.signature).decode()
# 3. Verify
verify_res = requests.post(
"https://etch.film.fun/api/auth/verify",
json={
"wallet": str(wallet.public_key),
"nonce": nonce,
"signature": signature
}
)
return verify_res.json()["token"]Security Best Practices
- Never share your token — Treat it like a password
- Use HTTPS — All API requests must use HTTPS
- Rotate tokens — Re-authenticate periodically
- Store securely — Don’t commit tokens to version control
Last updated on