New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Getting token in middleware doesn't work with authorization header request #4042
Comments
You should be using the dedicated Middleware API for this now: https://next-auth.js.org/configuration/nextjs#middleware
Your issue is that you did not pass the next-auth/packages/next-auth/src/jwt/index.ts Lines 93 to 106 in 3d0c68d
|
I tried this method you recommended as well, but still gives me null. I have not been able to get the token info in middleware by any means so far. Also, I pass secret in the environment variable correctly, and that shouldn't be the issue (unless I need to explicitly pass it somewhere else). Also the reason I can say it's probably not the issue is that it works correctly in the API code (see below description). Here's my middleware code (pages/api/_middleware.ts). This gives type errors, but that's another issue.: import { withAuth } from "next-auth/middleware"
import { NextRequest, NextResponse } from "next/server"
export default withAuth(
function middleware(req: NextRequest & { nextauth: { token: JWT } }) {
console.log("Middleware token", req.nextauth.token)
return NextResponse.next()
},
{
callbacks: {
authorized: ({ token }) => true,
},
}
) Here's my API code (pages/api/<my_api_path>) const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const token = await getToken({ req })
console.log("Server side token: ", token)
...
} My vscode rest client request is this:
The console output is:
Just for sake of completeness, console logging the token from the authorize callback also results in the same issue, i.e. following middleware code also gives same output: import { withAuth } from "next-auth/middleware"
export default withAuth({
callbacks: {
authorized: ({ token }) => {
console.log("Middleware token", token)
return true
},
},
}) |
Could you please respond to my comment or reopen the issue? I haven't figured it out yet. Please let me know if I need to provide more info. |
Could you attach a minimal reproduction repository? 🙏 Make sure you are on at least |
I forked the next auth example and made a branch and pull request with the above code so you can see it more clearly. This is the pull request: https://github.com/nextauthjs/next-auth-example/pull/67/files If you fill in all the environment variables, grab the raw token and send API request like I did in rest_client.http file, you'll see "Middleware token" output null whereas token in the API code output correctly. I did this with Google, so filled in Google's ID and secret as well as nextauth secret. |
Any update on this one by any chance? Just an acknowledgement that this is indeed an issue, and that you're prioritizing/deprioritizing this would be helpful to structure my project accordingly. |
Haven't had the time to confirm yet. Kept open with the If you are certain this is a bug, you are welcome to open a PR. Here is the relevant code: https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/next/middleware.ts |
@balazsorban44 Facing the exact same issue, I am calling my api in the getServerSideProps and my token returns null, I tried everything by reading other similiar issues, but no luck. Only this issue addresses it correctly. I tried using getSession and getToken, both of them return null for the requests made from getServerSideProps. It works fine in client side data fetching I am on a http connection during development, is it possible that could result in nextauth cookies not being sent along with my requests from getServerSideProps? |
Request is made here export async function getServerSideProps() {
const client = new QueryClient();
await client.prefetchQuery("menus", getMenus);
console.log(client.getQueryData("menus"));
return {
props: {
dehydratedState: dehydrate(client),
},
};
} Middleware import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";
const secret = process.env.NEXTAUTH_SECRET;
async function middleware(req: NextRequest) {
// @ts-ignore
const session = await getToken({ req, secret });
console.log("session: ", session);
if (!req.url.includes("/api/auth") && !session) {
console.log("session: ********" + req.url, session);
const response = new NextResponse("Unauthorized", {
status: 401,
statusText: "unauthorized",
});
return response;
}
NextResponse.next();
}
export default middleware; Note: I tried the nextauth middleware too but it no luck |
Having the same issue. Just a wild guess: "req.headers.authorization" does not work (anymore) as it is used e.g. here: next-auth/packages/next-auth/src/jwt/index.ts Lines 93 to 106 in 3d0c68d
What we actually need to do is (or at least that gets me the actual token): |
I believe Next.js Middleware now uses the So we should handle this case correctly. Feel free to open a PR |
Actually, this seems to have been fixed in #4472 already, we just need a new release. See the code here: next-auth/packages/next-auth/src/jwt/index.ts Lines 94 to 97 in e4ee520
|
Why is this closed? The original issue has not been resolved yet |
Please reopen this issue! I'm facing the same problem |
I faced the same issue while using next@latest[12.2.3]. Downgrading to next@12.2.0 fixed it for me. |
What does your middleware code look now please |
Mine is very simple.
|
Hmm thanks ! Buts still not working for me even with next@12.2.0 and the middleware in the root Update : I comfirm that downgrading to @12.2.0 make all working for now |
I confirm too, the only way to work is downgrading nextjs... I've been struggling all day, no hope. |
@90PabloRomero which version of next-auth are you using? I have the same issue even with the v12.0.0 |
@nicosilvabuydepa sorry for the late reply
|
I'm also not able to make middleware work properly. Could all this be related? |
same issue using next@latest[12.2.3]. |
I downgraded from next 12.2.3 to next 12.2.0 and that fixed the issue for me. |
The issue is being moved to: #5008 |
Also for me, using:
it works |
Failed with
|
For anyone working with next version >= 13, this solution worked for me. import { NextRequest, NextResponse } from "next/server";
import { getSession } from "next-auth/react";
import { env } from "./env.mjs";
async function middleware(request: NextRequest) {
const requestForNextAuth = {
headers: {
cookie: request.headers.get("cookie"),
},
};
const session = await getSession({ req: requestForNextAuth });
const isAuthPage =
request.nextUrl.pathname.startsWith("/login") ||
request.nextUrl.pathname.startsWith("/register");
if (!session) {
let from = request.nextUrl.pathname;
if (request.nextUrl.search) {
from += request.nextUrl.search;
}
const absoluteFrom = `${env.NEXT_PUBLIC_APP_URL}/${from}`;
return NextResponse.redirect(
`${env.NEXT_PUBLIC_APP_URL}/login?from=${encodeURIComponent(
absoluteFrom,
)}`,
);
} else if (isAuthPage) {
return NextResponse.redirect(`${env.NEXT_PUBLIC_APP_URL}/dashboard`);
}
return null;
}
export default middleware;
export const config = {
matcher: ["/dashboard", "/org/:path*"],
}; |
A work around for the problem is here!!Unfortunately those of us who are using alternate authentication methods such as session-based authentication don't have anything out of the box, and implementing a middleware like that yourself is trickier than you would expect, because you cannot simply pass the request in your middleware to getSession This seems to be because the next-auth accesses headers via req.headers.cookie, but the type of the headers inside middleware is not an object, but a Headers object which must be accessed through req.headers.get("cookie") I have implemented a middleware that works for session-based authentication. It does this by converting the relevant part of the request headers to an object import type { NextFetchEvent, NextRequest } from 'next/server';
import { getSession } from 'next-auth/react';
import { NextResponse } from 'next/server';
export async function middleware(req: NextRequest, ev: NextFetchEvent) {
const requestForNextAuth = {
headers: {
cookie: req.headers.get('cookie'),
},
};
const session = await getSession({ req: requestForNextAuth });
if (session) {
console.log(session);
// validate your session here
return NextResponse.next();
} else {
// the user is not logged in, redirect to the sign-in page
const signInPage = '/auth/signin';
const signInUrl = new URL(signInPage, req.nextUrl.origin);
signInUrl.searchParams.append('callbackUrl', req.url);
return NextResponse.redirect(signInUrl);
}
} However I think this means that an extra fetch call will be made to the next-auth backend. One in the middleware, and one later on if you want to access the session in API calls. |
You are a life saver! Ive been struggling with this problem all day, with no hope. |
Environment
System:
OS: macOS 11.6
CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
Memory: 169.62 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 16.13.0 - /usr/local/bin/node
Yarn: 1.22.15 - ~/.yarn/bin/yarn
npm: 8.1.0 - /usr/local/bin/npm
Browsers:
Brave Browser: 72.0.59.35
Chrome: 98.0.4758.102
Edge: 98.0.1108.56
Safari: 14.1.2
npmPackages:
next: ^12.0.7 => 12.0.9
next-auth: ^4.2.1 => 4.2.1
react: 17.0.2 => 17.0.2
Reproduction URL
None
Describe the issue
When using just the authorization header, the getToken(req) method returns correctly in the server with NextApiRequest, but not in the middleware with NextRequest. When I dug through the code, it seems it's because NextApiRequest authorization header is in the list, whereas getToken function is trying to split the authorization header by space, which shouldn't work for this case.
How to reproduce
For any OAuth provider, get the raw token.
Use it from a REST client with the Authorization: Bearer and send an API request.
In the middleware, try getToken({req}). It returns null, whereas in the actual API route code, it returns the token info correctly. Also, it works correctly when a user actually logs in in the browser and there's cookies and other jazz from the browser.
The middleware code is very simple:
My API request is:
Expected behavior
I should get the token info in the middleware with just the auth header with bearer token (not only with browser session).
The text was updated successfully, but these errors were encountered: