# NIP42

## 客户端到中继的身份验证

`draft` `optional` `author:Semisol` `author:fiatjaf`

该 NIP 为客户端定义了一种通过签署临时事件来对中继进行身份验证的方法。

## 动机

中继可能需要客户端进行身份验证才能访问受限资源。例如，

* 中继可以请求付费或其他形式的白名单来发布事件--这可以通过将发布限制为由白名单密钥签名的事件来实现，但使用此 NIP，他们可以选择接受任何事件，只要它们是由经过身份验证的用户发布的。
* 中继可以将对 `kind: 4` DMS 的访问仅限于聊天交换中所涉及的各方，并且为此，它可能需要在客户端可以查询该类型之前进行身份验证。
* 中继可以将任何类型的订阅限制为付费用户或通过任何其他方式列入白名单的用户，并要求进行身份验证。

## 定义

该 NIP 定义了一条新消息， `AUTH` 中继在支持身份验证时可以发送该消息，而客户端在需要进行身份验证时可以向中继发送该消息。当通过中继发送时，消息具有以下形式：

```
["AUTH", <challenge-string>]
```

并且，当由客户发送时，采用以下形式：

```
["AUTH", <signed-event-json>]
```

签名事件是一个临时事件，并不意味着要发布或查询，它必须是的， `kind: 22242` 并且应该至少有两个标记，一个用于中继 URL，一个用于从中继接收的质询字符串。中继必须禁止 `kind: 22242` 将事件广播到任何客户端。 `created_at` 应该是当前时间。示例：

```json
{
  "id": "...",
  "pubkey": "...",
  "created_at": 1669695536,
  "kind": 22242,
  "tags": [
    ["relay", "wss://relay.example.com/"],
    ["challenge", "challengestringhere"]
  ],
  "content": "",
  "sig": "..."
}
```

## 协议流

在任何时刻，中继可以向客户端发送 `AUTH` 包含质询的消息。在接收到该消息之后，客户端可以决定是否对自己进行认证。预期该质询在连接期间有效，或者直到中继发送下一个质询为止。

客户机可以在执行一个它知道需要身份验证的动作之前（例如，在请求 `kind: 4` 聊天消息之前）发送一个 AUTH 消息，或者它可以在连接开始时或在它认为最好的其他某个时刻发送 AUTH 消息。身份验证预计将在 WebSocket 连接期间持续。

在接收到来自未经身份验证的用户的消息时，如果没有身份验证，它就无法完成，中继可以选择通知客户端。为此，它可以使用 `NOTICE` 带有标准前缀的 OR `OK` 消息 `"restricted: "`，该标准前缀可由人类和机器读取，例如：

```
["NOTICE", "restricted: we can't serve DMs to unauthenticated users, does your client implement NIP-42?"]
```

或者，它可以返回一条 `OK` 消息，指出未使用相同的前缀写入事件的原因：

```
["OK", <event-id>, false, "restricted: we do not accept events from unauthenticated users, please sign up at https://example.com/"]
```

## 签名事件验证

要验证 `AUTH` 消息，中继必须确保：

* `kind` 即是 `22242`；
* 事件 `created_at` 与当前时间接近（例如，在约 10 分钟内）；
* `"challenge"` 标签与之前发送的挑战相匹配；
* `"relay"` 标记与中继 URL 匹配： - 可以应用 URL 规范化技术。在大多数情况下，只要检查域名是否正确就足够了。
