paint-brush
Having Trouble Accessing Your Session and Access Token Using Supabase, Nuxt and Vue3? Try This!by@thexumaker
1,378 reads
1,378 reads

Having Trouble Accessing Your Session and Access Token Using Supabase, Nuxt and Vue3? Try This!

by David XuMarch 9th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Use Vue lifecycle methods when possible to save you time and headaches from debugging.
featured image - Having Trouble Accessing Your Session and Access Token Using Supabase, Nuxt and Vue3? Try This!
David Xu HackerNoon profile picture


I was recently working on a side project in my free time when I ran into a really weird issue with Supabase and, specifically the @nuxtjs/supabase client library.


What I was attempting to do was to make an API call to get data to populate a profile page as soon as the user loaded the page. We had set up the backend API to require a basic auth token. The code looked something like this:


<script setup>
const client = useSupabaseAuthClient();

const session = await client.auth.getSession();

await useFetch(`${API_URL}/profile/:user_id`, {
  headers: {
    Authorization: `Bearer ${session.data.session.access_token}`,
  },
  onResponse({ request, response, options }) {
    console.log(response);
    //do other stuff
  },
});


What went wrong?

Rather than console logging out a 200 we got an error before we could even make a request.


TypeError: Cannot read properties of null (reading 'access_token')


Well that’s weird why would the client.auth.getSession() not have a session?


What was weirder was just console.logging it out would also give us the same error


const client = useSupabaseAuthClient();
const session = await client.auth.getSession();
console.log(session.data.session.access_token);


What if we tried this?


const client = useSupabaseAuthClient();
const session = await client.auth.getSession();
console.log(session.data.session?.access_token);


Funny enough this actually worked. It would log out the correct access token. It was at this moment I realized what was wrong. But I wanted to confirm if my thinking was correct with one last experiment.


I decided to wrap the entire fetch call with a try/catch block


try {
  const { data: fetchedProfileData, refresh } = await useFetch(
    `${API_URL}/profile/:user_id`,
    {
      headers: {
        Authorization: `Bearer ${
          (
            await client.auth.getSession()
          ).data.session.access_token
        }`,
      },
      onResponse({ request, response, options }) {
        console.log(response);
      },
    }
  );
} catch (e) {
  console.error(e);
}


It worked but didn’t?

So if you know the answer to this problem, it shouldn’t surprise you that the page loaded fine and the data was logged out properly. But at the same time there was also a second console.log message.

TypeError: Cannot read properties of null (reading 'access_token')
...
//Access token logged here:


How could we be getting an error that the session is null but then log the access token at the same time?


Answer: Vue lifecycle methods


So I want to say the core problem was that for whatever reason, a large part of client.auth.getSession() is not setup until after things are rendered in the lifecycle. And if you don’t explicitly state a lifecycle method our API call would run before the initial render. Whether that’s intentional or not I’m not exactly sure. The API call works with a try/catch block because on that initial load the API call errors out but as we continue our way along the Vue lifecycle the API call gets called again and this time around client.auth.getSession() is set properly and we can go on our merry way.


You can use the try/catch block but the better and cleaner way to do things is to use a lifecycle hook. In this instance onMounted or onBeforeMount works well. Docs here



onMounted(async () => {
  const session = await client.auth.getSession();
  await useFetch(`${API_URL}/profile/:user_id`, {
    headers: {
      Authorization: `Bearer ${session.data.session.access_token}`,
    },
    onResponse({ request, response, options }) {
      console.log(response);
      //do other stuff
    },
  });
});


Voila, now the errors are gone and we have our data. With this you can also trigger the error if we use the onServerPrefetch hook because we’re forcing our fetch to be called before the component instance is even rendered on the server


//This will error
onServerPrefetch(async () => {
  const session = await client.auth.getSession();
  const x = await useFetch(`${API_URL}/profile/:user_id`, {
    headers: {
      Authorization: `Bearer ${session.data.session.access_token}`,
    },
    onResponse({ request, response, options }) {
      console.log(response);
      //do other stuff
    },
  });
});


Conclusion

I hope this helps anyone else who ran into this issue with Supabase and Nuxt and hopefully someone reads this and can give a better explanation or confirm my suspicions in the comments since I’m mostly a backend developer and I only touch frontend code in my free time.