A browser extension that enables zero-redirect authentication to Solid servers using Nostr cryptographic keys (NIP-98).
✨ Zero OAuth Redirects - Authenticate instantly without leaving the page 🔑 Uses Existing Nostr Keys - Works with nos2x, Alby, and other NIP-07 providers 🎯 did:nostr Identity - Proper 64-char hex format for DID resolution 🛡️ Secure by Design - Never touches your private keys, NIP-07 only 🌈 Beautiful UI - Soft gradients and light theme ⚡ Auto-Sign - Optional automatic signing for trusted sites
- Intercepts 401 responses from Solid servers
- Prompts for trust on first visit to a domain
- Signs HTTP auth events using your Nostr provider (nos2x, Alby, etc.)
- Retries with Authorization header - seamless access!
Request → 401 → IdP Redirect → Login → Auth Code → Token Exchange → Access
Request → 401 → Sign Event → Access ✨
You must have a NIP-07 Nostr provider installed:
- nos2x (Chrome)
- Alby (Chrome/Firefox)
- nostr-keyx (Chrome)
-
Clone this repository:
git clone https://github.com/JavaScriptSolidServer/nostr-solid-auth.git cd nostr-solid-auth -
Open Chrome and navigate to
chrome://extensions/ -
Enable Developer mode (toggle in top right)
-
Click Load unpacked
-
Select the
nostr-solid-authdirectory -
The extension icon should appear in your toolbar! 🎉
-
Clone the repository (same as above)
-
Navigate to
about:debugging#/runtime/this-firefox -
Click Load Temporary Add-on
-
Select the
manifest.jsonfile
- Install a Nostr provider extension (nos2x, Alby, etc.)
- Visit a Solid server with protected resources
- The extension will prompt you to trust the origin
- Click "OK" - your Nostr provider will sign the auth event
- Access granted! ✨
Click the extension icon to:
- View your Nostr public key (64-char hex)
- See your did:nostr identity
- Toggle auto-sign for trusted sites
- Manage trusted origins (add/remove)
The extension implements NIP-98 HTTP Auth:
{
"kind": 27235, // HTTP Auth event
"created_at": 1704451200,
"tags": [
["u", "https://example.com/resource"], // Full URL
["method", "GET"] // HTTP method
],
"content": ""
}Authorization header format:
Authorization: Nostr <base64-encoded-signed-event>
Public keys are validated as 64-character hexadecimal strings:
// Valid
const pubkey = "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d";
const did = `did:nostr:${pubkey}`;
// did:nostr:3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d- ✅ Private keys never exposed - uses NIP-07 window.nostr API only
- ✅ Replay prevention - events expire in 60 seconds
- ✅ Method binding - HTTP method must match signed event
- ✅ URL binding - Request URL must match event 'u' tag
- ✅ User consent - explicit trust per origin
- ✅ Revocable - remove trusted sites anytime
Your Solid server must support NIP-98 authentication. See the server implementation in JavaScriptSolidServer.
Example server-side validation:
// Extract and decode Authorization header
const authHeader = request.headers.authorization;
if (authHeader?.startsWith('Nostr ')) {
const eventBase64 = authHeader.substring(6);
const event = JSON.parse(atob(eventBase64));
// Validate event
// 1. Verify signature
// 2. Check kind === 27235
// 3. Match URL and method
// 4. Check timestamp (< 60 seconds old)
// 5. Verify pubkey is 64-char hex
// Resolve identity
const did = `did:nostr:${event.pubkey}`;
// Map to WebID via did:nostr resolver
}┌─────────────────────────────────────────────────┐
│ Browser Tab │
│ ┌───────────────────────────────────────────┐ │
│ │ Content Script (content.js) │ │
│ │ - Detects 401 responses │ │
│ │ - Shows trust prompts │ │
│ │ - Calls window.nostr.signEvent() │ │
│ │ - Generates Authorization headers │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────┐
│ Background Service Worker (background.js) │
│ - Intercepts webRequest events │
│ - Manages trusted origins storage │
│ - Validates 64-char hex pubkeys │
│ - Coordinates auth flow │
└─────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────┐
│ NIP-07 Provider (nos2x, Alby, etc.) │
│ - Stores private keys securely │
│ - Signs events via window.nostr.signEvent() │
│ - Returns 64-char hex pubkey │
└─────────────────────────────────────────────────┘
nostr-solid-auth/
├── manifest.json # Extension manifest (MV3)
├── background.js # Service worker (401 detection)
├── content.js # Content script (NIP-07 bridge)
├── popup.html # Popup UI
├── popup.js # Popup logic
├── icons/ # Extension icons
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
└── README.md
- Load the extension in Chrome
- Install nos2x or Alby
- Visit a Solid server with protected resources
- Open DevTools Console to see logs:
[Nostr-Solid Auth] Extension installed [Nostr-Solid Auth] Detected 401 response: https://... [Nostr-Solid Auth] Auth required for: https://...
The extension validates all public keys to ensure proper did:nostr format:
function isValidNostrPubkey(pubkey) {
if (typeof pubkey !== 'string') return false;
if (pubkey.length !== 64) return false;
return /^[0-9a-fA-F]{64}$/.test(pubkey);
}- Manifest V3 extension structure
- 401 detection via webRequest
- NIP-07 integration
- Trust prompt UI
- 64-char hex validation
- Popup UI with soft light theme
- Declarative net request for header injection
- Better error messages
- Status notifications
- POST/PUT support
- Submit NIP-98 proposal
- Firefox port
- Server implementation guide
- Test suite
- Multi-key support
- Key rotation handling
- Advanced DID resolution
- Mobile support via deep links
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT
Built with 💜 for the Solid and Nostr ecosystems.
Part of the JavaScriptSolidServer project.