heyh0e on Nostr: NIP-42 #NIP > Authentication of clients to relays > ...
NIP-42
#NIP
> Authentication of clients to relays
> https://github.com/nostr-protocol/nips/blob/master/42.md
クライアントからリレーに対する認証
[有料リレー]を実現する仕様です
ざっくりと
認証は[署名]を使って行います
チャレンジ/レスポンス認証のような動きをします
流れ
クライアントはリレーから「チャレンジ」文字列をもらい、チャレンジを含むイベントを作って署名をし、リレーに送ります
リレーは署名されたイベントが届いたら、正しい署名かどうかを検証します
署名が正しければ、リレーはユーザの公開鍵を元に有料会員かどうかや許可リストに載っているかどうかを判断します
検証が成功したら、そのあとはクライアントは色々な操作を行えるようになります
失敗したときはエラーがクライアントに返ります
認証によってWebSocketに接続しているのが本人であることが保証されます
動機
制限されたリソースにアクセスするクライアントに対し、リレーは認証を求めたいかもしれない
イベントの投稿を支払いを求めるか、他の形による許可リストによって許可制にしたい
単に許可リスト内にあるキーで署名されたイベントのみに投稿を制限することで
チャットのやり取りをしている人々だけにダイレクトメッセージ(kind 4)の利用を制限したい
クライアントがDMをクエリするときに認証を必要とする
リレーは購読を有料会員や許可リストに載っているユーザだけに制限したい
新しく`AUTH`メッセージを定義する
リレーから送信されるAUTHメッセージ
`["AUTH", <challenge-string>]`
クライアントから送信されるAUTHメッセージ
`["AUTH", <signed-event-json>]`
→ 署名されたイベント
[署名]されたイベント(Signed event)
一時的なイベントであり、投稿や問い合わせには使われない
[イベントの種類 (kind)] は `22242` でなければならない
リレーは、kind 22242のイベントをいかなるクライアントに対してもブロードキャストしてはならない(MUST)
code:_.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/ でサインアップしてください"]`
[署名されたイベントの検証 https://github.com/nostr-protocol/nips/blob/master/42.md#signed-event-verification]
`AUTH`メッセージの検証では、リレーは次のことを確認しなければならない:
`kind`が`22242`であること
イベントの`created_at`が最近の時刻であること(例えば10分以内)
`"challenge"`タグが送信したチャレンジと一致すること
`"relay"`タグがリレーのURLに一致すること
URL正規化の手法を適用してもよい
多くの場合はドメイン名が正しいかどうかを確認するだけで十分である
#NIP
> Authentication of clients to relays
> https://github.com/nostr-protocol/nips/blob/master/42.md
クライアントからリレーに対する認証
[有料リレー]を実現する仕様です
ざっくりと
認証は[署名]を使って行います
チャレンジ/レスポンス認証のような動きをします
流れ
クライアントはリレーから「チャレンジ」文字列をもらい、チャレンジを含むイベントを作って署名をし、リレーに送ります
リレーは署名されたイベントが届いたら、正しい署名かどうかを検証します
署名が正しければ、リレーはユーザの公開鍵を元に有料会員かどうかや許可リストに載っているかどうかを判断します
検証が成功したら、そのあとはクライアントは色々な操作を行えるようになります
失敗したときはエラーがクライアントに返ります
認証によってWebSocketに接続しているのが本人であることが保証されます
動機
制限されたリソースにアクセスするクライアントに対し、リレーは認証を求めたいかもしれない
イベントの投稿を支払いを求めるか、他の形による許可リストによって許可制にしたい
単に許可リスト内にあるキーで署名されたイベントのみに投稿を制限することで
チャットのやり取りをしている人々だけにダイレクトメッセージ(kind 4)の利用を制限したい
クライアントがDMをクエリするときに認証を必要とする
リレーは購読を有料会員や許可リストに載っているユーザだけに制限したい
新しく`AUTH`メッセージを定義する
リレーから送信されるAUTHメッセージ
`["AUTH", <challenge-string>]`
クライアントから送信されるAUTHメッセージ
`["AUTH", <signed-event-json>]`
→ 署名されたイベント
[署名]されたイベント(Signed event)
一時的なイベントであり、投稿や問い合わせには使われない
[イベントの種類 (kind)] は `22242` でなければならない
リレーは、kind 22242のイベントをいかなるクライアントに対してもブロードキャストしてはならない(MUST)
code:_.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/ でサインアップしてください"]`
[署名されたイベントの検証 https://github.com/nostr-protocol/nips/blob/master/42.md#signed-event-verification]
`AUTH`メッセージの検証では、リレーは次のことを確認しなければならない:
`kind`が`22242`であること
イベントの`created_at`が最近の時刻であること(例えば10分以内)
`"challenge"`タグが送信したチャレンジと一致すること
`"relay"`タグがリレーのURLに一致すること
URL正規化の手法を適用してもよい
多くの場合はドメイン名が正しいかどうかを確認するだけで十分である