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ção | Descriçã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) |
--generate | Forçar geração de um novo segredo mestre, sobrescrevendo qualquer keyfile existente |
--single-key | Use uma chave de ligação global para todos os serviços (sem derivação por domínio) |
--no-t | Opçã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-run | Decodificar, buscar k1, assinar — mas não enviar o callback |
--json | Emitir JSON legível por máquina |
-v, --verbose | Log detalhado |
-q, --quiet | Suprimir logs de progresso |
-h, --help | Mostrar 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(modo0600). - 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-keypara uma chave de ligação global em todos os serviços.
Fluxo do protocolo (LUD-04)
lnurl1...ébech32("lnurl", utf8(serviceURL)). Decodificar -> URL contendok1(desafio hex de 32 bytes) e opcionalmenteaction.- Assine o
k1bruto de 32 bytes com a chave privada de ligação usando ECDSA (secp256k1,prehash: false), em seguida codifique em DER a assinatura. - 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. - 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ída0.{"status":"ERROR",...}→ código de saída3.- 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ço | Resposta |
|---|---|
| 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).