Skip to content

Fix NIP-05 verification fetch errors#281

Open
arnavkirti wants to merge 4 commits intoshopstr-eng:mainfrom
arnavkirti:fix/nip05-fetch-errors
Open

Fix NIP-05 verification fetch errors#281
arnavkirti wants to merge 4 commits intoshopstr-eng:mainfrom
arnavkirti:fix/nip05-fetch-errors

Conversation

@arnavkirti
Copy link
Copy Markdown
Contributor

Description

Fix NIP-05 verification so the client no longer fetches external /.well-known/nostr.json endpoints directly.

Root cause

Profile verification was running in the browser and fetching external NIP-05 documents from third-party domains. Many of those domains do not send Access-Control-Allow-Origin, so browsers blocked the requests and valid verifications failed silently.

Changes

  • add a Next.js API route that performs the external NIP-05 fetch server-side with timeout handling
  • update the client-side verifier to call the internal API route instead of the third-party domain directly
  • add route-level tests covering success, malformed identifiers, and external fetch failures

Impact

NIP-05 verification now avoids client-side CORS failures for external domains while preserving the existing boolean verification flow used during profile hydration.

Resolved or fixed issue

Fixes #262

Affirmation

For more details on what to include, see:

Bug Report Template
Feature Request Template
Documentation Issue Template
Security Issue Template

Copilot AI review requested due to automatic review settings April 3, 2026 09:23
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 3, 2026

@arnavkirti is attempting to deploy a commit to the shopstr-eng Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR moves NIP-05 verification fetching from the browser to a server-side Next.js API route to avoid client-side CORS failures, while keeping the client’s boolean verification flow.

Changes:

  • Added /api/nostr/verify-nip05 to fetch and validate /.well-known/nostr.json server-side with a request timeout.
  • Updated the client verifier to call the internal API route and consume a { verified } response.
  • Added Jest tests for the new API route covering success, malformed identifiers, and external fetch failure.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
utils/nostr/nostr-helper-functions.ts Switches client-side NIP-05 verification to call the internal API route and read verified.
pages/api/nostr/verify-nip05.ts Adds a server-side verification endpoint with timeout + response parsing/matching.
pages/api/nostr/tests/verify-nip05.test.ts Adds route-level tests validating core behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@GautamBytes GautamBytes self-assigned this Apr 3, 2026
@GautamBytes
Copy link
Copy Markdown
Contributor

Please make the server-side fetch reject/ignore redirects, since NIP-05 explicitly forbids following them and it also protects the new SSRF guard.
Also, please validate the NIP-05 local-part too so only spec-valid identifiers are accepted.

@arnavkirti
Copy link
Copy Markdown
Contributor Author

@GautamBytes Please take a look, I have done the changes.

@Aryan0699
Copy link
Copy Markdown
Contributor

Aryan0699 commented Apr 6, 2026

Hi @arnavkirti ! I’ve already opened a PR for this issue earlier. Sharing here in case it helps avoid duplicate work. Happy to collaborate or adjust if your approach improves something 👍
#263

@arnavkirti
Copy link
Copy Markdown
Contributor Author

Hi @arnavkirti ! I’ve already opened a PR for this issue earlier. Sharing here in case it helps avoid duplicate work. Happy to collaborate or adjust if your approach improves something 👍 #263

I am sorry, I didn't see your PR earlier. We can collaborate on this, as your PR implements the core feature, and my PR has relevant tests for the feature. Thanks!

@GautamBytes
Copy link
Copy Markdown
Contributor

LGTM Now!!

Comment on lines +1572 to +1575
const response = await fetch(
`/api/nostr/verify-nip05?nip05=${encodeURIComponent(
nip05
)}&pubkey=${encodeURIComponent(pubkey)}`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The url is still relative , a absolute url is requied in Node
  • Can Remove @-split validation — server already handles this so no need to duplicate
  • Can add type unknown as it would be more concrete
  • no need of nested try catch all three blocks were doing the same thing , one wrapper would be fine
    I have suggested the optimum code below do give a check
export async function verifyNip05Identifier(
  nip05: string,
  pubkey: string,
  options?: { baseUrl?: string }
): Promise<boolean> {
  if (!nip05 || !pubkey) return false;

  try {
    const params = new URLSearchParams({ nip05, pubkey });
    const path = `/api/nostr/verify-nip05?${params.toString()}`;

    const baseUrl =
      options?.baseUrl ??
      (typeof window !== "undefined" ? window.location.origin : null);

    if (!baseUrl && typeof window === "undefined") {
      throw new Error("verifyNip05Identifier requires baseUrl in SSR");
    }

    const requestUrl = baseUrl
export async function verifyNip05Identifier(
  nip05: string,
  pubkey: string,
  options?: { baseUrl?: string }
): Promise<boolean> {
  if (!nip05 || !pubkey) return false;

  try {
    const params = new URLSearchParams({ nip05, pubkey });
    const path = `/api/nostr/verify-nip05?${params.toString()}`;

    const baseUrl =
      options?.baseUrl ??
      (typeof window !== "undefined" ? window.location.origin : null);

    if (!baseUrl && typeof window === "undefined") {
      throw new Error("verifyNip05Identifier requires baseUrl in SSR");
    }

    const requestUrl = baseUrl
      ? new URL(path, baseUrl).toString()
      : path;

    const response = await fetch(requestUrl);

    if (!response.ok) return false;

    const data: unknown = await response.json();

    return (
      typeof data === "object" &&
      data !== null &&
      "verified" in data &&
      (data as { verified?: boolean }).verified === true
    );
  } catch {
    return fals
      ? new URL(path, baseUrl).toString()
      : path;

    const response = await fetch(requestUrl);

    if (!response.ok) return false;

    const data: unknown = await response.json();

    return (
      typeof data === "object" &&
      data !== null &&
      "verified" in data &&
      (data as { verified?: boolean }).verified === true
    );
  } catch {
    return false;
  }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are few things that can be improved . I hope it helps 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Fix NIP-05 verification failures caused by client-side CORS policy blocks

4 participants