5.8 KiB
NIP-05
Mapping Nostr keys to DNS-based internet identifiers
final
optional
author:fiatjaf
author:mikedilger
On events of kind 0
(set_metadata
) one can specify the key "nip05"
with an internet identifier (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, NIP-05 assumes the <local-part>
part will be restricted to the characters a-z0-9-_.
, case insensitive.
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. If the public key for the given <name>
matches the pubkey
from the set_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:
{
"pubkey": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9",
"kind": 0,
"content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\"}"
...
}
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
{
"names": {
"bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
}
}
or with the optional "relays"
attribute:
{
"names": {
"bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9"
},
"relays": {
"b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ]
}
}
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 optional "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 a that 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.
Finding users from their NIP-05 identifier
A client may implement support for finding users' public keys from internet identifiers, the flow is the same as above, but reversed: first the client fetches the well-known URL and from there it gets the public key of the user, then it tries to fetch the kind 0
event for that user and check if it has a matching "nip05"
.
Notes
Clients must always follow public keys, not NIP-05 addresses
For example, if after finding that bob@bob.com
has the public key abc...def
, the user clicks a button to follow that profile, the client must keep a primary reference to abc...def
, not bob@bob.com
. If, for any reason, the address https://bob.com/.well-known/nostr.json?name=bob
starts returning the public key 1d2...e3f
at any time in the future, the client must not replace abc...def
in his list of followed profiles for the user (but it should stop displaying "bob@bob.com" for that user, as that will have become an invalid "nip05"
property).
Public keys must be in hex format
Keys must be returned in hex format. Keys in NIP-19 npub
format are are only meant to be used for display in client UIs, not in this NIP.
User Discovery implementation suggestion
A client can also use this to allow users to search other profiles. If a client has a search box or something like that, a user may be able to type "bob@example.com" there and the client would recognize that and do the proper queries to obtain a pubkey and suggest that to the user.
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.:
$ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep ^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.
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.