Next.js Discord

Discord Forum

Next.js server action: axios not using credential that has been set in browser by Nest.js server

Answered
Minskin posted this in #help-forum
Open in Discord
Avatar
MinskinOP
So I am new to next.js 14, I am building an application that use Next.js in the frontend and Nest.js in the backend. After developing the backend solely in Nest.js and testing it via postman, it never has problem with cookie, as postman can receive it and set it to its header and use it for future request. However when I am trying to fetch data using Next.js server action, the cookie that has been set in the browser is not used by Axios, hence my server denying resources to client.

//auth.controller.ts (nest.js server)

@Post('login')
  async signIn(@Request() req, @Res() res: Response) {
    const { userID, accessToken, refreshToken } = await this.authService.login(
      req.user,
    );

    res
      .cookie('access_token', accessToken, {
        httpOnly: true,
        secure: true,
        sameSite: 'lax',
        expires: new Date(Date.now() + 1 * 12 * 60 * 1000),
      })
      .send({ status: 'ok' });
  }


//page.tsx (next.js)
import axios from 'axios';
import { redirect } from 'next/navigation';


export default async function Page() {
    async function postLogin(input: FormData) {
        'use server';

        let body = {
            email: input.get('email'),
            password: input.get('password'),
        };

        const { data }: any = await axios.post(
            'http://127.0.0.1:8080/auth/login',
            body,
        );
        
     
        
        redirect('/users')
    }

    return (
        <div className='h-screen w-screen bg-slate-300 flex flex-col align-middle justify-center content-center'>
            <form action={postLogin}>
                <input name='email' type='email' placeholder='example: john@mail.com' />
                <input
                    name='password'
                    type='password'
                    placeholder='8 characters minimum'
                />
                <button>login</button>
            </form>
        </div>
    );
}
Image
Image
Answered by Rafael Almeida
when you fire the request from the CLIENT, the browser will automatically add the cookies into this request. then in the next server you need to grab the cookie from the request using next/cookies and then add this cookie in the fetch request to your nest server. like this:
const token = cookies().get('token')
const req = await fetch('...', { 
  headers: {
    Cookie: `token=${token}`
  }
})

or if you dont mind sending the entire client headers:
const req = await fetch('...', { headers: headers() })
View full answer

26 Replies

Avatar
MinskinOP
//page.tsx (/users in next.js)
import axios from 'axios';
import { cookies } from 'next/headers';

export default async function () {


    async function getUserList() {
        'use server';

        const response = await axios('http://127.0.0.1:8080/users?offset=0&limit=10',{
            method:'GET',
            withCredentials:true
        })

        console.log(response);
    }

    let data = getUserList()

    // const userList = data.map((element: any) => {
    //     return (
    //         <ul>
    //             <li>{element.fullName}</li>
    //             <li>{element.gender}</li>
    //         </ul>
    //     );
    // });

    return <div className='list'>Hello this is rendred from server</div>;
}
cookie extraction from nest.js server doesn't get any cookie
Image
response from nest.js server
Image
Avatar
MinskinOP
what do you mean by add the cookie manually? isn't cookie supposed to be automatic..?
Avatar
only on the browser, you are making the fetch call in your server. the server doesn't have any cookies info, so thats why the credentials flag doesn't do anything
the easiest way to forward the cookies in the server fetch call is to replicate the headers from the request: fetch(..., { header: headers() })
but I prefer to only forward the cookies to keep the request cleaner
Avatar
MinskinOP
so I have looked around google about what you said earlier, it does make sense since the server action is separated from the browser, it shouldn't have had any access to the browser cookie. So how do I forward the cookie to the request then?
I can only find a stackoverflow answer that add a cookie to a function but they didn't give away how the function load that cookie to the request...
Avatar
@Minskin I can only find a stackoverflow answer that add a cookie to a function but they didn't give away how the function load that cookie to the request...
Avatar
when you fire the request from the CLIENT, the browser will automatically add the cookies into this request. then in the next server you need to grab the cookie from the request using next/cookies and then add this cookie in the fetch request to your nest server. like this:
const token = cookies().get('token')
const req = await fetch('...', { 
  headers: {
    Cookie: `token=${token}`
  }
})

or if you dont mind sending the entire client headers:
const req = await fetch('...', { headers: headers() })
Answer
Avatar
this is written with fetch but you can adapt it to axios, it should be very similar
Avatar
MinskinOP
alright, I will implement it right away
wish me luck
Avatar
MinskinOP
async function getUsers() {
        'use server';

        const token = cookies().getAll('access_token')[0];
        

        const response = await fetch(
            'http://127.0.0.1:8080/users?offset=0&limit=10',
            {
                method: 'GET',
                headers: {
                    Cookie: `access_token=${token.value}`
                },
            },
        );

        return response;
    }

    let data = await getUsers();


 {
    aborted: false,
    rangeRequested: false,
    timingAllowPassed: true,
    requestIncludesCredentials: true,
    type: 'default',
    status: 200,
    timingInfo: {
      startTime: 177798.5435,
      redirectStartTime: 0,
      redirectEndTime: 0,
      postRedirectStartTime: 177798.5435,
      finalServiceWorkerStartTime: 0,
      finalNetworkResponseStartTime: 0,
      finalNetworkRequestStartTime: 0,
      endTime: 0,
      encodedBodySize: 2,
      decodedBodySize: 2,
      finalConnectionTimingInfo: null
    },
    cacheState: '',
    statusText: 'OK',
    headersList: HeadersList {
      cookies: null,
      [Symbol(headers map)]: [Map],
      [Symbol(headers map sorted)]: null
    },
    urlList: [ URL {} ],
    body: { stream: undefined, length: undefined, source: undefined }
  },
  [Symbol(headers)]: HeadersList {
    cookies: null,
    [Symbol(headers map)]: Map(9) {
      'x-powered-by' => [Object],
      'access-control-allow-origin' => [Object],
      'access-control-allow-credentials' => [Object],
      'content-type' => [Object],
      'content-length' => [Object],
      'etag' => [Object],
      'date' => [Object],
      'connection' => [Object],
      'keep-alive' => [Object]
    },
    [Symbol(headers map sorted)]: null
  }
}
got status 200, but there is no data...
token also extracted successfully in the nestjs
Image
Avatar
MinskinOP
anw thank you for your support and answer
will look into the solution to another problem later
but your solution does work and it give me status 200, just need to figured out why it doesn't return data as expected
:100vercel:
okay solved using axios, rather than fetch
thank you so much @Rafael Almeida
:heartvercel:
Avatar
no problem, glad you got it working :blobthumbsup: