8.4 KiB
NIP-39
External Identities in Profiles
draft
optional
Abstract
Nostr protocol users may have other online identities such as usernames, profile pages, keypairs etc. they control and they may want to include this data in their profile metadata so clients can parse, validate and display this information.
i
tag on a metadata event
A new optional i
tag is introduced for kind 0
metadata event contents in addition to name, about, picture fields as included in NIP-01:
{
"kind": 0,
"tags": [
["i", "github:semisol", "9721ce4ee4fceb91c9711ca2a6c9a5ab"],
["i", "twitter:semisol_public", "1619358434134196225"],
["i", "mastodon:bitcoinhackers.org/@semisol", "109775066355589974"],
["i", "telegram:1087295469", "nostrdirectory/770"],
["i", "openpgp4fpr:1A04E0F1A78D982BD8885B7EB325A9C5F70849D0", "LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0did012TXdDVzJXWFhsMGU4Y25oY1lUeTlJWWtpVGw0bHpxbFFvemt6UHk4eExWeWpKeUN4V3lFMHRMazVNClQxWHdWRWpPejB2TExNb0ZDaWVXUUxnbFJmazVRRzZxUWtGUlpsbGlTYXBDZG1xbFFscCtFVmpNTDcrNHBFaWgKb0RRcEp6TVpMSkVIWkJ1V3A1a1VsS1lWbHlhbkZwbVdKVnFrV3hZWUZHV1pwdVJsbEtXbFpwaWxXSlFicEp1bApKbFltcGhhWXBtUVVGSnNWRmFjWG14aW5wR2RZY25XVXNqQ0ljVEhJaWlteVNMRTgrTGk4ZDRiMmpZN29PcGdQCldKbEF6bWZnNGhTQWlTU0pNVExjL2E3YmRtZUx3S0dMZWs2NkRTcDYvNmRmMzl6Nk5pN1E1dmcxLytCU0NRY1oKUm9ZOUwvN2NhWW05WnRZN2FkNm1GMy95ak83OVZqbWhZZmF4bm1mNlFaYldDM0lNQUE9PQo9ZXkyagotLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tCg", "LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgptRE1FWmdIZE94WUpLd1lCQkFIYVJ3OEJBUWRBNnBaZ2RzbUR2aVJGNDVDYys5TUJiK3VkUURZZ2ZHRjZrQkJVCk1CeUd4S2EwRjJaeVlXNTZZWEFnUEY5QVpuSmhibnBoY0M1amIyMCtpSk1FRXhZS0FEc1dJUVFhQk9EeHA0MlkKSzlpSVczNnpKYW5GOXdoSjBBVUNaZ0hkT3dJYkF3VUxDUWdIQWdJaUFnWVZDZ2tJQ3dJRUZnSURBUUllQndJWApnQUFLQ1JDekphbkY5d2hKMEw5R0FRQ3VFUFF0aW9EdGlKaWNVSGw4S0RqU0dmRU1laEFWdjZsTGJuZDBTRjN6Ci9BRCtQZWJCcFk3YkwvakY4QnViaU8rVm9nbUhsa2NGZ3h5V2ZEMDYwMDAwb0FvPQo9OWRBUAotLS0tLUVORCBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCg"]
],
// ...
}
An i
tag will have two parameters and an optional third parameter, which are defined as the following:
type:identity
: This is the platform name (for examplegithub
) or the linked cryptographic identity type (for exampleopenpgp4fpr
), and the identity on that platform (for examplesemisol
) or public key fingerprint (for example1A04E0F1A78D982BD8885B7EB325A9C5F70849D0
) joined together with:
.proof
: String that points to the proof of owning this identity or is the proof itself (crytographic signature).- The full public key in the case of a cryptographic identity.
Clients SHOULD process any i
tags with more than 3 values for future extensibility.
Identity provider names SHOULD only include a-z
, 0-9
and the characters ._-/
and MUST NOT include :
.
Identity names SHOULD be normalized if possible by replacing uppercase letters with lowercase letters, and if there are multiple aliases for an entity the primary one should be used.
Revocation
The event MAY be updated by removing i
tags that no longer apply.
Claim types
github
Identity: A GitHub username.
Proof: A GitHub Gist ID. This Gist should be created by <identity>
with a single file that has the text Verifying that I control the following Nostr public key: <npub encoded public key>
.
This can be located at https://gist.github.com/<identity>/<proof>
.
twitter
Identity: A Twitter username.
Proof: A Tweet ID. The tweet should be posted by <identity>
and have the text Verifying my account on nostr My Public Key: "<npub encoded public key>"
.
This can be located at https://twitter.com/<identity>/status/<proof>
.
mastodon
Identity: A Mastodon instance and username in the format <instance>/@<username>
.
Proof: A Mastodon post ID. This post should be published by <username>@<instance>
and have the text Verifying that I control the following Nostr public key: "<npub encoded public key>"
.
This can be located at https://<identity>/<proof>
.
telegram
Identity: A Telegram user ID.
Proof: A string in the format <ref>/<id>
which points to a message published in the public channel or group with name <ref>
and message ID <id>
. This message should be sent by user ID <identity>
and have the text Verifying that I control the following Nostr public key: "<npub encoded public key>"
.
This can be located at https://t.me/<proof>
.
openpgp4fpr
Identity: An OpenPGP fingerprint as described in the openpgp4fpr URI scheme, lowercased.
Proof: A signature of the text Verifying that I control the following Nostr public key: "<npub encoded public key>"
in base64 format, unwrapped.
Public key material: The full OpenPGP public key (including BEGIN
/END
PEM markers) in base64 format, unwrapped.
Example
{
"kind": 0,
"tags": [
["i", "openpgp4fpr:1a04e0f1a78d982bd8885b7eb325a9c5f70849d0", "LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0did012TXdDVzJXWFhsMGU4Y25oY1lUeTlJWWtpVGw0bHpxbFFvemt6UHk4eExWeWpKeUN4V3lFMHRMazVNClQxWHdWRWpPejB2TExNb0ZDaWVXUUxnbFJmazVRRzZxUWtGUlpsbGlTYXBDZG1xbFFscCtFVmpNTDcrNHBFaWgKb0RRcEp6TVpMSkVIWkJ1V3A1a1VsS1lWbHlhbkZwbVdKVnFrV3hZWUZHV1pwdVJsbEtXbFpwaWxXSlFicEp1bApKbFltcGhhWXBtUVVGSnNWRmFjWG14aW5wR2RZY25XVXNqQ0ljVEhJaWlteVNMRTgrTGk4ZDRiMmpZN29PcGdQCldKbEF6bWZnNGhTQWlTU0pNVExjL2E3YmRtZUx3S0dMZWs2NkRTcDYvNmRmMzl6Nk5pN1E1dmcxLytCU0NRY1oKUm9ZOUwvN2NhWW05WnRZN2FkNm1GMy95ak83OVZqbWhZZmF4bm1mNlFaYldDM0lNQUE9PQo9ZXkyagotLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tCg", "LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCgptRE1FWmdIZE94WUpLd1lCQkFIYVJ3OEJBUWRBNnBaZ2RzbUR2aVJGNDVDYys5TUJiK3VkUURZZ2ZHRjZrQkJVCk1CeUd4S2EwRjJaeVlXNTZZWEFnUEY5QVpuSmhibnBoY0M1amIyMCtpSk1FRXhZS0FEc1dJUVFhQk9EeHA0MlkKSzlpSVczNnpKYW5GOXdoSjBBVUNaZ0hkT3dJYkF3VUxDUWdIQWdJaUFnWVZDZ2tJQ3dJRUZnSURBUUllQndJWApnQUFLQ1JDekphbkY5d2hKMEw5R0FRQ3VFUFF0aW9EdGlKaWNVSGw4S0RqU0dmRU1laEFWdjZsTGJuZDBTRjN6Ci9BRCtQZWJCcFk3YkwvakY4QnViaU8rVm9nbUhsa2NGZ3h5V2ZEMDYwMDAwb0FvPQo9OWRBUAotLS0tLUVORCBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tCg"],
// ...
],
// ...
}
Example command to obtain a signature:
echo 'Verifying that I control the following Nostr public key: "<npub encoded public key>"' | gpg --sign --armor | base64
Example command to export the public key:
gpg --armor --export name@example.com | base64
x509
Identity: The X.509 certificate's SHA-256 fingerprint, lowercased.
Proof: A signature of the text Verifying that I control the following Nostr public key: "<npub encoded public key>"
in base64 format, unwrapped.
Public key material: The full public key (including BEGIN
/END
PEM markers) of the certificate in base64 format, unwrapped.
Example
{
"kind": 0,
"tags": [
["i", "x509:3220c353a73cfbd0c2f3052471c445324cf452bcba26de1c473a52fe5c44e1d6", "DRhQobBXnYFijFjJFZNWiAstqDv+8OACMQIzh+KKw0XS1PW869alYSW4erTUx8xlymlpMoC9et5+kLcfkOXf9jF2UVv5R1JCEGwD5L3/04OtT97h9CftPy1pvuYV6mhja3Ccv2RKGg7Hk99VlpQtFjtgbmCTxaXONGNhYbR/EL6aCEvKfyuuYyodtWTyo1Ys/R6eF7dqFPrDQ/rQ5W14Jmfxhvgn0SW83WqFy/d1A6AQqrku1ZWcHqk41Xaj72A5VmYY5bIe5NTTPTFVz6WhHkx452iZ9w6YlEz2PGzYlUAwq0arpXsD8BJrfBrTj9t+PMRvTV+Sw50Hgu4Ajl9waw==", "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF0cDczdXhiZGdkK3ZKNTZPWGM3dwpWZHQ2aDlwL282cDNBMDNub2ErR2F3TVpSMUVpbi8wMnZlaU54dHZqM3V3emFxazJRTFEwUkRlMnNiMnVHZ0RFCitEc1RONEdOb1JRVndGQUJramp3VlpIa0lnc1c3Q3o3dFBCTW5aRjBRT3Ixa1NwR09wL0crUDJUUHFvS0o4cXQKU0xnZzBQdW5CbHRxeEhtWFlPQXVicWlHaDRmdEt3UmFpQWh0MFQxOFJiZnNvY21XR1RwclYzS1BsalNxMWxveQpjSEx3QnROT3ZQdVhsMzl4cXExek1xTmFaTXpBbFdGeU12dmllMmU3ZWJFakdjY3pLSy9jWER0RzFNb1lIV0RvCndiQWdtemhWa2JFakJRREVPUWdGWmtiTURXRUpUemZlRVJNUzU5TU1PaTVrbTBHejVaalhRWHlhSTNFN1FadlgKUVFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="],
// ...
],
// ...
}
Example command to find the SHA-256 fingerprint of the certificate from a keystore:
keytool -list -keystore example.keystore
Example commands to extract the private key and sign the message:
keytool -importkeystore -srckeystore example.keystore -destkeystore example.p12 -deststoretype pkcs12
openssl pkcs12 -in example.p12 -nocerts -nodes -out privatekey.pem
echo 'Verifying that I control the following Nostr public key: "<npub encoded public key>"' | openssl dgst -sha256 -sign privatekey.pem | openssl base64 -A
Example commands to extract the public key:
openssl rsa -in privatekey.pem -pubout | base64
// or
openssl ec -in privatekey.pem -pubout | base64