> ## Documentation Index
> Fetch the complete documentation index at: https://lnurl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# LUD-04: auth base spec.

> Display inline code and code blocks

`author: akumaigorodski`

## Authorization with Bitcoin Wallet

A special `linkingKey` 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 an `LNURL-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 `k1`s are not accepted: it is strongly advised for `LN SERVICE` to have a cache of unused `k1`s, only proceed with verification of `k1`s present in that cache and remove used `k1`s 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:

1. `LN WALLET` scans a QR code and decodes an URL which is expected to have the following query parameters:
   * `tag` with value set to `login` which means no GET should be made yet.
   * `k1` (hex encoded 32 bytes of challenge) which is going to be signed by user's `linkingPrivKey`.
   * optional `action` enum which can be one of four strings: `register | login | link | auth`.
2. `LN WALLET` displays a "Login" dialog which must include a domain name extracted from `LNURL` query string and `action` enum translated into human readable text if `action` query parameter was present.
3. Once accepted by user, `LN WALLET` signs `k1` on `secp256k1` using `linkingPrivKey` and DER-encodes the signature. `LN WALLET` Then issues a GET to `LN SERVICE` using `<LNURL_hostname_and_path>?<LNURL_existing_query_parameters>&sig=<hex(sign(hexToBytes(k1), linkingPrivKey))>&key=<hex(linkingKey)>`
4. `LN SERVICE` responds with the following JSON once client signature is verified:

   ```JSON theme={null}
   {"status": "OK"}
   ```

   or

   ```JSON theme={null}
   {"status": "ERROR", "reason": "error details..."}
   ```

`action` enums meaning:

* `register`: service will create a new account linked to user's `linkingKey`.
* `login`: service will login user to an existing account linked to user's `linkingKey`.
* `link` service will link a user provided `linkingKey` to user's existing account (if account was not originally created using `lnurl-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 `linkingKey`s 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.

## Signature check examples

In Python

```Python theme={null}
from binascii import unhexlify
from secp256k1 import PublicKey

k1 = unhexlify('e2af6254a8df433264fa23f67eb8188635d15ce883e8fc020989d5f82ae6f11e')
key = unhexlify('02c3b844b8104f0c1b15c507774c9ba7fc609f58f343b9b149122e944dd20c9362')
sig = unhexlify('304402203767faf494f110b139293d9bab3c50e07b3bf33c463d4aa767256cd09132dc5102205821f8efacdb5c595b92ada255876d9201e126e2f31a140d44561cc1f7e9e43d')

pubkey = PublicKey(key, raw=True)
sig_raw = pubkey.ecdsa_deserialize(sig)
r = pubkey.ecdsa_verify(k1, sig_raw, raw=True)

assert r == True
```
