Open formerskulk4 opened 2 years ago
I've setup a quick reproduction based on your API route code provided above and it seems to work for me. It will return null
if you're unauthenticated. However, if you copy a request "as curl" out of your browsers network dev tools (when authenticated) which includes the token/cookie and modify the URL to the api route, I got a response and the dev server terminal logged the session successfully.
Can you double check the GET
requests you're making are actually also authenticated (i.e. including the cookie or authorization header?
I can confirm that with the GET
request, authenticated does not receive the session.
I tried with POST
on This request and it works perfectly.
I created a job from the POST
request and I received this by console.log(session)
{
user: { name: 'Company', email: 'company@email.com' },
expires: '2022-04-22T19:23:39.673Z',
id: 2,
name: 'Company',
surname: 'Surname',
email: 'company@email.com',
role: 2
}
I tried a POST
request from postman and it says that I am not logged in, which is okay, but when I am authenticated from my project, the session is retrieved successfully.
So this problem happens only with GET
This is the request from cuRL from the get request:
curl "http://localhost:3000/company/jobs" ^
-H "Connection: keep-alive" ^
-H "sec-ch-ua: ^\^" Not A;Brand^\^";v=^\^"99^\^", ^\^"Chromium^\^";v=^\^"99^\^", ^\^"Google Chrome^\^";v=^\^"99^\^"" ^
-H "sec-ch-ua-mobile: ?0" ^
-H "sec-ch-ua-platform: ^\^"Windows^\^"" ^
-H "DNT: 1" ^
-H "Upgrade-Insecure-Requests: 1" ^
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36" ^
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" ^
-H "Sec-Fetch-Site: none" ^
-H "Sec-Fetch-Mode: navigate" ^
-H "Sec-Fetch-User: ?1" ^
-H "Sec-Fetch-Dest: document" ^
-H "Accept-Language: en-US,en;q=0.9,de-DE;q=0.8,de;q=0.7,sq;q=0.6" ^
-H "Cookie: _ga=GA1.1.622907214.1643984174; next-auth.csrf-token=c2db1395200a91b1915039666fe73b4d36a5fd49a430dffac15d0d704b6613dc^%^7C07336a24d0a4cc0a2dd92548d698de66d84e5f3daf1e28b5592e3a2cb9ee871f; next-auth.callback-url=http^%^3A^%^2F^%^2Flocalhost^%^3A3000^%^2F; next-auth.session-token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..k5rKQz-UT6gGL2O8.381fW_sK8GZ-zo8PA3gS1V7xmwBvpYMc_EkgNx9wcbxKh9KsHGVe1adOrIUfexJeoxpP_WpBc1rpp3BIUdlPcLPCbmgor_WjHLbRhmOLQd7mW2bZN8C7DyZm3JlUdBCX6iIpOicYeNJSI6dtooVQkC136X1izbyaP3E92z56CiKbEhLVLd0o-SZZItreAvWXD04RjlqAhAmqovvwrcB-A1POYDxfsw2rR3Vf.UQuUbRZhvGPXwDV8nJB7Zg" ^
--compressed
Okay, alternatively you can give our experimental getServerSession
a try. Something like this:
import { getServerSession } from "next-auth/next";
import { authOptions } from './auth/[...nextauth]'
export default async (req, res) => {
const { method } = req;
switch (method) {
case "GET":
try {
const session = await getServerSession({req, res}, authOptions)
console.log("SESSION", session)
res.status(200).json({
message: "Success",
session
})
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message });
}
}
}
I was also able to get this ^^ to successfully work.
We've released it as a preview in the latest release, and there are two open PRs which provide more documentation for it which you can take a look at:
Thank you for your reply, but what is authOptions because referring to my [...nextauth.js] and I do not have a authOptions, in this way can you double check the procedure if the authentication is done correctly (for security issues or any other problem such as GET request, even though I think has nothing to do with [..nextauth].js )
import NextAuth from "next-auth";
import CredentialProvider from "next-auth/providers/credentials";
import axios from "axios";
export default NextAuth({
providers: [
CredentialProvider({
name: "credentials",
async authorize(credentials) {
try {
const user = await axios.post(
`${process.env.API_URL}/auth/authentication/login`,
{
email: credentials.email,
password: credentials.password,
}
);
if (!user.data.user) {
return null;
}
if (user.data.user) {
return {
id: user.data.user.id,
name: user.data.user.name,
surname: user.data.user.surname,
email: user.data.user.email,
role: user.data.user.role,
};
}
} catch (error) {
console.error(error);
}
},
}),
],
callbacks: {
jwt: ({ token, user }) => {
if (user) {
token.id = user.id;
token.name = user.name;
token.surname = user.surname;
token.email = user.email;
token.role = user.role;
}
// Here, check the token validity date
if (token.tokenExpiration < Date.now()) {
// Call the endpoint where you handle the token refresh for a user
const user = axios.post(
`${process.env.API_URL}/auth/authentication/refresh`,
{
refreshToken: token.refreshToken,
}
);
// Check for the result and update the data accordingly
return { ...token, ...user };
}
return token;
},
session: ({ session, token }) => {
if (token) {
session.id = token.id;
session.name = token.name;
session.surname = token.surname;
session.email = token.email;
session.role = token.role;
}
return session;
},
},
secret: process.env.SECRET_KEY,
jwt: {
secret: process.env.SECRET_KEY,
encryption: true,
maxAge: 5 * 60 * 1000,
},
pages: {
signIn: "/auth/login",
},
});
I also gave a try with getServerSession, but still no success.
API request
const session = await getServerSession({ req, res }, authOptions);
console.log(session);
console.log("SESSION", session);
if (!session) {
return res.status(401).json({
message: "You are not logged in",
});
}
[..nextauth].js
import NextAuth from "next-auth";
import CredentialProvider from "next-auth/providers/credentials";
import axios from "axios";
export const authOptions = {
providers: [
CredentialProvider({
name: "credentials",
async authorize(credentials) {
try {
const user = await axios.post(
`${process.env.API_URL}/auth/authentication/login`,
{
email: credentials.email,
password: credentials.password,
}
);
if (!user.data.user) {
return null;
}
if (user.data.user) {
return {
id: user.data.user.id,
name: user.data.user.name,
surname: user.data.user.surname,
email: user.data.user.email,
role: user.data.user.role,
};
}
} catch (error) {
console.error(error);
}
},
}),
],
callbacks: {
jwt: ({ token, user }) => {
if (user) {
token.id = user.id;
token.name = user.name;
token.surname = user.surname;
token.email = user.email;
token.role = user.role;
}
// Here, check the token validity date
if (token.tokenExpiration < Date.now()) {
// Call the endpoint where you handle the token refresh for a user
const user = axios.post(
`${process.env.API_URL}/auth/authentication/refresh`,
{
refreshToken: token.refreshToken,
}
);
// Check for the result and update the data accordingly
return { ...token, ...user };
}
return token;
},
session: ({ session, token }) => {
if (token) {
session.id = token.id;
session.name = token.name;
session.surname = token.surname;
session.email = token.email;
session.role = token.role;
}
return session;
},
},
secret: process.env.SECRET_KEY,
jwt: {
secret: process.env.SECRET_KEY,
encryption: true,
maxAge: 5 * 60 * 1000,
},
pages: {
signIn: "/auth/login",
},
};
export default NextAuth(authOptions);
I have created a new project to test that and it is still with the same problem,
@formerskulk4 getSession()
or getServerSession()
will return you null
if the user is not authenticated. Have you verified that the user is logged in when calling the function?
I am positive that the user is authenticated, it is weird because when POST
request is used there is no null returned.
Hey im having this problem as well the user is authenticated
i'm seeing a next-auth.session-token on cookies as well but when i try to request GET on getServerSideProps it will return me null on getSession on Handler(/api)
but if i use client side fetching it works perfectly
my code
/api/tasks/index.js
const handler = async (req, res) => {
if (req.method === "GET") {
const session = await getSession({ req });
if (!session) {
res.status(401).json({ message: "Not Authenticated" });
return;
}
const userId = session.user.id;
const client = await connectDb();
const db = client.db();
const tasks = await db
.collection("tasks")
.find({ user_id: userId })
.toArray();
res.status(200).json(tasks);
}
};
index.js
export const getServerSideProps = async (context) => {
const res = await fetch(`http://localhost:3000/api/tasks`);
const data = await res.json();
return {
props: { data },
};
};
where i fetch here now i get a message: "Not Authenticated" (i'm logged in 100% sure)
useEffect works perfectly fine(client fetching)
useEffect(() => {
const fetchData = async () => {
const res = await fetch(`http://localhost:3000/api/tasks`);
const data = await res.json();
console.log(data);
};
fetchData();
}, []);
@markmendozadev
When you use the POST
request does it work? Because I am having the same issue, I am positive that the user is authenticated however here returns null on the server side.
use this code in your _app.js :
function MyApp({Component, pageProps}) { return ( <SessionProvider session={pageProps.session}> <Component {...pageProps} /> </SessionProvider> ); }
@jaminecode I have already that.
`export default function App({ Component, pageProps }) { return (
); } `
Hi @ParidV Yes i think i found my answers already but not 100% sure. It works on client-side because getSession works on client-side requests.
if you do a request on your api through client side (not using any next data fetching just pure react it will 100% work) i mean the authentication.
now i did a little digging and here's what i found (https://github.com/nextauthjs/next-auth/pull/4116)
@jaminecode my _app.js already like that
import "../styles/globals.css";
import { SessionProvider } from "next-auth/react";
import Layout from "../components/layout/Layout";
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<Layout>
<Component {...pageProps} />
</Layout>
</SessionProvider>
);
}
export default MyApp;
@markmendozadev maybe this is a late response, but I faced the same issue with POST method, I could access the session, but not with POST, after doing some research, I found this is because NextJS does not send the cookies in the header for GET method, so I fixed the issue like this:
`let res = await fetch("http://localhost:3000/api/posts", { method: "GET", headers: {
"Content-Type": "application/json",
// I have to add cookie in the GET
Cookie: context.req.headers.cookie,
},
});`
@markmendozadev maybe this is a late response, but I faced the same issue with POST method, I could access the session, but not with POST, after doing some research, I found this is because NextJS does not send the cookies in the header for GET method, so I fixed the issue like this:
That worked for me, thanks!
@markmendozadev maybe this is a late response, but I faced the same issue with POST method, I could access the session, but not with POST, after doing some research, I found this is because NextJS does not send the cookies in the header for GET method, so I fixed the issue like this:
`let res = await fetch("http://localhost:3000/api/posts", { method: "GET", headers: {
"Content-Type": "application/json", // I have to add cookie in the GET Cookie: context.req.headers.cookie, },
});`
Still having an issue with using POST request where when using POST session returns null, but when using GET it returns normally (client-side)
The console log i would get would be
[next-auth][error][CLIENT_FETCH_ERROR]
https://next-auth.js.org/errors#client_fetch_error undefined {
error: {},
url: 'http://localhost:3000/api/auth/session',
message: undefined
}
But even though the link works and have nextauth url in .env and because it doesnt error out when using "GET"
{
the same issue, have solved it?
I had the same problem, when I try to make a GET request everything works fine, but when I make a POST request, it seems that the user is not logged in.
I solved it this way
const body = {...req.body} ;
req.body = null ;
const session = await getSession({ req:req });
req.body = body ;
I am not sure, but I think there is a problem inside the fetchData
function in file node_modules/next-auth/src/client/_utils.ts
Having the same issue on "next": "^14.0.1"
and "next-auth": "4.24.4"
When I am fetching from the API routes (serverless functions) I am cant retrieve the session. But this is only when I am fetching from the nextjs app.
Let me explain:
I have this API endpoint on my /api/session
.
// api/session/route.ts
import { getServerSession } from "next-auth";
import { NextResponse } from "next/server";
import { authOptions } from "@/lib/authOptions";
export async function GET(request: Request) {
const session = await getServerSession(authOptions);
return NextResponse.json({
authenticated: !!session,
session,
});
}
// page.tsx
import { authOptions } from "@/lib/authOptions";
import { getServerSession } from "next-auth";
async function getSession() {
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/session`,
{
method: "GET",
headers: { "Content-Type": "application/json" },
cache: "no-cache",
},
);
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
} catch (error) {
console.log(error);
}
}
const Page = async () => {
const firstSession = await getSession();
const secondSession = await getServerSession(authOptions);
return (
<pre>
{JSON.stringify(firstSession, null, 2)}
{JSON.stringify(secondSession, null, 2)}
</pre>
);
};
export default Page;
The result of this is the following
However when I reach for the same endpoint through the browser I am not seeing the following
Seems like the fetch
is missing some headers/cookies. Anyone has any suggestions on what I am missing ?
Okay I think I got it now
The reason I was getting null
when I called getServerSession() from server-side component is because cookies are not passed by default in server-side fetch.
So as people here mentioned before you have to pass the headers.
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/reservations/list`,
{
method: "GET",
headers: headers(), // passing the headers :)
cache: "no-cache",
},
);
Guys.. I hope to help you all, but I'm not sure.. My need is to make a request at getServerSideProps by using axios, but ofc the session will be not there in the axios interceptor when the request gets fired, so I made a function to attach the session into my axios instance.
Next 14.2 Next-Autg v5 (beta 17 ATM)
in my specific case the following solution has been working so far:
// the file where the getServerSideProps is
import { GetServerSideProps } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import getServerSession from "@/core/axios/getServerSession"; // <<-- this is the guy!
import getAvailableSites from "../path/to/getAvailableSites";
export const getServerSideProps: GetServerSideProps = async ({
locale,
req,
res,
}) => {
try {
await getServerSession(req, res);
const availableSites = await getAvailableSites();
// ... bla bla bla
return { props: {/* what you need to return*/} };
};
// getServerSession.ts
import type { IncomingMessage, ServerResponse } from "http";
import { NextApiRequest, NextApiResponse } from "next/types";
// default auth function from next-auth v5
import { auth } from "@/auth";
import { axiosInstance } from ".";
const getServerSession = async (req: IncomingMessage, res: ServerResponse) => {
const session = await auth(req as NextApiRequest, res as NextApiResponse);
if (session) {
axiosInstance.defaults.headers.common.Authorization = `Bearer ${session.accessToken}`;
return;
}
throw new Error("getServerSession - Not authenticated.");
};
export default getServerSession;
please guys, let me know if I'm missing something.. I'm sure there is a better way..
Good luck guys!
Okay I think I got it now
The reason I was getting
null
when I called getServerSession() from server-side component is because cookies are not passed by default in server-side fetch.So as people here mentioned before you have to pass the headers.
const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/reservations/list`, { method: "GET", headers: headers(), // passing the headers :) cache: "no-cache", }, );
@paschalidi you saved my day, thanks!
method: "GET"
is not necessary and remember about to wrap it when using Vercel in:
headers: new Headers(headers()),
Provider type
Credentials
Environment
System: OS: Windows 10 10.0.19044 CPU: (4) x64 Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz Memory: 5.06 GB / 15.87 GB Binaries: Node: 14.17.5 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.17 - ~\AppData\Roaming\npm\yarn.CMD npm: 8.1.3 - C:\Program Files\nodejs\npm.CMD Browsers: Edge: Spartan (44.19041.1266.0), Chromium (99.0.1150.46) Internet Explorer: 11.0.19041.1566 npmPackages: next: ^12.0.10 => 12.0.10 next-auth: ^4.2.1 => 4.2.1 react: 17.0.2 => 17.0.2
Reproduction URL
https://github.com/ParidV/Dua-n-pu
Describe the issue
getSession returning null in Get requests, in POST request the session is okay.
Component
API Request api/company/jobs/index.js
How to reproduce
In POST request, the session is okay, but when I make a get request to get the ID from the server to pass in the axios request come as NULL.
Expected behavior
It should return the session