Skip to content

idp: "Sign in with Schnorr" resolves user via typed username + CID verificationMethod #403

Description

@melvincarvalho

The IdP login page (/idp/interaction/:uid) already has a Sign in with Schnorr button wired up via handleSchnorrLogin — it asks window.nostr.signEvent() for a NIP-98 event and POSTs to /idp/interaction/:uid/schnorr-login. After Schnorr signature verification, it calls findByWebId(identity) where identity is whatever verifyNostrAuth() returned.

Today this only works if the user has published a did:nostr: DID document with bidirectional alsoKnownAs to their WebID — that's the existing resolver path. The new VM-lookup path (#400) needs a resource owner to derive the WebID, and the IdP login URL has no pod owner.

Result: the button is currently inert for users who've added their Nostr key to their profile via the doctor's B.2 (the path #400 was specifically designed to enable for resource auth).

Proposed fix

The login form already has a Username field. Use it:

  1. Frontend (src/idp/views.js): when calling loginWithSchnorr(), include the form's username value in the POST body.
  2. Backend (src/idp/interactions.js handleSchnorrLogin): after Schnorr signature verification, if findByWebId(identity) returns nothing AND a username was provided, look up the account by username and check whether the verified Nostr pubkey is declared as a CID verificationMethod referenced from authentication in that user's WebID profile. Reuses the same findNostrVmInProfile helper auth: NIP-98 → WebID via verificationMethod lookup (#399) #400 added.

Why this is safe

The Nostr signature is verified BEFORE the username lookup. The username only resolves which account/profile to check the pubkey against. If the typed username's profile doesn't contain the pubkey, login fails — typing someone else's username doesn't grant access.

Acceptance

  • User adds their Nostr Multikey VM to their WebID profile (via doctor B.2 paste, manual edit, or future B.4 PATCH path)
  • User clicks "Sign in with Schnorr" with their username typed in the form
  • xlogin signs a NIP-98 event; server verifies and matches against the typed user's profile
  • OIDC interaction completes, user returns to the OAuth client signed in as the WebID
  • Without the VM in profile → 403 with a clear message
  • Without a username typed → falls back to the existing DID-doc resolver path

Refs #4 (overall Schnorr auth tracker, Phase 2A), #386 (Phase 4 cross-protocol unification), #400 (resource-side VM lookup, this is the IdP-side parallel).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestnostrNostr relay, did:nostr auth, NIP-related

    Type

    No type

    Fields

    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