Symptom
When a user signs in to their own JSS pod via NIP-98 (did:nostr-based SSO) and then tries to write, they get 401 Unauthorized. SSO appears to succeed (UI shows logged-in state), but writes fail.
Server-side log:
```
DID resolution error for : fetch failed
```
WAC then denies the write because JSS cannot resolve the requesting did:nostr to the WebID that the ACL grants access to.
Cause
src/auth/did-nostr.js has:
```js
const DEFAULT_DID_RESOLVER = 'https://nostr.social/.well-known/did/nostr';
```
The resolver always fetches the DID document from the external nostr.social endpoint, even when the user is signing in to a JSS instance that hosts that user's pod and therefore already has the authoritative DID document for them locally (served by src/idp/well-known-did-nostr.js).
When the external endpoint is unavailable — currently true for nostr.social (SSL certificate expired at time of writing) — DID resolution fails entirely, and the most common SSO case (user signed into their own pod) breaks.
Verified behaviour
Local endpoint serves the correct DID doc:
```
$ curl -sS https:///.well-known/did/nostr/
HTTP/1.1 200 OK
content-type: application/did+json
{
"id": "did:nostr:",
"alsoKnownAs": ["https:///profile/card.jsonld#me"],
"verificationMethod": [...],
"authentication": [...]
}
```
External endpoint fails:
```
$ curl -sS https://nostr.social/.well-known/did/nostr/
curl: (60) SSL certificate problem: certificate has expired
```
Fix
src/auth/did-nostr.js should:
- Try the local well-known endpoint first when the pod hosts the relevant pubkey (i.e. the pubkey index built by
src/idp/well-known-did-nostr.js contains the pubkey). This is also what the well-known-did-nostr.js doc-comment describes: "making the pod its own authoritative DID resolver for its accounts."
- Fall back to external resolvers (
nostr.social, nostr.rocks, etc.) only when the pubkey is not local.
- Optional: surface the resolver source in the error message (
local-miss, external-fetch-failed, etc.) for easier diagnosis.
Benefits
- Eliminates the most common 401 failure — user signed into their own pod auths cleanly even when external resolvers are down
- Removes external dependency for the local case — most pod-auth traffic no longer hits the public internet
- Faster — no external round-trip on every NIP-98 auth check
- Aligned with the existing architecture —
well-known-did-nostr.js is already in place; this just makes the resolver use it locally before reaching out
References
Symptom
When a user signs in to their own JSS pod via NIP-98 (
did:nostr-based SSO) and then tries to write, they get 401 Unauthorized. SSO appears to succeed (UI shows logged-in state), but writes fail.Server-side log:
```
DID resolution error for : fetch failed
```
WAC then denies the write because JSS cannot resolve the requesting
did:nostrto the WebID that the ACL grants access to.Cause
src/auth/did-nostr.jshas:```js
const DEFAULT_DID_RESOLVER = 'https://nostr.social/.well-known/did/nostr';
```
The resolver always fetches the DID document from the external
nostr.socialendpoint, even when the user is signing in to a JSS instance that hosts that user's pod and therefore already has the authoritative DID document for them locally (served bysrc/idp/well-known-did-nostr.js).When the external endpoint is unavailable — currently true for
nostr.social(SSL certificate expired at time of writing) — DID resolution fails entirely, and the most common SSO case (user signed into their own pod) breaks.Verified behaviour
Local endpoint serves the correct DID doc:
```
$ curl -sS https:///.well-known/did/nostr/
HTTP/1.1 200 OK
content-type: application/did+json
{
"id": "did:nostr:",
"alsoKnownAs": ["https:///profile/card.jsonld#me"],
"verificationMethod": [...],
"authentication": [...]
}
```
External endpoint fails:
```
$ curl -sS https://nostr.social/.well-known/did/nostr/
curl: (60) SSL certificate problem: certificate has expired
```
Fix
src/auth/did-nostr.jsshould:src/idp/well-known-did-nostr.jscontains the pubkey). This is also what thewell-known-did-nostr.jsdoc-comment describes: "making the pod its own authoritative DID resolver for its accounts."nostr.social,nostr.rocks, etc.) only when the pubkey is not local.local-miss,external-fetch-failed, etc.) for easier diagnosis.Benefits
well-known-did-nostr.jsis already in place; this just makes the resolver use it locally before reaching outReferences
src/auth/did-nostr.js— current external-first resolversrc/idp/well-known-did-nostr.js— local DID-doc publisher and pubkey index (in-memory, 5-min TTL)