generated at
NIP-42

> Authentication of clients to relays

クライアントからリレーに対する認証

有料リレーを実現する仕様です

ざっくりと
認証は署名を使って行います
チャレンジ/レスポンス認証のような動きをします
流れ
クライアントはリレーから「チャレンジ」文字列をもらい、チャレンジを含むイベントを作って署名をし、リレーに送ります
リレーは署名されたイベントが届いたら、正しい署名かどうかを検証します
署名が正しければ、リレーはユーザの公開鍵を元に有料会員かどうかや許可リストに載っているかどうかを判断します
検証が成功したら、そのあとはクライアントは色々な操作を行えるようになります
失敗したときはエラーがクライアントに返ります
認証によってWebSocketに接続しているのが本人であることが保証されます

動機
制限されたリソースにアクセスするクライアントに対し、リレーは認証を求めたいかもしれない
イベントの投稿を支払いを求めるか、他の形による許可リストによって許可制にしたい
単に許可リスト内にあるキーで署名されたイベントのみに投稿を制限することで
チャットのやり取りをしている人々だけにダイレクトメッセージ(kind 4)の利用を制限したい
クライアントがDMをクエリするときに認証を必要とする
リレーは購読を有料会員や許可リストに載っているユーザだけに制限したい

新しく AUTH メッセージを定義する
リレーから送信されるAUTHメッセージ
["AUTH", <challenge-string>]
クライアントから送信されるAUTHメッセージ
["AUTH", <signed-event-json>]
→ 署名されたイベント

署名されたイベント(Signed event)
一時的なイベントであり、投稿や問い合わせには使われない
イベントの種類 (kind) 22242 でなければならない
リレーは、kind 22242のイベントをいかなるクライアントに対してもブロードキャストしてはならない(MUST)
_.json
{ "id": "...", "pubkey": "...", "created_at": 1669695536, "kind": 22242, "tags": [ ["relay", "wss://relay.example.com/"], ["challenge", "challengestringhere"] ], "content": "", "sig": "..." }

通信の流れ
リレーはいつでも、「チャレンジ」を含む AUTH メッセージをクライアントに送信してよい
クライアントはチャレンジを受信したら認証自体を行うかどうかを決めてよい
チャレンジは接続の間、あるいはリレーから次のチャレンジが送られるまでは有効と見做されることが期待される
クライアントは認証が必要だと知っている操作を行う直前に AUTH メッセージを送ってよい――例えば、 kind: 4 のチャットメッセージをリクエストする直前に――あるいは接続の開始時や最も良いタイミングで
認証はWebSocket接続が切れるまで続くことが期待される
認証済みでないユーザからメッセージを受信し、認証なしでは続行できない場合は、リレーはクライアントに通知できる
NOTICE または OK メッセージを利用する
人間と機械の両方が読める restricted: という標準のプレフィックス(接頭辞)を含める
NOTICE
["NOTICE", "restricted: 認証していないユーザにはDMを提供していません。お使いのクライアントはNIP-42に対応していますか?"]
OK
["OK", <event-id>, false, "restricted: 認証していないユーザからのイベントは受けつけていません。https://example.com/ でサインアップしてください"]

AUTH メッセージの検証では、リレーは次のことを確認しなければならない:
kind 22242 であること
イベントの created_at が最近の時刻であること(例えば10分以内)
"challenge" タグが送信したチャレンジと一致すること
"relay" タグがリレーのURLに一致すること
URL正規化の手法を適用してもよい
多くの場合はドメイン名が正しいかどうかを確認するだけで十分である