nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.06k stars 3.33k forks source link

V5 Fails Behind Corporate Proxy with Provider #11028

Open SolidAnonDev opened 3 months ago

SolidAnonDev commented 3 months ago

Environment

OS: Windows 11 10.0.22621
CPU: (12) x64 Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
Memory: 6.80 GB / 15.78 GB
Binaries:
Node: 20.9.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 10.8.0 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (125.0.2535.51)
Internet Explorer: 11.0.22621.3527
npmPackages:
next: ^14.2.3 => 14.2.3
next-auth: ^5.0.0-beta.18 <= 5.0.0-beta.18
react: ^18.3.1 => 18.3.1

Reproduction URL

https://github.com/tbrundige/authjs-adapter-issue

Describe the issue

First off, I pulled a random repro link from other open issues to make it valid for the bot. This isn't really something I can reproduce. The reproduction is to try to use next-auth with a provider behind a corporate proxy, there's not really a minimal reproduction for that. I'm sorry for doing this but there's not much I can do to reproduce this.

Next-Auth, just as in #2509 - appears to fail behind a corporate proxy in V5 as well. We are using the Microsoft Entra ID provider, coming from the V4 Azure AD Provider.

For V4, we had been using this solution which was coined in the issue linked above, involving patching the next-auth source code with patch-package. This worked fine, but it appears things have changed a great deal in the V5 source and we cannot find where we should patch the source to allow the requests to make it through.

If support cannot be added for a corporate proxy with providers, we would like to at least see how/where to apply a patch to the source to make this workable as we did in V4. If not, this may completely bar and shutdown any ability to use next-auth moving forward when V5 is released, which would be really unfortunate for us.

V5 is working in development for us (Microsoft Entra Id Provider) without issue, with successful authentication, but upon deployment, we receive errors very remeniscent of what we saw with V4 behind a corporate proxy.

How to reproduce

ust run any application with NextAuth behind a corporate proxy and try to log in with a Provider (like Google or GitHub).

You will see something similar to the following:

message: 'fetch failed',
    stack: 'TypeError: fetch failed\n' +
      '    at Object.processResponse (node:internal/deps/undici/undici:5555:34)\n' 

Expected behavior

The requests are able to make it out to the providers for successful authentication from behind a corporate proxy. In previous iterations, we acheived this using an HttpProxyAgent.

MobliMic commented 2 months ago

So I've been having issues with corporate proxy as well for both v4 and v5 but have managed to get it working on v5 with the following code

import { ProxyAgent } from 'undici';

const discoveryResponse = await o.discoveryRequest(issuer,
        {
          [o.customFetch]: (...args) => {
            if (process.env.http_proxy) {
              const agent =  new ProxyAgent(process.env.http_proxy);
              args[1].dispatcher = agent;
            }
            return fetch(...args);
          }
        });

Below is the full (messy and auto-formatted) patch I've applied. I haven't tested the change for the profile image fetch but that's something I don't need so just applied the change in case I do in the future and based it on the v4 change.

Run an npm i undici

diff --git a/node_modules/@auth/core/lib/actions/callback/oauth/callback.js b/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
index e4e64ca..f912fc7 100644
--- a/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
+++ b/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
@@ -1,6 +1,8 @@
 import * as checks from "./checks.js";
 import * as o from "oauth4webapi";
 import { OAuthCallbackError, OAuthProfileParseError, } from "../../../../errors.js";
+import { ProxyAgent } from 'undici';
+
 /**
  * Handles the following OAuth steps.
  * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
@@ -20,7 +22,16 @@ export async function handleOAuth(query, cookies, options, randomState) {
         // We assume that issuer is always defined as this has been asserted earlier
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         const issuer = new URL(provider.issuer);
-        const discoveryResponse = await o.discoveryRequest(issuer);
+        const discoveryResponse = await o.discoveryRequest(issuer,
+          {
+            [o.customFetch]: (...args) => {
+              if (process.env.http_proxy) {
+                const agent =  new ProxyAgent(process.env.http_proxy);
+                args[1].dispatcher = agent;
+              }
+              return fetch(...args);
+            },
+          });
         const discoveredAs = await o.processDiscoveryResponse(issuer, discoveryResponse);
         if (!discoveredAs.token_endpoint)
             throw new TypeError("TODO: Authorization server did not provide a token endpoint.");
@@ -61,6 +72,9 @@ export async function handleOAuth(query, cookies, options, randomState) {
                 args[1]?.body instanceof URLSearchParams) {
                 args[1].body.delete("code_verifier");
             }
+            if (process.env.http_proxy) {
+              args[1].dispatcher = new ProxyAgent(process.env.http_proxy);
+            }
             return fetch(...args);
         },
     });
diff --git a/node_modules/@auth/core/lib/actions/signin/authorization-url.js b/node_modules/@auth/core/lib/actions/signin/authorization-url.js
index 8f093cb..6553c77 100644
--- a/node_modules/@auth/core/lib/actions/signin/authorization-url.js
+++ b/node_modules/@auth/core/lib/actions/signin/authorization-url.js
@@ -1,5 +1,7 @@
 import * as checks from "../callback/oauth/checks.js";
 import * as o from "oauth4webapi";
+import { ProxyAgent } from 'undici';
+
 /**
  * Generates an authorization/request token URL.
  *
@@ -15,7 +17,16 @@ export async function getAuthorizationUrl(query, options) {
         // We check this in assert.ts
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         const issuer = new URL(provider.issuer);
-        const discoveryResponse = await o.discoveryRequest(issuer);
+        const discoveryResponse = await o.discoveryRequest(issuer,
+        {
+          [o.customFetch]: (...args) => {
+            if (process.env.http_proxy) {
+              const agent =  new ProxyAgent(process.env.http_proxy);
+              args[1].dispatcher = agent;
+            }
+            return fetch(...args);
+          }
+        });
         const as = await o.processDiscoveryResponse(issuer, discoveryResponse);
         if (!as.authorization_endpoint) {
             throw new TypeError("Authorization server did not provide an authorization endpoint.");
diff --git a/node_modules/@auth/core/providers/microsoft-entra-id.js b/node_modules/@auth/core/providers/microsoft-entra-id.js
index 2063d5e..8b45cb6 100644
--- a/node_modules/@auth/core/providers/microsoft-entra-id.js
+++ b/node_modules/@auth/core/providers/microsoft-entra-id.js
@@ -100,6 +100,8 @@
  *
  * :::
  */
+import { ProxyAgent } from "undici";
+
 export default function MicrosoftEntraID(options) {
     const { tenantId = "common", profilePhotoSize = 48, ...rest } = options;
     rest.issuer ?? (rest.issuer = `https://login.microsoftonline.com/${tenantId}/v2.0`);
@@ -110,12 +112,21 @@ export default function MicrosoftEntraID(options) {
         wellKnown: `${rest.issuer}/.well-known/openid-configuration?appid=${options.clientId}`,
         authorization: {
             params: {
-                scope: "openid profile email User.Read",
-            },
+                scope: "openid profile email User.Read"
+            }
         },
         async profile(profile, tokens) {
             // https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples
-            const response = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, { headers: { Authorization: `Bearer ${tokens.access_token}` } });
+            let fetchOptions = {
+                headers: {
+                    Authorization: `Bearer ${tokens.access_token}`
+                }
+            };
+
+            if (process.env.http_proxy) {
+                fetchOptions.dispatcher = new ProxyAgent(process.env.http_proxy);
+            }
+            const response = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, fetchOptions);
             // Confirm that profile photo was returned
             let image;
             // TODO: Do this without Buffer
@@ -124,17 +135,17 @@ export default function MicrosoftEntraID(options) {
                     const pictureBuffer = await response.arrayBuffer();
                     const pictureBase64 = Buffer.from(pictureBuffer).toString("base64");
                     image = `data:image/jpeg;base64, ${pictureBase64}`;
+                } catch {
                 }
-                catch { }
             }
             return {
                 id: profile.sub,
                 name: profile.name,
                 email: profile.email,
-                image: image ?? null,
+                image: image ?? null
             };
         },
         style: { text: "#fff", bg: "#0072c6" },
-        options: rest,
+        options: rest
     };
 }

Using patch-package to generate and apply the change. Hope this helps if you haven't already solved the issue since posting :)

SolidAnonDev commented 2 months ago

@MobliMic - If this is working for you, this will likely work for me. A quick once over looks really good, as it appears to hit the same things V4 needed to work successfully behind the proxy.

I have been successfully using V4 for over a year with an older corporate proxy patch. I just had no idea how to track down where the problematic fetches are that need a proxy agent for V5. I will try this early next week and report back. Thanks so much for this!

Also, I am not using the profile picture call like you, so I have removed it completely in my patch file.

Charismara commented 2 months ago

So I've been having issues with corporate proxy as well for both v4 and v5 but have managed to get it working on v5 with the following code

import { ProxyAgent } from 'undici';

const discoveryResponse = await o.discoveryRequest(issuer,
        {
          [o.customFetch]: (...args) => {
            if (process.env.http_proxy) {
              const agent =  new ProxyAgent(process.env.http_proxy);
              args[1].dispatcher = agent;
            }
            return fetch(...args);
          }
        });

Below is the full (messy and auto-formatted) patch I've applied. I haven't tested the change for the profile image fetch but that's something I don't need so just applied the change in case I do in the future and based it on the v4 change.

Run an npm i undici

diff --git a/node_modules/@auth/core/lib/actions/callback/oauth/callback.js b/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
index e4e64ca..f912fc7 100644
--- a/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
+++ b/node_modules/@auth/core/lib/actions/callback/oauth/callback.js
@@ -1,6 +1,8 @@
 import * as checks from "./checks.js";
 import * as o from "oauth4webapi";
 import { OAuthCallbackError, OAuthProfileParseError, } from "../../../../errors.js";
+import { ProxyAgent } from 'undici';
+
 /**
  * Handles the following OAuth steps.
  * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
@@ -20,7 +22,16 @@ export async function handleOAuth(query, cookies, options, randomState) {
         // We assume that issuer is always defined as this has been asserted earlier
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         const issuer = new URL(provider.issuer);
-        const discoveryResponse = await o.discoveryRequest(issuer);
+        const discoveryResponse = await o.discoveryRequest(issuer,
+          {
+            [o.customFetch]: (...args) => {
+              if (process.env.http_proxy) {
+                const agent =  new ProxyAgent(process.env.http_proxy);
+                args[1].dispatcher = agent;
+              }
+              return fetch(...args);
+            },
+          });
         const discoveredAs = await o.processDiscoveryResponse(issuer, discoveryResponse);
         if (!discoveredAs.token_endpoint)
             throw new TypeError("TODO: Authorization server did not provide a token endpoint.");
@@ -61,6 +72,9 @@ export async function handleOAuth(query, cookies, options, randomState) {
                 args[1]?.body instanceof URLSearchParams) {
                 args[1].body.delete("code_verifier");
             }
+            if (process.env.http_proxy) {
+              args[1].dispatcher = new ProxyAgent(process.env.http_proxy);
+            }
             return fetch(...args);
         },
     });
diff --git a/node_modules/@auth/core/lib/actions/signin/authorization-url.js b/node_modules/@auth/core/lib/actions/signin/authorization-url.js
index 8f093cb..6553c77 100644
--- a/node_modules/@auth/core/lib/actions/signin/authorization-url.js
+++ b/node_modules/@auth/core/lib/actions/signin/authorization-url.js
@@ -1,5 +1,7 @@
 import * as checks from "../callback/oauth/checks.js";
 import * as o from "oauth4webapi";
+import { ProxyAgent } from 'undici';
+
 /**
  * Generates an authorization/request token URL.
  *
@@ -15,7 +17,16 @@ export async function getAuthorizationUrl(query, options) {
         // We check this in assert.ts
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         const issuer = new URL(provider.issuer);
-        const discoveryResponse = await o.discoveryRequest(issuer);
+        const discoveryResponse = await o.discoveryRequest(issuer,
+        {
+          [o.customFetch]: (...args) => {
+            if (process.env.http_proxy) {
+              const agent =  new ProxyAgent(process.env.http_proxy);
+              args[1].dispatcher = agent;
+            }
+            return fetch(...args);
+          }
+        });
         const as = await o.processDiscoveryResponse(issuer, discoveryResponse);
         if (!as.authorization_endpoint) {
             throw new TypeError("Authorization server did not provide an authorization endpoint.");
diff --git a/node_modules/@auth/core/providers/microsoft-entra-id.js b/node_modules/@auth/core/providers/microsoft-entra-id.js
index 2063d5e..8b45cb6 100644
--- a/node_modules/@auth/core/providers/microsoft-entra-id.js
+++ b/node_modules/@auth/core/providers/microsoft-entra-id.js
@@ -100,6 +100,8 @@
  *
  * :::
  */
+import { ProxyAgent } from "undici";
+
 export default function MicrosoftEntraID(options) {
     const { tenantId = "common", profilePhotoSize = 48, ...rest } = options;
     rest.issuer ?? (rest.issuer = `https://login.microsoftonline.com/${tenantId}/v2.0`);
@@ -110,12 +112,21 @@ export default function MicrosoftEntraID(options) {
         wellKnown: `${rest.issuer}/.well-known/openid-configuration?appid=${options.clientId}`,
         authorization: {
             params: {
-                scope: "openid profile email User.Read",
-            },
+                scope: "openid profile email User.Read"
+            }
         },
         async profile(profile, tokens) {
             // https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0&tabs=http#examples
-            const response = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, { headers: { Authorization: `Bearer ${tokens.access_token}` } });
+            let fetchOptions = {
+                headers: {
+                    Authorization: `Bearer ${tokens.access_token}`
+                }
+            };
+
+            if (process.env.http_proxy) {
+                fetchOptions.dispatcher = new ProxyAgent(process.env.http_proxy);
+            }
+            const response = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, fetchOptions);
             // Confirm that profile photo was returned
             let image;
             // TODO: Do this without Buffer
@@ -124,17 +135,17 @@ export default function MicrosoftEntraID(options) {
                     const pictureBuffer = await response.arrayBuffer();
                     const pictureBase64 = Buffer.from(pictureBuffer).toString("base64");
                     image = `data:image/jpeg;base64, ${pictureBase64}`;
+                } catch {
                 }
-                catch { }
             }
             return {
                 id: profile.sub,
                 name: profile.name,
                 email: profile.email,
-                image: image ?? null,
+                image: image ?? null
             };
         },
         style: { text: "#fff", bg: "#0072c6" },
-        options: rest,
+        options: rest
     };
 }

Using patch-package to generate and apply the change. Hope this helps if you haven't already solved the issue since posting :)

I've tried to use your patch in my NextJs Project and i run into this error:

With --turbo: image

Without --turbo: image

Is there something that i need to configure in nextjs to make it work?

Oakwhisper commented 2 months ago

We applied MobliMic's patch as is on our app and got it working. All we had to do was create a new patch file called next-auth+5.0.0-beta.19.patch and paste their patch in. Previously we couldn't get the other suggested patch for V4 working, so this is great!

We did run into a slight hiccup with the .env. The patch uses lowercase key names and our .env had uppercase. Adding a lowercase key did the trick.

Charismara commented 2 months ago

I still wasn't able to make this patch work for me.

I'm using the patch function of pnpm instead of patch-package with "next": "14.2.4" and "next-auth": "^5.0.0-beta.19".

@auth__core@0.32.0.patch file ```diff diff --git a/lib/actions/callback/oauth/callback.js b/lib/actions/callback/oauth/callback.js index e4e64ca424e3f46ccf3924d8b6e620ad75697b65..61f716840e37377e0f4191fbb932bddcb6ebcee4 100644 --- a/lib/actions/callback/oauth/callback.js +++ b/lib/actions/callback/oauth/callback.js @@ -1,6 +1,8 @@ import * as checks from "./checks.js"; import * as o from "oauth4webapi"; import { OAuthCallbackError, OAuthProfileParseError, } from "../../../../errors.js"; +import {customFetch} from "oauth4webapi"; +import {ProxyAgent} from "undici"; /** * Handles the following OAuth steps. * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 @@ -21,7 +23,15 @@ export async function handleOAuth(query, cookies, options, randomState) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const issuer = new URL(provider.issuer); const discoveryResponse = await o.discoveryRequest(issuer); - const discoveredAs = await o.processDiscoveryResponse(issuer, discoveryResponse); + const discoveredAs = await o.processDiscoveryResponse(issuer, discoveryResponse, { + [customFetch]: (input, init) => { + if(!init) init = {}; + if(process.env.HTTPS_PROXY) { + init.dispatcher = new ProxyAgent(process.env.HTTPS_PROXY); + } + return fetch(input, init); + } + }); if (!discoveredAs.token_endpoint) throw new TypeError("TODO: Authorization server did not provide a token endpoint."); if (!discoveredAs.userinfo_endpoint) @@ -61,6 +71,9 @@ export async function handleOAuth(query, cookies, options, randomState) { args[1]?.body instanceof URLSearchParams) { args[1].body.delete("code_verifier"); } + if (process.env.HTTPS_PROXY) { + args[1].dispatcher = new ProxyAgent(process.env.HTTPS_PROXY); + } return fetch(...args); }, }); diff --git a/lib/actions/signin/authorization-url.js b/lib/actions/signin/authorization-url.js index 8f093cb7ad48c9b5969ffe1da7fcd7b02ea1dbf2..408c7c19ba528b4854fe31a9da24f0f89c4b6b2e 100644 --- a/lib/actions/signin/authorization-url.js +++ b/lib/actions/signin/authorization-url.js @@ -1,5 +1,7 @@ import * as checks from "../callback/oauth/checks.js"; import * as o from "oauth4webapi"; +import {customFetch} from "oauth4webapi"; +import {ProxyAgent} from "undici"; /** * Generates an authorization/request token URL. * @@ -15,7 +17,15 @@ export async function getAuthorizationUrl(query, options) { // We check this in assert.ts // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const issuer = new URL(provider.issuer); - const discoveryResponse = await o.discoveryRequest(issuer); + const discoveryResponse = await o.discoveryRequest(issuer, { + [customFetch]: (input, init) => { + if(!init) init = {}; + if(process.env.HTTPS_PROXY) { + init.dispatcher = new ProxyAgent(process.env.HTTPS_PROXY); + } + return fetch(input, init); + } + }); const as = await o.processDiscoveryResponse(issuer, discoveryResponse); if (!as.authorization_endpoint) { throw new TypeError("Authorization server did not provide an authorization endpoint."); diff --git a/package.json b/package.json index e2d3af63a37d3f4b2cb922c347cd64126e343ef4..c4499b5539623db707ecfce3f5678b901ca4d34b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,8 @@ "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", - "nodemailer": "^6.8.0" + "nodemailer": "^6.8.0", + "undici": "^6.19.2" }, "peerDependenciesMeta": { "@simplewebauthn/browser": { ```
Errors With `--turbo`: ![image](https://github.com/nextauthjs/next-auth/assets/14293974/ee24c955-c413-4381-8434-de747e8108a4) Without `--turbo`: ![image](https://github.com/nextauthjs/next-auth/assets/14293974/940c62c5-2735-4636-a678-65e61b908eab)

Any Ideas what could be wrong?

SolidAnonDev commented 2 months ago

I was briefly attempting to use the patch the other day, but I ran into an issue with Undici and Next 14 with the error:

This error is referenced in this issue here

Module parse failed: Unexpected token (884:57)
|       // 5. If object is not a default iterator object for interface,
|       //    then throw a TypeError.
>       if (typeof this !== 'object' || this === null || !(#target in this)) {
|         throw new TypeError(
|           `'next' called on an object that does not implement interface ${name} Iterator.`

Import trace for requested module:
./node_modules/undici/lib/web/fetch/util.js
./node_modules/undici/lib/web/fetch/index.js
./node_modules/undici/index.js
./node_modules/@elastic/transport/lib/connection/UndiciConnection.js
./node_modules/@elastic/transport/lib/connection/index.js
./node_modules/@elastic/transport/index.js
./node_modules/@elastic/elasticsearch/index.js
./src/search/client.ts
./src/search/search.ts

This appears to be an issue with next and not undici, though I did apply the patch as@auth__core@0.32.0.patch and not next-auth+5.0.0-beta.19.patch so maybe I will try that and see what happens.

@Charismara I just realized this is the same issue you're having - this is a problem with next parsing Undici, and I'm not quite sure how to get around it or what versions of Next the other users are using in order to resolve this issue.

SolidAnonDev commented 2 months ago

We applied MobliMic's patch as is on our app and got it working. All we had to do was create a new patch file called next-auth+5.0.0-beta.19.patch and paste their patch in. Previously we couldn't get the other suggested patch for V4 working, so this is great!

We did run into a slight hiccup with the .env. The patch uses lowercase key names and our .env had uppercase. Adding a lowercase key did the trick.

@Oakwhisper Could you call out the package versions you're using for Undici and Next? I cannot get this working for the same reason as the other user.

Oakwhisper commented 1 month ago

@SolidAnonDev We are using:

"undici": "6.19.2",
"next": "14.2.3",
"next-auth": "5.0.0-beta.19",

I did start getting that same error when attempting to use middleware for auth instead of handling it in a server component.

Charismara commented 1 month ago

I'm still running into the errors from my last comment and got no ideas left to try. Any help is appreciated 😓

SolidAnonDev commented 1 month ago

I'm still running into the errors from my last comment and got no ideas left to try. Any help is appreciated 😓

I have not yet found a solution for this either.

This is a bit ridiculous that we can't get simple support for a corporate proxy. The community came up with a minimal solution for V4, they said it's "not a priority" back then, and still won't do anything about it now.

ajhous44 commented 4 weeks ago

I agree this seems actually quite limiting! Imagine all the corps that could use nextjs/next-auth if they would allow this natively 👍

SolidAnonDev commented 4 weeks ago

Right? It's been a problem for 2+ years.

github-actions[bot] commented 1 week ago

This issue was marked with the help needed label by a maintainer.

The issue might require some digging, so it is recommended to have some experience with the project.

Have a look at the Contributing Guide first.

This will help you set up your development environment to get started. When you are ready, open a PR, and link back to this issue in the form of adding Fixes #1234 to the PR description, where 1234 is the issue number. This will auto-close the issue when the PR gets merged, making it easier for us to keep track of what has been fixed.

Please make sure that - if applicable - you add tests for the changes you make.

If you have any questions, feel free to ask in the comments below or the PR. Generally, you don't need to @mention anyone directly, as we will get notified anyway and will respond as soon as we can)

[!NOTE]
There is no need to ask for permission "can I work on this?" Please, go ahead if there is no linked PR :slightly_smiling_face:

ThangHuuVu commented 1 week ago

We're happy to review a PR to get rid of the patch 😊 due to the complexity of corporate proxy setup - as mentioned in the PR description by @SolidAnonDev, us maintainers also haven't really found the time to implement & test it thoroughly. This is where we can really use some help from the community! 🙏

ajhous44 commented 1 week ago

@ThangHuuVu If it means anything, as others have echoed, the above patch worked for me.

SolidAnonDev commented 1 week ago

@ajhous44

Not sure what version of next you're using, but I was unable to get it working due to the previously documented errors but now see this with the next@latest

Module build failed: UnhandledSchemeError: Reading from "node:console" is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "node:" URIs.
Import trace for requested module:
node:console
./node_modules/undici/lib/mock/pending-interceptors-formatter.js
./node_modules/undici/lib/mock/mock-agent.js
./node_modules/undici/index.js
./node_modules/@auth/core/providers/microsoft-entra-id.js
./node_modules/next-auth/providers/microsoft-entra-id.js
./src/lib/auth.ts

This kind of thing with Undici is not something I know how to resolve or diagnose unfortunately.

Zamoca42 commented 1 week ago

When I tried to reproduce the issue in callback.ts of @auth/core, I encountered errors when importing undici or node-related modules. Shouldn't we attempt to implement the proxy using only the fetch API, or be able to internally import node modules? Additionally, in the patch provided above, the init (RequestInit) object doesn't contain a dispatcher property.

Zamoca42 commented 1 week ago

@SolidAnonDev

Module build failed: UnhandledSchemeError: Reading from "node:console" is not handled by plugins (Unhandled scheme).

I discovered that the UnhandledSchemeError occurs when using node modules and auth.js middleware simultaneously.

Next.js supports node runtime, but when auth is added to middleware, it runs in full edge runtime, restricting the use of some node modules.

Reference: https://authjs.dev/guides/edge-compatibility#middleware

For middleware-related issues, I referred to this discussion: https://github.com/vercel/next.js/discussions/62985