Skip to content

Registry auth fails on non-www redirects since node-fetch was replaced in CLI 4.11.1+ #11071

Description

@JugglerX

Describe the bug

This is not stricly a bug. But I believe its something that will effect many registries.

Registry auth fails on non-www/cross-host redirects since node-fetch was replaced with native fetch (4.11.1+)

Summary

The latest shadcn CLI 4.11.1+ switched from node-fetch to native fetch. Now shadcn add returns 401 Unauthorized for authenticated registries whose URL redirects across hosts (e.g. apex → www), even with a valid API key. Pointing the registry at the post-redirect (canonical) host works.

For example: Prior to this change our registry worked with both www and non-www urls https://www.shadcnblocks.com/r/{name} or https://shadcnblocks.com/r/{name}. After this change the non-www version no longer works.

{
  "registries": {
    "@shadcnblocks": {
      "url": "https://www.shadcnblocks.com/r/{name}",
      "headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
    }
  }
}

Root cause

When a registry URL responds with a redirect to a different host (e.g. https://example.com/r/{name}https://www.example.com/r/{name}), native fetch/undici drops the Authorization header on the cross-origin hop for security. The token never reaches the final host → 401.

node-fetch → native fetch

This changed behavior in 4.11.1 (commit 9197676, "chore: replace node-fetch", 2026-06-15), which removed node-fetch/https-proxy-agent in favor of native fetch + undici.

  • node-fetch used a lenient rule: it kept Authorization when the redirect target was the same domain or a subdomain (so apex → www preserved the header).
  • Native fetch/undici strips Authorization on any cross-origin redirect, including apex ↔ www.
CLI version fetch impl cross-host redirect w/ auth
≤ 4.11.0 node-fetch header preserved (same-domain/subdomain)
4.11.1+ / current native fetch + undici header stripped → 401

Because npx shadcn (unpinned) resolves to the latest, configs that worked before now fail after a routine upgrade — with no change on the user's side.

Reproduction

  1. Configure an authenticated registry whose URL 301/308-redirects to another host (e.g. apex → www):
{
  "registries": {
    "@shadcnblocks": {
      "url": "https://shadcnblocks.com/r/{name}",
      "headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
    }
  }
}
  1. Both npx shadcn@latest add @shadcnblocks/hero36 or npx shadcn@4.11.1 add @shadcnblocks/hero36 will fail with 401
  2. Change the URL to the redirect target host (https://www.shadcnblocks.com/r/{name}) → succeeds.

Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions

  1. make sure the url is non-www https://shadcnblocks.com/r/{name}
  2. npx shadcn@4.11.0 add @shadcnblocks/hero36 will work

Verified behavior (same cross-host 308)

Client Keeps Authorization?
node-fetch (≤ 4.11.0) ✅ kept on same-domain/subdomain
native fetch / undici (4.11.1+) ❌ stripped
curl -L ❌ stripped

Impact

  • Any registry that relies on a host-level redirect (apex → www is extremely common on Vercel/Netlify/Cloudflare) breaks for authenticated installs on current CLI.
  • Also affects bunx, Deno, and CI, which strip cross-host auth regardless of version.

Immediate Mitigations

  • Registry operators: publish the canonical (post-redirect) host in components.json
  • Avoid cross-host redirects on registry paths.

Possible fix

While this is likely expected native fetch behavior, the CLI could handle this case for a better ongoing DX.

Option 1: Document the caveat (lowest effort)

In registry/auth docs, note that:

  • registry URLs should use the canonical URL (final URL after redirects)
  • auth headers from registries.*.headers are sent on the initial request only
  • they are not re-sent across origin-changing redirects

Option 2: CLI warning (helpful, still spec-correct)

If a registry request fails with 401/403 and the response was reached via a redirect that changed host/scheme/port, emit a targeted message:

Auth headers were not sent to the redirected URL (www.example.com). Use the canonical registry URL in components.json.

Option 3: CLI compatibility layer (optional)

To restore prior node-fetch ergonomics for private registries:

  • detect redirects where the target is the same registrable domain (e.g. example.comwww.example.com)
  • manually follow the redirect and re-attach configured per-registry headers on the redirected request

This would be an intentional deviation from strict fetch redirect semantics, so it should probably be:

  • opt-in (e.g. followRegistryRedirects: true), or
  • limited to same-site/subdomain cases only

Affected component/components

Registry

How to reproduce

  1. Configure an authenticated registry whose URL 301/308-redirects to another host (e.g. apex → www):
{
  "registries": {
    "@shadcnblocks": {
      "url": "https://shadcnblocks.com/r/{name}",
      "headers": { "Authorization": "Bearer ${SHADCNBLOCKS_API_KEY}" }
    }
  }
}
  1. Both npx shadcn@latest add @shadcnblocks/hero36 or npx shadcn@4.11.1 add @shadcnblocks/hero36 will fail with 401
  2. Change the URL to the redirect target host (https://www.shadcnblocks.com/r/{name}) → succeeds.

Alternatively if you a cli version before 4.11.1 it will work with both www and non-ww versions

  1. make sure the url is non-www https://shadcnblocks.com/r/{name}
  2. npx shadcn@4.11.0 add @shadcnblocks/hero36 will work

Codesandbox/StackBlitz link

No response

Logs

System Info

Node v22.15.0

Before submitting

  • I've made research efforts and searched the documentation
  • I've searched for existing issues

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

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