P2P SAML Identity Provider using PeerPigeon WebDHT and UnSEA
A decentralized identity provider (IdP) solution that works in browsers using PeerPigeon's WebDHT for storage and UnSEA for cryptographic operations. Built for integration with PigeonHub and supports custom namespaces.
Built with PeerPigeon 1.0.6 - Latest stable release with improved WebRTC mesh networking and DHT performance.
- 🔐 Decentralized Authentication - No central authority required
- 🌐 Browser-First - Works natively in modern browsers
- 🔑 UnSEA Cryptography - Uses UnSEA for signing, encryption, and key management
- 💾 WebDHT Storage - Distributed hash table for identity storage
- 🏷️ Custom Namespaces - Support for namespace-specific authentication
- 🤝 PigeonHub Integration - Designed to work with PigeonHub servers
- 📦 NPM Module - Easy to import and use in any project
- 🔒 Secure Key Storage - Password-encrypted key storage in IndexedDB
- ✅ JWT-like Tokens - Generate and verify authentication tokens
- 🏢 SAML 2.0 Support - Full SAML IdP for enterprise SSO (Salesforce, AWS, Google, etc.)
- 🚀 Deploy to Fly.io - One-command deployment with automated CI/CD
npm install pigeonidpimport { PigeonIdP } from 'pigeonidp';
// Create an IdP instance with custom namespace
const idp = new PigeonIdP({
namespace: 'my-app-namespace',
signalingServers: ['wss://pigeonhub.fli.dev']
});
// Initialize the IdP
await idp.init();
// Create a new identity
const keys = await idp.createIdentity('alice', 'secure-password');
// Sign a message
const signature = await idp.sign('Hello World');
// Generate an authentication token
const token = await idp.generateAuthToken({
username: 'alice',
role: 'user'
}, 3600); // expires in 1 hour
// Verify the token
const verification = await idp.verifyAuthToken(token);
console.log('Token valid:', verification.valid);
// Disconnect when done
await idp.disconnect();<!DOCTYPE html>
<html>
<head>
<title>PigeonIdP Demo</title>
</head>
<body>
<script type="module">
import { PigeonIdP } from './node_modules/pigeonidp/index.js';
const idp = new PigeonIdP({
namespace: 'my-namespace'
});
await idp.init();
await idp.createIdentity('user1', 'password123');
const token = await idp.generateAuthToken({ user: 'user1' });
console.log('Token:', token);
</script>
</body>
</html>See examples/browser-example.html for a full interactive demo.
Note on Password Storage: The password parameter for createIdentity() enables encrypted key storage using IndexedDB, which is only available in browsers. In Node.js environments, omit the password parameter or keys will not be persisted. For server-side key persistence, implement your own storage solution using the exportKeys() and importKeys() methods.
PigeonIdP includes full SAML 2.0 support for enterprise Single Sign-On integration.
import { PigeonIdP } from 'pigeonidp';
import { PigeonIdPSAML } from 'pigeonidp/saml';
const idp = new PigeonIdP({ namespace: 'my-org' });
await idp.init();
await idp.createIdentity('admin');
// Add SAML support
const saml = new PigeonIdPSAML(idp, {
entityId: 'https://myidp.example.com',
ssoUrl: 'https://myidp.example.com/saml/sso',
organizationName: 'My Organization'
});
// Generate SAML assertion for user
const user = {
id: 'alice@company.com',
username: 'alice',
attributes: {
email: 'alice@company.com',
roles: ['admin']
}
};
const assertion = await saml.generateAssertion(
user,
'https://sp.example.com/acs',
'https://sp.example.com'
);# Deploy to Fly.io (no prompts)
npm run deploy
# Your IdP will be available at:
# https://your-app-name.fly.dev
# SAML Metadata URL:
# https://your-app-name.fly.dev/saml/metadataNote: Replace your-app-name with your chosen app name during deployment. The default name is pigeonidp, but you should use a unique name for your deployment (e.g., mycompany-idp).
- ✅ Salesforce
- ✅ Google Workspace
- ✅ AWS IAM
- ✅ Azure AD
- ✅ Okta
- ✅ OneLogin
- ✅ Most enterprise SaaS applications
See SAML.md for complete guide including:
- SAML configuration
- Service provider setup
- Attribute mapping
- Testing and troubleshooting
- Security best practices
Deploy PigeonIdP as a server with REST API and SAML endpoints.
# One-command deployment (no prompts)
npm run deploy
# Or use the deployment script
./deploy.shYour server will be available at: https://your-app-name.fly.dev
Important: Before deploying, edit fly.toml and change the app name from pigeonidp to a unique name for your deployment (e.g., mycompany-idp, acme-idp). The app name must be globally unique across all Fly.io applications.
Replace your-app-name with your actual Fly.io app name:
GET /health- Health checkGET /api/info- Server informationGET /api/identity/:alias- Lookup identity from DHTPOST /api/verify- Verify a signaturePOST /api/verify-token- Verify auth tokenGET /saml/metadata- SAML IdP metadataGET /saml/sso- SAML Single Sign-OnPOST /saml/sso- SAML authentication
Automatic deployment on push to main:
- Get Fly.io token:
flyctl auth token - Add to GitHub secrets as
FLY_API_TOKEN - Push to main branch = auto-deploy
See DEPLOYMENT.md for detailed deployment guide.
new PigeonIdP(options)Options:
namespace(string, default: 'default') - Custom namespace for the IdPsignalingServers(array, default: ['wss://pigeonhub.fli.dev']) - Signaling servers for WebRTC (uses PeerPigeon 1.0.6)meshOptions(object) - Additional options for PeerPigeonMesh
Initialize the IdP with mesh network and WebDHT.
await idp.init();Create a new identity with cryptographic keypair.
const keys = await idp.createIdentity('alice', 'secure-password');Parameters:
alias(string) - Alias for the identitypassword(string, optional) - Password for encrypted storage
Returns: Keypair object with pub, priv, epub, epriv
Load an existing identity from encrypted storage.
const keys = await idp.loadIdentity('alice', 'secure-password');Sign a message or authentication token.
const signature = await idp.sign('Hello World');Verify a signed message.
const isValid = await idp.verify('Hello World', signature, publicKey);Encrypt a message for a recipient.
const encrypted = await idp.encrypt('Secret message', recipientKeys);Decrypt a message.
const decrypted = await idp.decrypt(encrypted);Generate an authentication token (JWT-like).
const token = await idp.generateAuthToken({
username: 'alice',
role: 'user'
}, 3600); // expires in 1 hourParameters:
claims(object) - Claims to include in the tokenexpiresIn(number, default: 3600) - Expiration time in seconds
Returns: Token object with claims and signature
Verify an authentication token.
const result = await idp.verifyAuthToken(token);
if (result.valid) {
console.log('User:', result.claims.username);
}Returns: Object with valid (boolean), claims (if valid), or error (if invalid)
Register an identity in the DHT for discovery.
await idp.registerIdentity({
username: 'alice',
displayName: 'Alice Wonderland',
email: 'alice@example.com'
});Lookup an identity from the DHT.
const identity = await idp.lookupIdentity(publicKey);
console.log('Profile:', identity.profile);Authenticate with a PigeonHub namespace.
const result = await idp.authenticateWithHub('my-hub', {
username: 'alice'
});
console.log('Auth token:', result.token);Export keys to JWK format.
const jwkKeys = await idp.exportKeys();Import keys from JWK format.
await idp.importKeys(jwkKeys);Clear stored identity.
await idp.clearIdentity('alice');Get current identity public keys.
const pubKeys = idp.getPublicKeys();
// Returns { pub, epub }Disconnect from the mesh network.
await idp.disconnect();See examples/basic-usage.js for a comprehensive example covering:
- Creating and loading identities
- Signing and verifying messages
- Generating and verifying tokens
- DHT registration and lookup
- Encryption and decryption
Run with:
node examples/basic-usage.jsSee examples/pigeonhub-integration.js for:
- Namespace-specific authentication
- Cross-user discovery
- Encrypted messaging between users
- Multiple namespace support
Run with:
node examples/pigeonhub-integration.jsSee examples/browser-example.html for an interactive browser demo with UI controls.
PigeonIdP is built on three key technologies:
- PeerPigeon (v1.0.4) - Provides WebRTC mesh networking and WebDHT for distributed storage
- UnSEA - Cryptographic toolkit for key generation, signing, encryption (using WebCrypto and noble-curves)
- WebDHT - Distributed hash table for storing and discovering identities
User Identity
↓
UnSEA (Key Generation)
↓
Local Storage (Encrypted with Password)
↓
WebDHT (Public Keys & Profiles)
↓
PeerPigeon Mesh (P2P Network)
PigeonIdP is designed to integrate seamlessly with PigeonHub:
-
Namespace Isolation - Each PigeonHub server can have its own namespace
-
Authentication Flow:
- User creates/loads identity in IdP
- IdP generates authentication request
- Request is stored in DHT under the hub's namespace
- Hub server verifies and processes authentication
- Token is issued for authenticated sessions
-
Discovery - Users can discover other users in the same namespace through DHT lookups
- 🔐 Private keys are encrypted with user passwords before storage
- 🔑 Uses P-256 ECDSA for signatures and ECDH for encryption
- 🛡️ AES-GCM for message encryption
- ⏰ Tokens include expiration timestamps
- ✅ All identity data in DHT is cryptographically signed
- 🔒 Constant-time operations for sensitive comparisons
peerpigeon(^1.0.4) - Includes:- UnSEA for cryptography
- WebDHT for distributed storage
- PigeonRTC for WebRTC support
- ✅ Chrome/Edge (88+)
- ✅ Firefox (78+)
- ✅ Safari (14+)
- ✅ Opera (74+)
Requires WebRTC and WebCrypto API support.
- Node.js 16.0.0 or higher
- Uses native WebCrypto API (crypto.webcrypto)
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
For issues and questions:
- GitHub Issues: https://github.com/PeerPigeon/PigeonIdP/issues
- PeerPigeon Docs: https://github.com/PeerPigeon/PeerPigeon
- PeerPigeon - WebRTC mesh networking library
- UnSEA - Cryptographic toolkit
- PigeonHub - P2P hub server (planned integration)
PigeonIdP is part of the PeerPigeon ecosystem.