-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Labels
enhancementNew feature or requestNew feature or request
Description
Overview
Currently, Podkey provides NIP-07 window.nostr API for websites to manually create and sign NIP-98 auth events, but it does not automatically intercept HTTP requests to add NIP-98 Authorization headers. This issue tracks the implementation of automatic NIP-98 authentication for Solid servers and other Nostr-authenticated HTTP endpoints.
Current State
- ✅ Extension has
webRequestpermission inmanifest.json - ✅ Extension can sign NIP-98 events (kind 27235) via
window.nostr.signEvent() - ✅ Auto-sign functionality exists for trusted origins
- ❌ No automatic HTTP request interception
- ❌ No automatic 401 response detection and retry
- ❌ No automatic Authorization header injection
NIP-98 Specification Reference
Specification: https://github.com/nostr-protocol/nips/blob/master/98.md
Event Structure
{
"kind": 27235,
"content": "",
"tags": [
["u", "https://example.com/api/resource?query=value"],
["method", "GET"]
],
"created_at": 1682327852
}Authorization Header Format
Authorization: Nostr <base64-encoded-signed-event>
For Requests with Body (POST, PUT, etc.)
Include a payload tag with SHA-256 hash of the request body.
Implementation Requirements
1. HTTP Request Interception
Location: src/background.js
- Use
chrome.webRequest.onBeforeSendHeadersto intercept outgoing requests - Filter requests to origins that are trusted or are known Solid servers
- Only intercept requests to origins that have been trusted or are known Solid servers
- Don't intercept requests that already have an
Authorizationheader (unless it's a retry) - Cache signed auth events per request URL+method to avoid re-signing identical requests
2. 401 Response Detection and Retry
Location: src/background.js
- Use
chrome.webRequest.onHeadersReceivedto detect 401 responses - When 401 is detected:
- Check if origin is trusted
- Create NIP-98 auth event for the failed request
- Sign the event using existing
signEvent()function - Retry the original request with
Authorization: Nostr <base64-event>header
Retry Logic:
- Only retry on 401 Unauthorized responses
- Consider 403 Forbidden if it's auth-related (optional, may need user preference)
- Do NOT retry on other 4xx errors (404, 400, etc.) - these are not auth issues
- Limit retry attempts (max 1 retry per request to avoid loops)
- Track retry state to prevent infinite loops
3. NIP-98 Event Creation
Location: src/background.js (new function)
async function createNip98AuthEvent(requestDetails) {
const event = {
kind: 27235,
content: '',
created_at: Math.floor(Date.now() / 1000),
tags: [
['u', requestDetails.url],
['method', requestDetails.method]
]
};
// If request has body, add payload tag
if (requestDetails.requestBody) {
const bodyHash = await hashRequestBody(requestDetails.requestBody);
event.tags.push(['payload', bodyHash]);
}
return event;
}4. Request Body Hashing
- For requests with body (POST, PUT, PATCH), compute SHA-256 hash
- Use existing
@noble/hasheslibrary - Handle different body formats: FormData, ArrayBuffer, Blob, string
5. Base64 Encoding
- Encode signed event JSON to base64
- Format:
Authorization: Nostr <base64-string>
6. User Preferences
- Add setting: "Auto-authenticate HTTP requests" (separate from event auto-sign)
- Add setting: "Retry on 403 Forbidden" (optional, default false)
- Respect existing
getAutoSign()preference
Code Structure
WebRequest Listeners
// Intercept outgoing requests
chrome.webRequest.onBeforeSendHeaders.addListener(
interceptRequest,
{
urls: ['<all_urls>'],
types: ['xmlhttprequest', 'main_frame', 'sub_frame']
},
['requestHeaders', 'blocking']
);
// Detect 401 responses
chrome.webRequest.onHeadersReceived.addListener(
handle401Response,
{
urls: ['<all_urls>'],
types: ['xmlhttprequest', 'main_frame', 'sub_frame']
},
['responseHeaders']
);Edge Cases
- Request Body Handling: Different formats (FormData, Blob, ArrayBuffer, string)
- URL Normalization: Ensure
utag matches exactly what server expects - Timing:
created_atshould be recent (within 60 seconds typically) - Caching: Cache signed events per (URL, method, bodyHash) tuple
- Security: Only auto-auth for trusted origins
- Performance: Minimize blocking operations
- Error Handling: Handle signing failures gracefully
Acceptance Criteria
- Extension automatically adds NIP-98 Authorization header to requests from trusted origins
- Extension detects 401 responses and retries with NIP-98 auth
- NIP-98 events are correctly formatted per specification
- Request bodies are hashed and included in
payloadtag when present - Only 401 (and optionally 403) responses trigger retry
- User preferences (auto-sign, trusted origins) are respected
- No infinite retry loops
- Works with GET, POST, PUT, DELETE, PATCH methods
- Handles various request body formats correctly
- Unit tests pass
- Integration tests pass
References
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request