1

So basically I'm working on a nextjs app which uses authentication. I have a 2 functions which I run on every page load. The first checks if jwt cookies exist and calls another function to validate the tokens if they don't exist. This function is ran from wrapper.getServerSideProps and is passed in the context as ctx. This function works as intended.

export const checkServerSideCookie = (ctx) => {
   const access = getCookie("access", ctx.req);
   const refresh = getCookie("refresh", ctx.req);
   if (access && refresh) {
      return checkAuthentication(access, refresh);
   } else return { isAuthenticated: false, token: null };
};

The second function is the token validator and this is where the issue arises. I have an object which I intended to update if the validation is successful and leave alone if it isn't. Here is the function

export const checkAuthentication = (access, refresh) => {
   const obj = {
      isAuthenticated: false,
      token: null,
   };
   const body = JSON.stringify({ token: access });
   axios
      .post("http://localhost:8000/api/jwtoken/verify/", body, {
         headers: {
            "Content-Type": "application/json",
         },
      })
      .then((res) => {
         obj.isAuthenticated = true;
         obj.token = access;
      })
      .catch((err) => {
         // call new token function using refresh
         console.log("it doesnt work");
      });
   return obj;
};

The issue is is that the .then does update the object, and when I console.log(obj) in the .then it shows the proper obj to return, however when I return the obj it still holds the initial values of false and null. I don't understand what the issue is. I try doing the return in the .then itself but it throughs this error TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is undefined. What is the issue here? It all seems good but the updated obj isn't returned.

darkstar
  • 829
  • 11
  • 23

2 Answers2

2

axios.post is async, you're returning the obj before it gets filled with data from the api response, you can use async/await to solve that :

export const checkAuthentication = async (access, refresh) => {
  const obj = {
    isAuthenticated: false,
    token: null
  };

  const body = JSON.stringify({ token: access });

  try {
    const res = await axios.post("http://localhost:8000/api/jwtoken/verify/", body, {
      headers: {
        "Content-Type": "application/json"
      }
    });

    obj.isAuthenticated = true;
    obj.token = access;
  } catch (e) {
    // do something with the error
    // call new token function using refresh
    console.log("it doesnt work");
  }

  return obj;
};

usage (checkAuthentication now return a promise ) :

checkAuthentication(a, b).then((obj) => {
  console.log(obj);
});
Taki
  • 17,320
  • 4
  • 26
  • 47
  • In the usage case, would I do "return checkAuthentication(a, b).then(obj => return obj);" in my first function? – darkstar Apr 08 '21 at 22:44
  • no, just `return checkAuthentication(a, b)` and whenever you need to access the `obj` do the `then (obj => { ... })` , in your case : `checkServerSideCookie().then(obj => ...)` – Taki Apr 08 '21 at 22:50
1

When you call checkAuthentication it immediately returns the obj with the default properties. You have an asynchronous operation specified in your function, however you don't wait until it's done. You'd have to rebuild your function the following way:

export const checkAuthentication = (access, refresh) => {
   const obj = {
      isAuthenticated: false,
      token: null,
   };
   const body = JSON.stringify({ token: access });
   return new Promise((resolve, reject) => {
    axios
      .post("http://localhost:8000/api/jwtoken/verify/", body, {
         headers: {
            "Content-Type": "application/json",
         },
      })
      .then((res) => {
         resolve({
           isAuthenticated: true,
           token: access
         })
      })
      .catch((err) => {
         // call new token function using refresh
         console.log("it doesnt work");
         reject();
      });
    });
};

and then call your function the following way:

checkAuthentication(access, refresh)
  .then(console.log)
  .catch(console.log)

You, of course, have multiple options to make your function cleaner, such as by using async/await etc, but this should give you a quick overview of what is wrong.

Keimeno
  • 2,512
  • 1
  • 13
  • 34