Next.js Discord

Discord Forum

After login, how to get stored cookie/localStorage data into server component?

Answered
Sloth bear posted this in #help-forum
Open in Discord
Sloth bearOP
Thanks @Ray for helping me out in my last question about Login with server component.

Now I am able to store the tokens I need, idToken, personId into cookies or localStorage from the login-form client component. Next I redirect to /postings, which loads up my postings/page server component.

And that page component needs to get a fetch from another server component fetchPostings.

I'm able to set the cookies and localStorage, but unable to fetch the required tokens from page and send them into fetchPostings to make the next call.

I read that js-cookies would let me solve that, but the tokens are undefined, I tried cookies from next/headers, but got an error saying I can't do that.

Is there another way to pass those tokens after login into server components for another call?

The only other thing I can think of is while I'm in the login server component, to go ahead and make that getUserPostings call there, then passing everything into the login-form client component to pass on.

## My postings/page (server component)
import Cookies from 'js-cookie';
// import { cookies } from 'next/headers';

import PostingsList from '@/components/postings/postings-list';
import fetchPostings from '@/services/postings';

export default async function Postings() {
  let postingsData = [];
  let errorMessage;
  const cookies = new Cookies();
  // const cookieStore = cookies();

  const idToken = cookies.get('idToken') ?? '';
  const personId = cookies.get('personId') ?? '';

  // console.log('idToken', idToken);
  // console.log('personId', personId);


  try {
    postingsData = await fetchPostings(idToken, personId);
    console.log('postingsData', postingsData);
  } catch (error: any) {
    errorMessage = error.message;
  }

  return (
    <>
      <PostingsList postings={postingsData} errorMessage={errorMessage} />
    </>
  );
};


## My fetchPostings (server component)
'user server';
import { API_GET_POSTINGS, METHOD_GET } from '@/constants';

const fetchPostings = async (idToken: string, personId: string) => {

  const generateSearchParams = () => {
    const params = new URLSearchParams();
    params.append('posting-state', 'all');
    params.append('page', '1');
    params.append('page-size', '5');
    return params;
  };

  const params = generateSearchParams();
  try {
    const response = await fetch(API_GET_POSTINGS(personId || '', params), {
      ...METHOD_GET,
      headers: {
        Authorization: idToken || '',
      },
    });

    if (!response.ok) {
      throw new Error(`Error fetching postings: ${response.statusText}`);
    }

    const data = await response.json();
    console.log('fetching postings data:', data);
    return data;
  } catch (error: any) {
    console.error(error);
    return error;
  }
};

export default fetchPostings;


## my login-form (client component)
Where I save the cookies/localStorage

// ? store idToken in redux
   if (idToken) {
     cookies().set('idToken', idToken);
     localStorage.setItem('idToken', idToken);
   }
Answered by Ray
try this
import { cookies } from 'next/headers';

 const cookieStore = cookies();
 const idToken = cookieStore.get('idToken')?.value ?? '';
 const personId = cookieStore.get('personId')?.value ?? '';
View full answer

42 Replies

@Sloth bear Thanks <@743561772069421169> for helping me out in my last question about Login with server component. Now I am able to store the tokens I need, idToken, personId into cookies or localStorage from the login-form client component. Next I redirect to /postings, which loads up my postings/page server component. And that page component needs to get a fetch from another server component fetchPostings. I'm able to set the cookies and localStorage, but unable to fetch the required tokens from page and send them into fetchPostings to make the next call. I read that js-cookies would let me solve that, but the tokens are undefined, I tried cookies from next/headers, but got an error saying I can't do that. Is there another way to pass those tokens after login into server components for another call? The only other thing I can think of is while I'm in the login server component, to go ahead and make that getUserPostings call there, then passing everything into the login-form client component to pass on. ## My postings/page (server component) import Cookies from 'js-cookie'; // import { cookies } from 'next/headers'; import PostingsList from '@/components/postings/postings-list'; import fetchPostings from '@/services/postings'; export default async function Postings() { let postingsData = []; let errorMessage; const cookies = new Cookies(); // const cookieStore = cookies(); const idToken = cookies.get('idToken') ?? ''; const personId = cookies.get('personId') ?? ''; // console.log('idToken', idToken); // console.log('personId', personId); try { postingsData = await fetchPostings(idToken, personId); console.log('postingsData', postingsData); } catch (error: any) { errorMessage = error.message; } return ( <> <PostingsList postings={postingsData} errorMessage={errorMessage} /> </> ); }; ## My fetchPostings (server component) 'user server'; import { API_GET_POSTINGS, METHOD_GET } from '@/constants'; const fetchPostings = async (idToken: string, personId: string) => { const generateSearchParams = () => { const params = new URLSearchParams(); params.append('posting-state', 'all'); params.append('page', '1'); params.append('page-size', '5'); return params; }; const params = generateSearchParams(); try { const response = await fetch(API_GET_POSTINGS(personId || '', params), { ...METHOD_GET, headers: { Authorization: idToken || '', }, }); if (!response.ok) { throw new Error(`Error fetching postings: ${response.statusText}`); } const data = await response.json(); console.log('fetching postings data:', data); return data; } catch (error: any) { console.error(error); return error; } }; export default fetchPostings; ## my login-form (client component) Where I save the cookies/localStorage // ? store idToken in redux if (idToken) { cookies().set('idToken', idToken); localStorage.setItem('idToken', idToken); }
try this
import { cookies } from 'next/headers';

 const cookieStore = cookies();
 const idToken = cookieStore.get('idToken')?.value ?? '';
 const personId = cookieStore.get('personId')?.value ?? '';
Answer
Sloth bearOP
Ok yes I did get that to work now thanks 🙂

const personId = allCookies.find(cookie => cookie.name === 'personId');
  const idToken = allCookies.find(cookie => cookie.name === 'idToken');
I'm running into this error tho

Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.

But need to fix something and try again
I think you need
const personId = allCookies.find(cookie => cookie.name === 'personId') ?? '';
  const idToken = allCookies.find(cookie => cookie.name === 'idToken') ?? '';
Sloth bearOP
Yes thats what I have, but now I keep running into this

Error: 
  × You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/
  │ react-essentials#server-components


I'm using cookies from next/headers in my login client component, going to try use js-cookies there again.

Just strange I have to use 2 different cookie libs
Sloth bearOP
yes I do, but I can't get to localStorage from my server component, or at least, I don't know how
if so, just read from there in the client component, so you don't need to use cookies()
Sloth bearOP
But I have to make all my calls from server components now
The reason is
1) we hide the API key
2) avoid CORs issues
So I login, I save the cookies and localStorage
Sloth bearOP
Next I route to /postings, and I need to GET postings, but with those vars I saved
Oh no ignore the login component, I'm using cookie logic there to SAVE the cookies
sec going to try again
Willing to screenshare? 😄 I can pay for some time via CashApp or Bitcoin
liveshare?
Sloth bearOP
yeah
discord call or google meet
vscode extension lol
Sloth bearOP
oh
ok I have it installed how do I use it?
ah crap I'm hiding the status bar 1 sec
can you see my other tabs? or just this one?
try again
fetching
Sloth bearOP
same error

Uncaught Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
Sloth bearOP
forbidden I'll login again real quick
oh wait, no more error now
the Postings call is forbidden but app doesn't break hmm
 ⨯ Error: Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.
    at stringify (<anonymous>)
queryString: ?posting-state=all&page=1&page-size=5
response.status 403
Error: Error fetching postings: Forbidden
ok I still see Forbidden, so it may be our Backend issue
but ok so that Only Plain Objects error, I don't get that message in the browser anymore, only in the terminal, which is better?
Thanks! Getting closer
@Sloth bear the Postings call is forbidden but app doesn't break hmm
don't return the error directly, it is not serializable by react
Sloth bearOP
gotcha, throw it instead
Appreciate it
Sloth bearOP
This is solved now, again thanks! 😄