Skip to Content
DevelopersNIP-98 HTTP authentication

NIP-98 HTTP authentication

Several services used with Shosho require NIP-98 authentication: the Shosho Streaming API, the Show Chat API, and nostr.build file uploads.

NIP-98 means signing a kind 27235 event and including it base64-encoded in the Authorization: Nostr <token> header.

The auth event

Per NIP-98 :

  • kind MUST be 27235.
  • content SHOULD be empty.
  • Tag u MUST be set to the absolute request URL, including query parameters — the server checks for an exact match.
  • Tag method MUST be the HTTP method (GET, POST, PATCH, DELETE, etc.).
  • created_at MUST be within a reasonable freshness window — NIP-98 suggests 60 seconds, and Shosho enforces 60 seconds. Don’t cache or reuse tokens.
  • For requests with a body (POST/PUT/PATCH), clients SHOULD include a payload tag with the SHA-256 hex of the request body: ["payload", "<sha256-hex>"]. Servers MAY validate it. (Shosho’s current validator does not check this, but include it for spec compliance and to be future-proof.)

Pattern

# Generate a NIP-98 auth token for any URL AUTH=$(nak event -k 27235 \ -t u=<full_request_url_including_query_string> \ -t method=<HTTP_METHOD> \ --sec <nsec1...> < /dev/null 2>/dev/null | base64) # Use it in a curl request curl -H "Authorization: Nostr $AUTH" <full_request_url_including_query_string>

For a POST/PUT/PATCH with a body, include the payload tag:

BODY='{"dTag":"my-stream-id","status":"ended"}' PAYLOAD=$(printf %s "$BODY" | shasum -a 256 | cut -d' ' -f1) AUTH=$(nak event -k 27235 \ -t u=https://shosho.live/api/show-chat/update \ -t method=POST \ -t payload=$PAYLOAD \ --sec <nsec1...> < /dev/null 2>/dev/null | base64) curl -X POST -H "Authorization: Nostr $AUTH" \ -H "Content-Type: application/json" \ -d "$BODY" \ https://shosho.live/api/show-chat/update

Common failure modes

  • URL mismatch. The u tag is matched exactly. If the request URL contains a query string (e.g. ?amount=1000), the u tag must include the same query string. Trailing slashes count.
  • Stale token. Tokens older than 60 seconds are rejected with 401. Generate a fresh token per request rather than reusing one.
  • Method mismatch. A GET token won’t authorise a POST, even on the same URL.

Why < /dev/null and 2>/dev/null?

  • < /dev/null — required because some nak subcommands (event, encode naddr) read from stdin when their output is piped or captured in a $() subshell. Without it, the command will hang.
  • 2>/dev/null — suppresses stderr connection messages.

Use < /dev/null on any nak call inside a subshell.

Where this pattern applies

Last updated on