author: akumaigorodski
Authorization with Bitcoin Wallet
A speciallinkingKey can be used to login user to a service or authorise sensitive actions. This preferably should be done without compromising user identity, so plain LN node key can not be used here. Instead of asking for user credentials, a service could display a “login” QR code which contains a specialized LNURL.
Server-side generation of auth URL and signature verification:
When creating anLNURL-auth handler LN SERVICE must include in it a k1 query parameter consisting of randomly generated 32 bytes of data as well as optional action enum, an example is https://site.com?tag=login&k1=hex(32 bytes of random data)&action=login.
Later, once LN SERVICE receives a call at the specified LNURL-auth handler, it MUST take k1, compressed (33-byte) secp256k1 public key encoded as hex, and a DER-hex-encoded ECDSA sig and verify the signature using secp256k1. Once signature is successfully verified a user provided key can be used as an identifier and may be stored in a session, database or however LN SERVICE sees fit.
LN SERVICE must make sure that unexpected k1s are not accepted: it is strongly advised for LN SERVICE to have a cache of unused k1s, only proceed with verification of k1s present in that cache and remove used k1s on successful auth attempts.
Server-side choice of subdomain:
LN SERVICE should carefully choose which subdomain (if any) will be used as LNURL-auth endpoint and stick to chosen subdomain in future. For example, if auth.site.com was initially chosen then changing it to, say, login.site.com will result in a different account for each user because the full domain name is used by wallets as material for key derivation.
LN SERVICE should consider giving meaningful names to chosen subdomains since LN WALLET may show a full domain name to users on login attempt. For example, auth.site.com is less confusing than ksf03.site.com.
Wallet to service interaction flow:
-
LN WALLETscans a QR code and decodes an URL which is expected to have the following query parameters:tagwith value set tologinwhich means no GET should be made yet.k1(hex encoded 32 bytes of challenge) which is going to be signed by user’slinkingPrivKey.- optional
actionenum which can be one of four strings:register | login | link | auth.
-
LN WALLETdisplays a “Login” dialog which must include a domain name extracted fromLNURLquery string andactionenum translated into human readable text ifactionquery parameter was present. -
Once accepted by user,
LN WALLETsignsk1onsecp256k1usinglinkingPrivKeyand DER-encodes the signature.LN WALLETThen issues a GET toLN SERVICEusing<LNURL_hostname_and_path>?<LNURL_existing_query_parameters>&sig=<hex(sign(hexToBytes(k1), linkingPrivKey))>&key=<hex(linkingKey)> -
LN SERVICEresponds with the following JSON once client signature is verified:or
action enums meaning:
register: service will create a new account linked to user’slinkingKey.login: service will login user to an existing account linked to user’slinkingKey.linkservice will link a user providedlinkingKeyto user’s existing account (if account was not originally created usinglnurl-auth).auth: some stateless action which does not require logging in (or possibly even prior registration) will be granted.
linkingKey derivation
LNURL-auth works by deriving domain-specific linkingKeys from user seed. This approach has two goals: first one is simplicity (user only needs to keep mnemonic to preserve both funds and identity), second one is portability (user should be able to switch a wallet by entering the same mnemonic and get the same identity).
However, the second goal is not reachable in practice because there exist different formats of seeds which can’t be transferred across all existing wallets. As such, a practical approach is to have recommended ways to derive linkingKey for different wallet types.