nostr-auth
nostr-auth-agents
Nostr sign-in for LLM coding agents — auth-only, no wallet, no browser extension, no relay account.
An agent (Claude Code, OpenCode, OpenClaw, Codex, Cursor, ...) is handed a "Sign in with Nostr" challenge or event template. This repo signs it with a secp256k1 (BIP-340 schnorr) key derived from a local master secret, and optionally submits the signature to the service callback.
Zero npm runtime dependencies: pure BigInt secp256k1/schnorr + node:crypto.
Boots from a clean clone.
Methods
Method | Status | Notes |
NIP-07 sign-in (challenge event signing) | ✅ v1.0.0 | Mirrors the LNURL-auth UX |
NIP-98 HTTP Auth ( | 🔜 planned | next |
NIP-42 relay AUTH (websocket) | 🔜 planned | |
NIP-05 identifier resolution | 🔜 planned |
Usage
# Sign a classic kind-22242 sign-in challenge and submit it
node nostr_auth.js nip07 --challenge "<hex>" \
--relay "wss://relay.example.com" \
--domain example.com \
--callback "https://site.example.com/verify"
# Dry-run: sign but don't submit (inspect first)
node nostr_auth.js nip07 --challenge "<hex>" --dry-run --json
# Sign an arbitrary event template (what window.nostr.signEvent would do)
node nostr_auth.js nip07 '{"kind":22242,"tags":[["challenge","<hex>"]],"content":""}'
# Print the derived identity (hex pubkey + npub)
node nostr_auth.js nip07 pubkey --domain example.comProgress logs go to stderr; results (JSON) go to stdout. Exit codes:
0 accepted, 1 client error, 2 usage, 3 server ERROR, 4 non-JSON
callback response.
Key management
First run generates a 32-byte master secret at
~/.config/nostr-auth/master.key(mode0600).Per-service identity:
linkingPriv = HMAC-SHA256(master, serviceDomain). Same domain → same npub; different domains → different npubs (privacy).--single-keyshares one identity across all services.--generateoverwrites the master secret. Override path with--keyfile/--keyoutor theNOSTR_AUTH_KEYFILEenv var.
Protocol (NIP-07 style)
Challenge → event (kind
22242by default) withchallengeand optionalrelaytags.NIP-01 id:
sha256(JSON.stringify([0, pubkey, created_at, kind, tags, content])).BIP-340 schnorr sign the raw 32-byte id → 64-byte hex
sig.POST
{"event": {...}}to the callback →{"status":"OK"}/{"status":"ERROR","reason":"..."}.
See SKILL.md for the full agent-facing docs.
MCP server
Zero-dependency stdio MCP server (mcp/server.js) exposing
nostr_nip07_sign / nostr_nip07_pubkey tools:
{
"mcpServers": {
"nostr-auth": { "command": "node", "args": ["mcp/server.js"] }
}
}Plugin manifests for Claude Code (.claude-plugin/), Codex, Cursor, and
skills.sh discoverability (skills.sh.json) are included. See
PUBLISHING.md for distribution status per platform.
Install as an agent skill (per platform)
Claude Code / any MCP client: drop the repo in your skills dir, use
SKILL.md+.mcp.json.OpenClaw / ClawHub:
skills/nostr-auth/is an autonomous bundle (SKILL.md+scripts/nostr_auth.js, zero npm deps).skills.sh (Vercel):
npx skills add dyegolara/nostr-auth-agentsnpm:
npm i -g nostr-auth→nostr-auth nip07 ...
Self-test (offline, cost-free)
npm ci
npm testA local mock "Sign in with Nostr" service (mock_server.js) validates the
challenge → sign → submit → verify roundtrip, replay rejection, dry-run
safety, per-domain identity stability, and the portable skill bundle.
Project layout
nostr_auth.js CLI (bin "nostr-auth")
lib/ key mgmt, BIP-340 schnorr, NIP-01 events, NIP-07 flow
mcp/server.js zero-dep MCP server (stdio)
mock_server.js local sign-in mock for tests
skills/nostr-auth/ portable OpenClaw/ClawHub skill bundle
contrib/anthropics/ educational skill variant for anthropics/skills
test/ vitest suiteLicense
MIT — see LICENSE. Auth-only: this project never holds funds, never publishes notes, and never connects to a relay on its own.