Skip to content

Auth middleware: prefer OIDC/DPoP over NIP-98 when both are present on a request #306

@melvincarvalho

Description

@melvincarvalho

Problem

Browser extensions that inject NIP-98 Authorization headers (e.g. Podkey) break Solid-OIDC flows when they overwrite headers on already-authenticated requests.

Observed flow on solid.social:

  1. User signs in via Solid-OIDC as WebID https://test.solid.social/profile/card.jsonld#me
  2. Pilot (or any OIDC client) makes an authenticated request — session cookie + DPoP token present
  3. Podkey intercepts and adds an Authorization: Nostr ... header signed with a random Nostr key it holds
  4. JSS's auth middleware sees the NIP-98 header first, resolves to did:nostr:<podkey-random-key>
  5. ACL grants access to the WebID, not to the random Nostr key → 403 Forbidden

The user is authenticated as the pod owner, but the server reads a different identity and denies writes to their own profile.

Proposed fix

When a request carries multiple credentials, prefer the one associated with the active session over ambient injected headers. Concretely:

  • If a valid Solid-OIDC session cookie + DPoP proof are present → resolve identity from OIDC
  • Only fall back to NIP-98 Bearer when OIDC is not present

This mirrors how browsers resolve identity for mixed auth layers (cookies + Authorization): the active session takes precedence.

Impact

Without this, any browser extension that auto-signs with NIP-98 effectively breaks Solid-OIDC on JSS pods. Users can't edit their own profiles while the extension is enabled.

Workaround

Disable the injecting extension (or use incognito). Not viable long-term — users shouldn't have to disable Nostr extensions to use their Solid pod.

Reference

Debugged on solid.social with JSS v0.0.149 and pilot. Disabling Podkey fully (all sites) fixed the PUT; toggling it off on one site kept the interception active and preserved the 403.

Metadata

Metadata

Assignees

No one assigned

    Labels

    nostrNostr relay, did:nostr auth, NIP-related

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions