7

I am using Nextjs with next-auth for authentication with node.js at the backend . Now , I am setting my cookies in node.js and it works correctly in postman. I can authenticate ,without any issue. When it comes to NextJs , since I am only returning the res.data from the response , which essentially contains the user data and not JWT , I am not able to pass the cookies to the frontend. Hence, I am not authenticated for Node.js .I checked the documentation for cookies on next-auth but couldn't make it work .

The code for ./api/[...nextauth.ts]

import axios from 'axios'
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    Providers.Credentials({
      name: 'Credentials',
      credentials: {
        email: { label: "Email", type: "email", placeholder: "Your email" },
        password: { label: "Password", type: "password",placeholder: "*********" }
      },
      async authorize(credentials:any, req) {
          try
          {
              const res = await axios.post('http://node-app:4200/users/login',credentials)
              if(res.status==200)
              {
                return res.data
              }
          }
        catch(e:any){
          console.log(e.data)
        }
        return null
      }
    })
  ],
  pages: {
    signIn: '/auth/login',
    signOut: '/auth/logout',
    // error: '/auth/error', // Error code passed in query string as ?error=
    // verifyRequest: '/auth/verify-request', // (used for check email message)
    // newUser: undefined // If set, new users will be directed here on first sign in
  }
})

It would be helpful if someone could guide me how to add the cookies that I pushed from node.js to the nextjs's server side can be pushed to the next's frontend.

Ankush Verma
  • 689
  • 1
  • 8
  • 17
  • Hey just a small side note: `axios` throws an error for any status code outside 200-299, so you don't have to do the `res.status === 200` check to `return res.data` :) – rantao Sep 07 '21 at 15:39

3 Answers3

6

I think this was answered by Saul Montilla in this other question. I copy and paste his answer:

After time of researching I have figured it out.

I had to make a change in /pages/api/auth in the way I'm exporting NextAuth.

Instead of

export default NextAuth({
    providers: [
       ...
    ]

})

Export it like this, so we can have access to request and response object

export default (req, res) => {
    return NextAuth(req, res, options)
}

But to access them in the options object, we can make it a callback

const nextAuthOptions = (req, res) => {
    return {
        providers: [
           ...
        ]
    }
}

export default (req, res) => {
    return NextAuth(req, res, nextAuthOptions(req, res))
}

To send a cookie back to the frontend from the backed we must add a 'Set-Cookie' header in the respond

res.setHeader('Set-Cookie', ['cookie_name=cookie_value'])

The complete code would be

import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';

const nextAuthOptions = (req, res) => {
    return {
        providers: [
           CredentialsProvider({
                async authorize(credentials) {
                   try {                      
                        const response = await axios.post('/api/login', {
                            username: credentials.username,
                            password: credentials.password
                        })

                        const cookies = response.headers['set-cookie']

                        res.setHeader('Set-Cookie', cookies)
                        
                        return response.data
                    } catch (error) {
                        console.log(error)
                        throw (Error(error.response))
                    } 
                }
           })
        ]
    }
}

export default (req, res) => {
    return NextAuth(req, res, nextAuthOptions(req, res))
}
  • 1
    this works ok and we can get the cookie from the backend. but the problem is that the cookie stays in the header even after signout. how should we handle this? – amir yeganeh May 05 '22 at 06:12
  • @amiryeganeh Did you find a way to remove the cookie after logging out? – Doreen Chemweno Oct 04 '22 at 11:31
  • 1
    yes, but not using nextAuth! I ended up removing nextAuth from my project and I used js-cookie to set and remove the cookie manually – amir yeganeh Oct 23 '22 at 10:15
-1

From the source, return value of jwt callback will be encoded and updated back to client side via set-cookie response headers.
Though, I'm having issue in my case but maybe you could start looking from here.

JWT callbacks

callbacks: {
  async jwt(token, user) {
    if (user) {
      // `user` will be the return value of `authorize` if user first login.
      return user;
    } else {
      // after login, `token` is the decoded jwt from current session-token.
      return token;
    }
  }
}

// If you're interested, my issue is that after login, modified token (for example: exchanged expired access token with refresh token) couldn't be persist on client side.

Thanh Nhan
  • 453
  • 6
  • 17
-3

If you want to set cookie try to do something like this:

// import ... from ...
import Cookies from 'cookies';

const getOptions = (req, res) => ({
  // Configure one or more authentication providers
  providers: [
    Providers.Credentials({
      name: 'Credentials',
      credentials: {
        email: { label: "Email", type: "email", placeholder: "Your email" },
        password: { label: "Password", type: "password",placeholder: "*********" }
      },
      async authorize(credentials:any, req) {
        // do something

        // Set cookies
        const cookies = new Cookies(req, res);
        cookies.set('myCookie', myCookieValue);

        return null
      }
    })
  ],
  // some other configurations ...
});

export default (req, res) => NextAuth(req, res, getOptions(req, res));
Simone Urbani
  • 130
  • 1
  • 5