Passing auth credentials in nextjs server side api call

30 views Asked by At

I'm using Laravel breeze-next nextjs starter package to create a nextjs app with a backend powered by laravel and protected by sanctum.

Laravel expects a csrf header value and a session cookie. I'm having no problem setting these values in client components and getting data back from laravel using something like this:

async function fetchData(url: string): Promise<Response> {
    let fetch_path = process.env.NEXT_PUBLIC_BACKEND_URL + '/api/' + url
    console.log('fetch data called')

    const options: RequestInit = {
        method: "GET",
        credentials: "include",
        headers: {
            "Accept": "application/json",
            "Referer": process.env.APP_URL,
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
        }
    };

    return await fetch(fetch_path, options);
}

When I try to make an API request in a server component doing something similar it fails every time with a 401:

async function fetchDataServerSide(url: string) {
    'use server'
    let fetch_path = process.env.NEXT_PUBLIC_BACKEND_URL + '/api/' + url

    const options: RequestInit = {
        method: "GET",
        headers: {
            "Accept": "application/json",
            "Referer": process.env.APP_URL,
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
            "X-CSRF-TOKEN": cookies().get('XSRF-TOKEN'),
        }
    };

    return await fetch(fetch_path, options);
}

Note that this is basically exactly what I'm doing with the same calls via Postman, and they work as expected.

Can anyone point out what I'm doing wrong?

2

There are 2 answers

0
Ahmed Abdelbaset On BEST ANSWER

Next.js's cookies().get(key) doesn't return the actual value of the cookie. It returns object of {name: string, value: string}.

async function fetchDataServerSide(url: string) {
    'use server'
    let fetch_path = process.env.NEXT_PUBLIC_BACKEND_URL + '/api/' + url

    const options: RequestInit = {
        method: "GET",
        headers: {
            "Accept": "application/json",
            "Referer": process.env.APP_URL,
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
            "X-CSRF-TOKEN": cookies().get('XSRF-TOKEN').value, // ⬅️⬅️⬅️⬅️
        }
    };

    return await fetch(fetch_path, options);
}
0
user101289 On

Thanks to @Ahmed for the help, he put me on the right track. The full call I needed to make was the following:

async function fetchDataServerSide(url: string): Promise<Response> {
    'use server'
    let fetch_path = process.env.NEXT_PUBLIC_BACKEND_URL + '/api/' + url

    const options: RequestInit = {
        method: "GET",
        headers: {
            "Accept": "application/json",
            "Referer": process.env.APP_URL,
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
            "cookie": "XSRF-TOKEN=" + cookies().get('XSRF-TOKEN').value + ";breezeapi_session="+cookies().get('breezeapi_session').value,
        }
    }

    return await fetch(fetch_path, options);
}

When I dumped the request object in the laravel middleware, the cookie header had been converted into an actual cookie array.