Adding a Legacy Identity Provider
To build a more connected web, Zapf encourages developers to integrate new Legacy Identity Providers (LIDPs) into the network.
Whether you want to add GitHub, Slack, Telegram, or a custom enterprise authentication system, the process follows a standardized pattern.
Understanding the Role
When you add a LIDP, you are essentially teaching an Identity Authority (IA) how to verify ownership of that specific platform and how to construct the standardized Nostr events (Kind 35521 and Kind 35522) that prove it.
The Integration Pattern
If you are developing a new LIDP integration for the official open-source Zapf backend (or your own custom IA), you must implement these four steps:
1. The Verification Flow (OAuth or OTP)
You need to write the logic that securely proves the user owns the identifier.
For OAuth Providers (e.g., GitHub, Google, LinkedIn):
- Register an OAuth application with the provider to get a Client ID and Secret.
- Implement the standard OAuth 2.0 authorization code flow.
- Ensure you request the minimum necessary scopes (usually just
read:useroremail). - Fetch the user's canonical identifier (e.g., their numeric GitHub ID or primary email).
For OTP Providers (e.g., SMS, Custom App Push):
- Integrate a reliable delivery mechanism (like Twilio, SendGrid, or Firebase).
- Implement rate limiting (CRITICAL) to prevent abuse.
- Generate and verify short-lived numeric codes.
2. Identifier Normalization
Before signing any attestations, the IA must rigidly normalize the identifier to prevent spoofing.
- Emails must be lowercased and stripped of aliases (e.g.,
user+spam@gmail.com->user@gmail.com). - Phone numbers must be in E.164 format (e.g.,
+1234567890). - Social handles should ignore casing if the platform is case-insensitive.
3. ConnectionKey Generation
Generate the d tag (ConnectionKey) for the Nostr events:
// Example logic
rawString := fmt.Sprintf("%s:%s", lidpName, normalizedIdentifier)
connectionKey := sha256(rawString)
Note: Even if you intend to publish the raw identifier in the content field for searchability (the Public Privacy Model), the d tag must strictly be this SHA-256 hash.
4. Constructing the Evidence Payload (OAuth Only)
If your LIDP uses OAuth, you must construct an evidence object containing the Access Token and provider metadata. This is necessary for Evidence Sharing.
NIP-44 encrypt this payload directed at the user's pubkey.
5. Signing and Publishing
Finally, your IA code must construct the Kind 35522 (IA Attestation):
- Set
dto the generated ConnectionKey. - Set
pto the user's Nostr pubkey. - Set
lidpto your provider string (e.g.,"github"). - Specify the
expirationbased on the OAuth token expiry or a sensible default for OTP.
Sign the event with the IA's private key and publish it to the designated Nostr relays. Return the raw JSON to the user's frontend client so they can construct their Kind 35521 connection.