NextJS with next-auth ,setting cookie received from node.js [duplicate]
Asked Answered
H

3

10

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.

Hinny answered 3/7, 2021 at 10:4 Comment(1)
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 :)Middle
D
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))
}
Demos answered 25/10, 2021 at 8:16 Comment(3)
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?Tarver
@amiryeganeh Did you find a way to remove the cookie after logging out?Neumeyer
yes, but not using nextAuth! I ended up removing nextAuth from my project and I used js-cookie to set and remove the cookie manuallyTarver
L
-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.

Levorotation answered 5/9, 2021 at 3:17 Comment(0)
M
-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));
Merari answered 16/7, 2021 at 11:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.