NIP-05
Mapping Nostr keys to DNS-based internet identifiers
final optional
On events of kind 0 (user 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, the <local-part> part MUST
only use characters a-z0-9-_..
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:
{
"pubkey": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9",
"kind": 0,
"content": "{\"name\": \"bob\", \"nip05\": \"bob@example.com\"}"
// other fields...
}
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 recommended "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 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.
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
Identification, not verification
The NIP-05 is not intended to verify a user, but only
to identify them, for the purpose of facilitating the
exchange of a contact or their search.
Exceptions are people who own (e.g., a company) or are connected
(e.g., a project) to a well-known domain, who can exploit NIP-05
as an attestation of their relationship with it, and thus to the
organization behind it, thereby gaining an element of trust.
User discovery implementation suggestion
A client can 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.
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, 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.:
$ 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.
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.