CommunityEscrita e Ediçãogithub.com

dyegolara/lnurl-auth-agentes

Assinante LNURL-auth (LUD-04) para agentes de codificação LLM — Faça login com Lightning, sem necessidade de carteira

O que é lnurl-auth-agentes?

Esta skill implementa o protocolo LNURL-auth (LUD-04) para que agentes de IA, como Claude Code ou Cursor, possam autenticar-se em serviços web usando 'Sign in with Lightning' sem precisar de uma carteira Lightning ou gastar dinheiro. Ela permite que o agente assine um desafio `k1` de 32 bytes recebido do servidor usando uma chave privada secp256k1, retornando a assinatura e a chave pública via GET para o callback. A skill gera uma chave mestre local e deriva chaves de ligação determinísticas por domínio (via HMAC-SHA256), preservando a privacidade entre serviços. Suporta Node.js (v20.19+) com dependências vendadas (como `@noble/secp256k1` e `bech32`), oferece opções para gerenciamento de chaves, modo dry-run, saída JSON, e inclui testes automatizados para verificar o fluxo completo.

Funciona com✓Claude Code✓Codex CLI✓Cursor✓OpenCode
npx skills add dyegolara/lnurl-auth-agents

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

lnurl-auth (LUD-04)

Autentique-se em um serviço usando LNURL-auth (Lightning "Entre com Lightning") inteiramente do lado do cliente. Isto é apenas autenticação: o servidor envia um desafio k1, você assina o k1 bruto de 32 bytes com uma chave privada secp256k1 e retorna sig + key via GET para o callback. Sem invoice, sem pagamento, sem nó Lightning.

Quando usar

  • Um site exibe "Entrar com Lightning" / LNURL-auth.
  • Você recebe uma string lnurl1... (de um QR code, um link ou texto colado).
  • Você NÃO deve gastar dinheiro ou executar um nó Lightning.

Comando

Execute com Node (já instalado). O script está em:

<skill_dir>/lnurl_auth.js
node <skill_dir>/lnurl_auth.js --lnurl <lnurl1...> [opções]
# ou passe o lnurl posicionalmente:
node <skill_dir>/lnurl_auth.js <lnurl1...>

Opções

OpçãoDescrição
--lnurl <str>A string lnurl1... (ou passe posicionalmente)
--key <hex>Use esta chave privada hex como segredo mestre
--keyfile <caminho>Leia o segredo mestre (hex) de um arquivo
--keyout <caminho>Onde persistir um segredo mestre gerado (padrão ~/.config/lnurl-auth/master.key)
--generateForçar geração de um novo segredo mestre, sobrescrevendo qualquer keyfile existente
--single-keyUse uma chave de ligação global para todos os serviços (sem derivação por domínio)
--no-tOpção de compatibilidade; o callback não adiciona um parâmetro t
--action <a>Afirmar/sobrescrever ação: register, login, link ou auth
--callback <url>Sobrescrever a URL para onde a assinatura é enviada
--dry-runDecodificar, buscar k1, assinar — mas não enviar o callback
--jsonEmitir JSON legível por máquina
-v, --verboseLog detalhado
-q, --quietSuprimir logs de progresso
-h, --helpMostrar ajuda

Gerenciamento de chaves (padrão, preservação de privacidade)

  • No primeiro uso, um segredo mestre de 32 bytes é gerado e salvo em ~/.config/lnurl-auth/master.key (modo 0600).
  • Para cada serviço, uma chave de ligação é derivada deterministicamente: linkingPriv = HMAC-SHA256(master, serviceDomain).
  • Mesmo serviço → mesma chave (usuário recorrente). Serviços diferentes → chaves diferentes (privacidade — no espírito do LUD-05/LUD-13).
  • Use --single-key para uma chave de ligação global em todos os serviços.

Fluxo do protocolo (LUD-04)

  1. lnurl1... é bech32("lnurl", utf8(serviceURL)). Decodificar -> URL contendo k1 (desafio hex de 32 bytes) e opcionalmente action.
  2. Assine o k1 bruto de 32 bytes com a chave privada de ligação usando ECDSA (secp256k1, prehash: false), em seguida codifique em DER a assinatura.
  3. Faça GET para a URL do serviço com &sig=<hex assinatura DER>&key=<hex chave pública compactada> anexado, preservando os parâmetros de consulta existentes.
  4. O servidor verifica a assinatura e responde {"status":"OK"} ou {"status":"ERROR","reason":"..."}.

Referência: https://github.com/lnurl/luds/blob/luds/04.md

Saída

  • Mensagens de progresso vão para stderr.
  • Resposta do servidor (JSON) vai para stdout.
  • {"status":"OK"} → código de saída 0.
  • {"status":"ERROR",...} → código de saída 3.
  • Resposta não JSON ou não 200 → código de saída 4.

Exemplos

Login básico

node <skill_dir>/lnurl_auth.js --lnurl "lnurl1dp68gurn8ghj7..."

Dry-run primeiro (inspecionar sem enviar)

node <skill_dir>/lnurl_auth.js "lnurl1..." --dry-run --json

Usar uma chave específica

node <skill_dir>/lnurl_auth.js "lnurl1..." --key <64-caracteres-hex-chave-privada>

Forçar nova identidade

node <skill_dir>/lnurl_auth.js "lnurl1..." --generate

Dependências

  • Node.js v20.19+ (v22 recomendado).
  • Dois pequenos pacotes npm em JS puro, vendidos dentro de node_modules/:
    • @noble/secp256k1 (assinar/verificar, pequeno, zero dependências)
    • bech32 (decodificar/codificar lnurl)
  • Sem compilação nativa; chamadas de rede são limitadas ao GET opcional do desafio e ao GET final do callback.
  • Sem custo, sem nó Lightning.

Instalando / atualizando dependências vendidas

cd <skill_dir>
npm install

Autoteste (sem serviços externos, sem custo)

Um servidor LUD-04 mockado local valida o ciclo completo de assinar → enviar → verificar:

cd <skill_dir>
npm test

Cobre: caminho feliz, rejeição de replay, segurança do dry-run, rejeição de k1 adulterado, estabilidade de chave por domínio, sobrescrita com --generate e validação de hex ímpar.

Verificação no mundo real

Verificado em dois serviços públicos:

ServiçoResposta
bitsimp.com{"status":"OK"}
lightninglogin.live{"status":"OK"}

Limitações

  • Isso realiza o handshake criptográfico; a criação de conta/login depende de o serviço remoto reconhecer a chave.
  • A chave de ligação padrão é derivada por domínio de um segredo mestre local — ela não é a mesma identidade que a carteira de um usuário produziria. Suficiente para autenticação de agente.
  • Requer saída de rede para o GET opcional do desafio e o GET final do callback (sem pagamento, sem nó Lightning).

Habilidades Relacionadas