Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 42 additions & 52 deletions 05.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,33 @@
NIP-05
======

Mapping Nostr keys to DNS-based internet identifiers
----------------------------------------------------
DNS-based identifiers
---------------------

`final` `optional`

On events of kind `0` (`user metadata`) one can specify the key `"nip05"` with an [internet identifier](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, the `<local-part>` part MUST only use characters `a-z0-9-_.`.
Users can declare their control over one of more DNS-based internet identifiers in kind `10008`.

Upon seeing that, the client splits the identifier into `<local-part>` and `<domain>` and use these values to make a GET request to `https://<domain>/.well-known/nostr.json?name=<local-part>`.

The result should be a JSON document object with a key `"names"` that should then be a mapping of names to hex formatted public keys, in lowercase. If the public key for the given `<name>` matches the `pubkey` from the `user metadata` event, the client then concludes that the given pubkey can indeed be referenced by its identifier.

### Example

If a client sees an event like this:

```jsonc
```yaml
{
"pubkey": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9",
"kind": 0,
"content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\"}"
// other fields...
"kind": 10008,
"tags": [
["n", "<name>@<domain>"],
["n", "name@domain.com"],
["n", "name2@domain2.com"],
],
"content": "",
//...
}
```

It will make a GET request to `https://example.com/.well-known/nostr.json?name=bob` and get back a response that will look like
Internet identifiers follow [RFC-5322](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) with the exception that `<name>`s MUST only use characters `a-z0-9-_.`.

```json
{
"names": {
"bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
}
}
```
Supporting Clients split the identifier into `<name>` and `<domain>` and use these values to make a GET request to `https://<domain>/.well-known/nostr.json?name=<name>`.

or with the **recommended** `"relays"` attribute:
The result MUST be a JSON document with two properties: `names` and `relays`:

```json
```yaml
{
"names": {
"bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
Expand All @@ -48,9 +38,32 @@ or with the **recommended** `"relays"` attribute:
}
```

If the pubkey matches the one given in `"names"` (as in the example above) that means the association is right and the `"nip05"` identifier is valid and can be displayed.
The property `names` MUST contain a mapping of names to hex formatted public keys, in lowercase.

The property `relays` is optional, but when present MUST contain an array of relay urls where the events from this key can be found.

A valid NIP-05 identifier MUST match the resulting public key to the pubkey of the `10008` event.

A domain MAY offer the complete `https://<domain>/.well-known/nostr.json` with all names and relay information for all users.

### Root Identifiers

Clients MUST treat the identifier `_@<domain>` as the "root" identifier and MUST display it as just the `<domain>`. For example, if Bob owns `bob.com`, he may not want an identifier like `bob@bob.com` as that is redundant. Instead, Bob can use the identifier `_@bob.com` and expect Nostr clients to show and treat that as just `bob.com` for all purposes.

### Allowing access from JavaScript apps

Servers MUST provider their `/.well-known/nostr.json` documents with the HTTP header `Access-Control-Allow-Origin: *` to ensure it can be validated by pure JS apps running in modern browsers, avoiding [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) issues.

```bash
$ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep -i ^Access-Control
Access-Control-Allow-Origin: *
```

### Security Constraints

Servers MUST offer the `/.well-known/nostr.json` endpoint without any HTTP redirects.

The recommended `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays the specific user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available.
Clients MUST ignore any HTTP redirects given by the `/.well-known/nostr.json` endpoint.

## Finding users from their NIP-05 identifier

Expand All @@ -75,29 +88,6 @@ For example, if after finding that `bob@bob.com` has the public key `abc...def`,

Keys must be returned in hex format, in lowercase. Keys in NIP-19 `npub` format are only meant to be used for display in client UIs, not in this NIP.

### Showing just the domain as an identifier

Clients may treat the identifier `_@domain` as the "root" identifier, and choose to display it as just the `<domain>`. For example, if Bob owns `bob.com`, he may not want an identifier like `bob@bob.com` as that is redundant. Instead, Bob can use the identifier `_@bob.com` and expect Nostr clients to show and treat that as just `bob.com` for all purposes.

### Reasoning for the `/.well-known/nostr.json?name=<local-part>` format

By adding the `<local-part>` as a query string instead of as part of the path, the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.

### Allowing access from JavaScript apps

JavaScript Nostr apps may be restricted by browser [CORS][] policies that prevent them from accessing `/.well-known/nostr.json` on the user's domain. When CORS prevents JS from loading a resource, the JS program sees it as a network failure identical to the resource not existing, so it is not possible for a pure-JS app to tell the user for certain that the failure was caused by a CORS issue. JS Nostr apps that see network failures requesting `/.well-known/nostr.json` files may want to recommend to users that they check the CORS policy of their servers, e.g.:

```bash
$ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep -i ^Access-Control
Access-Control-Allow-Origin: *
```

Users should ensure that their `/.well-known/nostr.json` is served with the HTTP header `Access-Control-Allow-Origin: *` to ensure it can be validated by pure JS apps running in modern browsers.

[CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

### Security Constraints

The `/.well-known/nostr.json` endpoint MUST NOT return any HTTP redirects.

Fetchers MUST ignore any HTTP redirects given by the `/.well-known/nostr.json` endpoint.
By adding the `<local-part>` as a query string instead of as part of the path, the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-02: Follow List](02.md)
- [NIP-03: OpenTimestamps Attestations for Events](03.md)
- [NIP-04: Encrypted Direct Message](04.md) --- **unrecommended**: deprecated in favor of [NIP-17](17.md)
- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md)
- [NIP-05: DNS-based identifiers](05.md)
- [NIP-06: Basic key derivation from mnemonic seed phrase](06.md)
- [NIP-07: `window.nostr` capability for web browsers](07.md)
- [NIP-08: Handling Mentions](08.md) --- **unrecommended**: deprecated in favor of [NIP-27](27.md)
Expand Down