12

I manage to update my session serverside, with new user data, but event after assigning it to my session object in [...nextauth.js], my session client side remains the old one. It doesn't refresh, event if I use getSession().

This code works for the back-end :

callbacks.session = async function session({ session, token }) {
  // we can fetch info from back end here to add it to the session   
  session.user = token.user;
  session.jti = token.jti;

  // If user is logged, we refresh his session
  if (token?.user?.id) {
    const url = routes.api.entities.shop.get.byId.build(token?.user?.id);
    let apiResp = await axios.get(url, {});
    session.user = { ...apiResp.data };
    token.user = { ...apiResp.data };
  }

  return session;
};

How can I refresh the session in front-end ?

Baldráni
  • 5,332
  • 7
  • 51
  • 79
Yoann Buzenet
  • 651
  • 2
  • 5
  • 12

5 Answers5

33

UPDATE 2023: There is now an official way to do it as of v4.22.1. See here and the updated docs

You now get an update function like this:

  const { update } = useSession();

PREVIOUS ANSWER:

There is no easy official way to do it, it is still in discussion among contributors.

That said, there is a way. Next-auth does refresh session if you click on another tab, then on the one of your app. It happens, it is a javascript event we can reproduce.

So just define a method to do it :

const reloadSession = () => {
  const event = new Event("visibilitychange");
  document.dispatchEvent(event);
};

Call it, and .. you're done. Session did refresh.

reloadSession();

For more information, this behaviour comes from this part of the code

Abe Caymo
  • 193
  • 7
Yoann Buzenet
  • 651
  • 2
  • 5
  • 12
6

Using the hack of simulating a tab switch does not works anymore in the v4.

What you could do is to update the callback to session?update.

const createOptions = (req) => ({
  // ...
  callbacks: {
    async jwt({ token, ...params }) {
      if (req.url === "/api/auth/session?update") {
          const response = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/users/get/${token.email}`);
          const newUser = await response.json();
          token.hasAcceptedTerms = newUser.hasAcceptedTerms;
      }
      return token;
    },
    async session({ session, token }) {
        if (session.user != null && token.hasAcceptedTerms != null) {
            session.user.hasAcceptedTerms = token?.hasAcceptedTerms;
        }

        return Promise.resolve(session);
     },
  },
});

export default async (req, res) => {
  return NextAuth(req, res, createOptions(req));
};

Then in your client you can do a call

  await axios.get('/api/auth/session?update');

Tribute goes to this answer on github.

Baldráni
  • 5,332
  • 7
  • 51
  • 79
4

Just in case that anyone needs this. Here it is how to update the session when you make a change.

On your component you will do:

import { useSession } from "next-auth/react";
...

const {data: session, update: sessionUpdate} = useSession()
...

function handleUpdateSession() {
  sessionUpdate({
    info: //Your info here...
  })
}

And in your [...nextauth] you do something like:

callbacks: {
    jwt({ token, trigger, session }) {
      if(trigger === 'update') {
        if(session.info) {
          // update your token whatever you like
        }
      }
      
      return token;
    }
}

trigger are triggered in 3 scenarios (Signin, SignUp and Update) and session receives what you send on your update call. In this case it will be just an object like:

{
  info: some info here
}
2

The update() method is now available.

The useSession() hook exposes a update(data?: any): Promise<Session | null> method that can be used to update the session, without reloading the page.
You can optionally pass an arbitrary object as the first argument, which will be accessible on the server to merge with the session object.
If you are not passing any argument, the session will be reloaded from the server. (This is useful if you want to update the session after a server-side mutation, like updating in the database.)

import { useSession } from "next-auth/react"

export default function Page() {
  const { data: session, status, update } = useSession()

  if (status === "authenticated") {
    return (
      <>
        <p>Signed in as {session.user.name}</p>
        
        {/* Update the value by sending it to the backend. */}
        <button onClick={() => update({ name: "John Doe" })}>
          Edit name
        </button>
        {/*
          * Only trigger a session update, assuming you already updated the value server-side.
          * All `useSession().data` references will be updated.
          */}
        <button onClick={() => update()}>
          Edit name
        </button>
      </>
    )
  }

  return <a href="/api/auth/signin">Sign in</a>
}
Ahmed Sbai
  • 10,695
  • 9
  • 19
  • 38
0

Just incase anyone comes here to figure out how to get the session info into an analytics platform like Heap, I ended up creating a component that uses useSession.

export default function HeapAnalytics() {
  const { data: session, status } = useSession();
  const [scriptLoaded, setScriptLoaded] = useState(false);

  useEffect(() => {
    if (status === "authenticated" && window.heap) {
      console.info("Identifying Heap User...");
      window.heap.identify(session.user.email);
      window.heap.addUserProperties({
        name: session.user.name,
        userId: session.user.id,
      });
    }
  }, [scriptLoaded, session, status]);

  const scriptReady = () => {
    if (window.heap) {
      setScriptLoaded(true);
    }
  };

  return (
    <Script
      id="heap-analytics"
      strategy="afterInteractive"
      dangerouslySetInnerHTML={{
        __html: `
      window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=document.createElement("script");r.type="text/javascript",r.async=!0,r.src="https://cdn.heapanalytics.com/js/heap-"+e+".js";var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(r,a);for(var n=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","resetIdentity","removeEventProperty","setEventProperties","track","unsetEventProperty"],o=0;o<p.length;o++)heap[p[o]]=n(p[o])};
      heap.load("${config.tags.HEAP_ANALYTICS}");
      `,
      }}
      onReady={scriptReady}
    />
  );
}

Full documentation: https://samelogic.com/blog/heap-analytics-in-nextjs-with-nextauthjs

Shawn Mclean
  • 56,733
  • 95
  • 279
  • 406