Skip to Content
APIAuthentication

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:

  1. Request a new challenge
  2. 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

  1. Never share your token — Treat it like a password
  2. Use HTTPS — All API requests must use HTTPS
  3. Rotate tokens — Re-authenticate periodically
  4. Store securely — Don’t commit tokens to version control
Last updated on