You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
Frontend (src/idp/views.js): when calling loginWithSchnorr(), include the form's username value in the POST body.
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).
The IdP login page (
/idp/interaction/:uid) already has a Sign in with Schnorr button wired up viahandleSchnorrLogin— it askswindow.nostr.signEvent()for a NIP-98 event and POSTs to/idp/interaction/:uid/schnorr-login. After Schnorr signature verification, it callsfindByWebId(identity)whereidentityis whateververifyNostrAuth()returned.Today this only works if the user has published a
did:nostr:DID document with bidirectionalalsoKnownAsto 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:
src/idp/views.js): when callingloginWithSchnorr(), include the form's username value in the POST body.src/idp/interactions.js handleSchnorrLogin): after Schnorr signature verification, iffindByWebId(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 CIDverificationMethodreferenced fromauthenticationin that user's WebID profile. Reuses the samefindNostrVmInProfilehelper 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
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).