lnurl-auth (LUD-04)
LNURL-auth(라이트닝 '라이트닝으로 로그인')을 사용하여 서비스에 인증합니다.
전적으로 클라이언트 측에서 처리됩니다. 이 도구는 인증 전용입니다: 서버가 k1 챌린지를 보내면, 사용자는 secp256k1 개인키로 원시 32바이트 k1에 서명하고 sig + key를 콜백 URL에 GET 파라미터로 전송합니다. 인보이스, 결제, 라이트닝 노드가 필요하지 않습니다.
사용 시점
- 사이트에 '라이트닝으로 로그인' / LNURL-auth가 표시될 때.
lnurl1...문자열(QR 코드, 링크, 또는 텍스트 붙여넣기)을 전달받았을 때.- 비용을 지출하거나 라이트닝 노드를 실행하면 안 되는 경우.
명령어
Node(이미 설치됨)로 실행합니다. 스크립트는 다음 위치에 있습니다:
<skill_dir>/lnurl_auth.js
node <skill_dir>/lnurl_auth.js --lnurl <lnurl1...> [옵션]
# 또는 lnurl을 위치 인자로 전달:
node <skill_dir>/lnurl_auth.js <lnurl1...>
옵션
| 옵션 | 설명 |
|---|---|
--lnurl <str> | lnurl1... 문자열 (또는 위치 인자로 전달) |
--key <hex> | 이 16진수 개인키를 마스터 시크릿으로 사용 |
--keyfile <path> | 파일에서 마스터 시크릿(16진수) 읽기 |
--keyout <path> | 생성된 마스터 시크릿을 저장할 위치 (기본값 ~/.config/lnurl-auth/master.key) |
--generate | 새 마스터 시크릿을 강제 생성, 기존 키파일을 덮어씀 |
--single-key | 모든 서비스에 하나의 전역 링킹 키 사용 (도메인별 파생 없음) |
--no-t | 호환성 옵션; 콜백에 t 파라미터를 추가하지 않음 |
--action <a> | action 강제 지정: register, login, link, 또는 auth |
--callback <url> | 서명을 제출할 URL 재정의 |
--dry-run | 디코딩, k1 가져오기, 서명 — 하지만 콜백을 보내지 않음 |
--json | 기계가 읽을 수 있는 JSON 출력 |
-v, --verbose | 상세 로깅 |
-q, --quiet | 진행 로그 억제 |
-h, --help | 도움말 표시 |
키 관리 (기본값, 프라이버시 보호)
- 처음 사용 시 32바이트 마스터 시크릿이 생성되어
~/.config/lnurl-auth/master.key에 저장됩니다 (모드0600). - 각 서비스에 대해 링킹 키가 결정론적으로 파생됩니다:
linkingPriv = HMAC-SHA256(master, serviceDomain). - 같은 서비스 → 같은 키 (재방문 사용자). 다른 서비스 → 다른 키 (프라이버시 — LUD-05/LUD-13 정신).
- 모든 서비스에 단일 전역 링킹 키를 사용하려면
--single-key를 사용하세요.
프로토콜 흐름 (LUD-04)
lnurl1...은bech32("lnurl", utf8(serviceURL))입니다. 디코딩 →k1(32바이트 16진수 챌린지)과 선택적으로action을 포함하는 URL이 생성됩니다.- ECDSA(secp256k1,
prehash: false)를 사용하여 링킹 개인키로 원시 32바이트k1에 서명한 다음, 서명을 DER 인코딩합니다. - 기존 쿼리 파라미터를 유지하면서
&sig=<16진수 DER 서명>&key=<16진수 압축 공개키>를 추가하여 서비스 URL에 GET 요청을 보냅니다. - 서버가 서명을 확인하고
{"status":"OK"}또는{"status":"ERROR","reason":"..."}로 응답합니다.
참고: https://github.com/lnurl/luds/blob/luds/04.md
출력
- 진행 메시지는 stderr로 전송됩니다.
- 서버 응답(JSON)은 stdout으로 전송됩니다.
{"status":"OK"}→ 종료 코드0.{"status":"ERROR",...}→ 종료 코드3.- JSON이 아니거나 200이 아닌 응답 → 종료 코드
4.
예제
기본 로그인
node <skill_dir>/lnurl_auth.js --lnurl "lnurl1dp68gurn8ghj7..."
드라이 런 먼저 (제출하지 않고 검사)
node <skill_dir>/lnurl_auth.js "lnurl1..." --dry-run --json
특정 키 사용
node <skill_dir>/lnurl_auth.js "lnurl1..." --key <64-char-hex-private-key>
새 신원 강제 생성
node <skill_dir>/lnurl_auth.js "lnurl1..." --generate
의존성
- Node.js v20.19+ (v22 권장).
- 두 개의 작은 순수 JS npm 패키지가
node_modules/내부에 vendor되어 있습니다:@noble/secp256k1(서명/검증, 작고, 의존성 없음)bech32(lnurl 디코딩/인코딩)
- 네이티브 빌드 없음; 네트워크 호출은 선택적인 챌린지 GET과 최종 콜백 GET으로 제한됩니다.
- 비용 없음, 라이트닝 노드 없음.
Vendor 의존성 설치/갱신
cd <skill_dir>
npm install
자체 테스트 (외부 서비스 없음, 비용 없음)
로컬 모의 LUD-04 서버가 전체 서명 → 제출 → 검증 왕복을 검증합니다:
cd <skill_dir>
npm test
다음 항목을 포함합니다: 정상 경로, 재전송 거부, 드라이 런 안전성, 변조된 k1 거부, 도메인별 키 안정성, --generate 덮어쓰기, 홀수 16진수 유효성 검사.
실제 검증
두 개의 공개 서비스에서 검증되었습니다:
| 서비스 | 응답 |
|---|---|
| bitsimp.com | {"status":"OK"} |
| lightninglogin.live | {"status":"OK"} |
제한 사항
- 이 도구는 암호학적 핸드셰이크를 수행합니다. 계정 생성/로그인은 원격 서비스가 키를 인식하는지에 따라 달라집니다.
- 기본 링킹 키는 로컬 마스터 시크릿에서 도메인별로 파생됩니다. 사용자의 휴대폰 지갑이 생성하는 동일한 신원이 아닙니다. 에이전트 인증에는 충분합니다.
- 선택적인 챌린지 GET 및 최종 콜백 GET을 위해 네트워크 아웃바운드가 필요합니다 (결제 또는 라이트닝 노드 없음).