hoangvvo / next-connect

The TypeScript-ready, minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2
https://www.npmjs.com/package/next-connect
MIT License
1.64k stars 65 forks source link

Nextjs jwt.getToken and getSession returning null with next-connect handler #151

Closed mohsenmahoski closed 3 years ago

mohsenmahoski commented 3 years ago

I using next-auth for users authentication and this is my configuration:

import NextAuth from "next-auth";
import Providers from "next-auth/providers";
import { User } from "../../../model/entity/User";
import { getOrCreateConnection } from "../../../utils/connection";
import {
  AuthorizationError,
  NotFoundError,
  ServerError,
} from "../../../utils/error";
import bcrypt from "bcrypt";

export default NextAuth({
  providers: [
    Providers.Credentials({
      async authorize(credentials, req) {
        const { username, password } = credentials as {
          username: string;
          password: string;
        };

        try {
          const conn = await getOrCreateConnection();
          const userRepo = await conn.getRepository(User);
          const user = await userRepo.findOne({ username });

          if (!user) {
            throw new NotFoundError(["user not found."]);
          }

          const isUser = await bcrypt.compare(password, user.password);
          if (!isUser) {
            throw new AuthorizationError(["wrong credentials."]);
          }
          return { username: user.username, role: user.role };
        } catch (error) {
          throw new ServerError();
        }
      },
    }),
  ],
  secret: process.env.JWT_SECRET,
  session: {
    jwt: true,
    maxAge: 5 * 60 * 60,
  },
  jwt: {
    secret: process.env.JWT_SECRET,
  },
  pages: {
    signIn: "/login",
  },
  callbacks: {
    //customize token and session of nextAuth
    async jwt(token, user, account, profile, isNewUser) {
      // Add access_token to the token right after signin
      if (user?.username) {
        token.username = user.username;
      }
      if (user?.role) {
        token.role = user.role;
      }
      delete token.user;
      return token;
    },
    async session(session, token) {
      // Add property to session, like an access_token from a provider.
      if (token?.username) {
        session.username = token.username;
      }
      if (token?.role) {
        session.role = token.role;
      }
      delete session.user;
      return session;
    },
  },
});

when I want to get users info in the API routes its working:

import { NextApiRequest, NextApiResponse } from "next";
import { ERequest } from "../../../enums/app.enums";
import { getSession } from "next-auth/client";
import jwt from "next-auth/jwt";

const routes = async (req: NextApiRequest, res: NextApiResponse) => {
  const method = req.method;

  switch (method) {
    case ERequest.GET:
      const token = await jwt.getToken({ req, secret: process.env.JWT_SECRET });
      const session = await getSession({ req });
      console.log(
        "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>"
      );
      console.log("JSON Web Token", token);
      console.log("Session is:", session);
      console.log(
        "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>"
      );
      return res.status(200).json({ data: "OK" });
    default:
      res.status(400).json({ message: "bad request." });
  }
};
export default routes;

I have the user info in my console:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>
JSON Web Token {
  username: 'mohsenmahoski@gmail.com',
  role: 'ADMIN',
  iat: 1626257715,
  exp: 1628849715
}
The ession is: {
  expires: '2021-07-14T15:15:52.262Z',
  username: 'mohsenmahoski@gmail.com',
  role: 'ADMIN'
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>

but when I using next-connect like this:

import nextConnect from "next-connect";
import { getSession } from "next-auth/client";
import jwt from "next-auth/jwt";

const handler = nextConnect<any, any>();

handler.get(async (req, res) => {
  const token = await jwt.getToken({ req, secret: process.env.JWT_SECRET });
  const session = await getSession({ req });
  console.log("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>");
  console.log("JSON Web Token", token);
  console.log("Session is:", session);
  console.log("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>");
  return res.status(200).json({ data: "OK" });
});

export default handler;

result of both is null:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>
JSON Web Token null
The session is: null
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>

I also found that there are no cookies in my request when using handler and req.cookies is {} what I missed and what's my wrong?

mohsenmahoski commented 3 years ago

sorry, it was my mistake and a wrong approach. I sent the request to my API in getServerSideProps and my Fetch class not sending cookies, it not related to the next-connect handler

snax4a commented 2 years ago

Hi @mohsenmahoski, I like your code structure. Is this project public or private? I would love to take a look at the rest of your code to learn more.