Identity Connection (Kind 35521)
A Kind 35521 is a verifiable Nostr event published by an end-user to announce that their Nostr public key is linked to a Legacy Identity Provider (LIDP) account, such as a Discord or X account.
Crucially, because an end-user could lie about owning an account, Kind 35521 alone is insufficient. It must encapsulate cryptographic proof signed by a trusted third party—an Identity Authority (IA).
Event Structure
{
"kind": 35521,
"pubkey": "<user_pubkey>",
"created_at": "<unix_timestamp>",
"tags": [
["d", "<lidp_name>:<connection_key>"],
["s", "<attestation_event_id>", "<attestation_json>", "<ia_relay_url>"],
["lidp", "<lidp_name>"]
],
"content": "<public_or_encrypted_profile>",
"id": "...",
"sig": "..."
}
Required Tags
| Tag | Format | Description |
|---|---|---|
d | ["d", "<lidp_name>:<connection_key>"] | Compound key for parameterized replaceable uniqueness (e.g., discord:a1b2c3...). |
lidp | ["lidp", "<lidp_name>"] | The name of the Legacy Identity Provider (e.g., discord, x) for quick relay filtering. |
s | ["s", "<attestation_event_id>", "<attestation_json>", "<ia_relay_url>"] | The embedded Kind 35522 evidence event signed by the IA. See below. |
The s Tag and Multi-IA Stacking
The s tag is the heart of this protocol's identity model.
- Index 1: The event ID of the IA's Kind 35522 Attestation.
- Index 2: The full, stringified JSON of the Kind 35522 Attestation.
- Index 3: A relay hint where clients can fetch the original Kind 35522 for an online Deep Check.
Stacking: A user can include multiple s tags in their Kind 35521 event. If a user proves their Discord account to three different IAs, they can embed all three attestations. This means a client only needs to trust one of those IAs to verify the connection.
Content Privacy Modes
By default, the d tag only broadcasts a deterministic hash of the user's identity.
The content field contains the user's profile metadata (passed down from the IA, such as Display Name, Avatar, Bio), not the raw identifier handle (like @username or email@example.com). Its visibility—chosen by the user—dictates how this metadata is exposed:
| Mode | Content Field Data | Resulting Network Behavior |
|---|---|---|
| Public | Unencrypted JSON (e.g., {"name": "Elon", "picture": "..."}) | Profile metadata is globally readable on the Nostr network. |
| Private | NIP-44 self-encrypted (readable only by the user's own pubkey) | Profile metadata is entirely hidden. The user can still read it from their local client. |
| Empty | No content exposed. | Functions identically to Private mode, but without storing an encrypted backup of the profile. |
Security & Spoofing
Because Kind 35521 is a user-signed event, a user could theoretically place malicious or spoofed data into the content field (e.g., claiming their display name is "Elon Musk" when it is not).
This does not affect the protocol:
- Routing ignores content: The backend strictly routes payments based on the cryptographic hash in the
dtag. A user cannot spoof the payment destination by changing their event content. - Verification catches spoofing: The embedded
"s"tag contains the unforgeable Kind 35522 Attestation signed by the IA. Clients must cross-reference the user'scontentclaims against the IA's verified payload. If they do not match, the client UI should flag the connection as spoofed.