How to refresh feathers.js token with next-auth and next.js setup

Viewed 308

Whenever a user logins in successfully, this is a sample of the server response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyJ9.eyJpYXQiOjE2NDY1MDc5ODEsImV4cCI6MTY0NzExMjc4MSwiYXVkIjoiaHR0cHM6Ly95b3VyZG9tYWluLmNvbSIsImlzcyI6ImZlYXRoZXJzIiwic3ViIjoiMiIsImp0aSI6ImVlMTExOGNhLTVhOGEtNGJiMC1iMDRkLTdlMTUzM2RlMmQ4YyJ9.T5gBB9CYulofSa_rTKP23wNG5YUMyEKtqQIFG0X5RX4",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwidXNlciI6eyJpZCI6MiwiZmlyc3QiOiJKYW5lIiwibGFzdCI6IkRvZSIsImVtYWlsIjoiaGVsbG8xQGZlYXRoZXJzanMuY29tIiwicGhvbmUiOiIwNzk1ODU3MTM5IiwibG9jYXRpb24iOiJOYWlyb2JpIiwiaXNWZXJpZmllZCI6MCwiaXNBZG1pbiI6MCwicm9sZXMiOiJ1c2VyIiwiY29uZmlybWVkRW1haWwiOjEsImNvbmZpcm1lZFBob25lIjoxLCJjb25maXJtYXRpb25JZCI6IiIsImRlYWN0aXZhdGVkIjowLCJsb2dpbnMiOjAsImJpbyI6IiIsIndlYnNpdGUiOiIiLCJzb2NpYWwiOiIiLCJ1cGxvYWRJZCI6bnVsbCwiY3JlYXRlZEF0IjoiMjAyMi0wMy0wNVQxNzo0NDowNS4wMDBaIiwidXBkYXRlZEF0IjoiMjAyMi0wMy0wNVQxNzo0NDowNS4wMDBaIn0sImlhdCI6MTY0NjUwNzk4MSwiZXhwIjoxNjQ3MTEyNzgxLCJhdWQiOiJodHRwczovL3lvdXJkb21haW4uY29tIiwiaXNzIjoiZmVhdGhlcnMiLCJzdWIiOiIyIiwianRpIjoiNzJjMzZjMWQtZTQwYy00NTE4LTg2NDctYjczNDdiNWFjMzMxIn0.Ba_LBdDBYf5rcTWcR6AaR_uAyqHxpHg3rbqEii8h78I",
  "authentication": {
    "strategy": "local"
  },
  "user": {
    "id": 2,
    "first": "Jane",
    "last": "Doe",
    "email": "hello1@feathersjs.com",
    "isAdmin": 0,
    "roles": "user",        
    "createdAt": "2022-03-05T17:44:05.000Z",
    "updatedAt": "2022-03-05T17:44:05.000Z"
  }
}

Once the feathersjs accessToken expires, the site hits the api with the refreshToken, and gets a new one without the user's intervention.

I can't however include the refreshToken as there in no way to pass it into callback options of the [...nextauth].js file. How do I go about this?

EDIT: I managed to pass the refresh token, together with the accessToken like so:

// [...nextauth.js]
const providers = [
  CredentialsProvider({
    name: "Credentials",
    authorize: async (credentials) => {
      const { email, password, refreshToken = null } = credentials;          
      try {
        if (refreshToken) {
          console.log("REFRESHING TOKEN");
          const { data } = await axios.post(
            API_AUTH,
            {
              strategy: "local",
              action: "refresh",
              refresh_token: refreshToken,
            },
            {
              headers: {
                accept: "*/*",
                "Content-Type": "application/json",
              },
            }
          );

          const token = JSON.stringify({
            token: data.accessToken,
            refresh: data.refreshToken,
          });

          const user = {
            name: data.user.first,
            email: data.user.email,
            image: "/hkgghlk",
            token,
          };

          if (user) {
            return user;
          }
        } else {
          console.log("LOGGING IN");
          const { data } = await axios.post(
            API_AUTH,
            { strategy: "local", email, password },
            {
              headers: {
                accept: "*/*",
                "Content-Type": "application/json",
              },
            }
          );

          const token = JSON.stringify({
            token: data.accessToken,
            refresh: data.refreshToken,
          });

          const user = {
            name: data.user.first,
            email: data.user.email,
            image: "/hkgghlk",
            token,
          };

          if (user) {
            return user;
          }
        }
      } catch (e) {
        const errorMessage = e.response.data.message;
        throw new Error(errorMessage);
      }
    },
  }),
];

const callbacks = {
  async jwt({ token, user, account, profile, isNewUser }) {
    if (user) {
      const { token: access, refresh } = JSON.parse(user.token);
      token.accessToken = access;
      token.refreshToken = refresh;
    }
    return token;
  },

  async session({ session, token }) {
    session.refreshToken = token.refreshToken;
    return session;
  },
};

Now I know this is a hack. Is there a 'proper' way of doing this? I don't want the refreshToken saved in the session as this is not ideal.

If interested in how feathersjs creates a refresh token, here is how.

0 Answers
Related