Home > Enterprise >  How to manage localStorage with nextJS?
How to manage localStorage with nextJS?

Time:07-11

Usually I make applications with Django and React, using JWT for authentication. I am testing nextJS. I can't manage the JWT authentication because I can't access the localstorage to get my 2 tokens (access refresh).

With react I use axios.js:

import axios from 'axios';
import { baseURL } from './const/urls';

const axiosInstance = axios.create({
  baseURL: baseURL,
  timeout: 5000,
  headers: {
    Authorization: localStorage.getItem('access_token')
      ? 'JWT '   localStorage.getItem('access_token')
      : null,
    'Content-Type': 'application/json',
    accept: 'application/json',
    'Cache-Control': 'no-cache',
    Pragma: 'no-cache',
    Expires: '0'
  }
});

axiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    const originalRequest = error.config;

    // Prevent infinite loops
    if (
      error.response.status === 401 &&
      originalRequest.url === '/token/refresh/'
    ) {
      window.location.href = '/login/';
      return Promise.reject(error);
    }

    if (
      error.response.data.code === 'token_not_valid' ||
      error.response.status === 401 ||
      error.response.statusText === 'Unauthorized'
    ) {
      const refreshToken = localStorage.getItem('refresh_token');

      if (refreshToken) {
        const tokenParts = JSON.parse(atob(refreshToken.split('.')[1]));

        // exp date in token is expressed in seconds, while now() returns milliseconds:
        const now = Math.ceil(Date.now() / 1000);

        if (tokenParts.exp > now) {
          return axiosInstance
            .post('/token/refresh/', { refresh: refreshToken })
            .then((response) => {
              localStorage.setItem('access_token', response.data.access);
              localStorage.setItem('refresh_token', response.data.refresh);

              axiosInstance.defaults.headers['Authorization'] =
                'JWT '   response.data.access;
              originalRequest.headers['Authorization'] =
                'JWT '   response.data.access;

              return axiosInstance(originalRequest);
            })
            .catch((err) => {
              console.log(err);
            });
        } else {
          console.log('Refresh token is expired', tokenParts.exp, now);
          window.location.href = '/Login/';
        }
      } else {
        console.log('Refresh token not available.');
        window.location.href = '/Login/';
      }
    }

    // specific error handling done elsewhere
    return Promise.reject(error);
  }
);

export default axiosInstance;

But It doesn't work with nextJS. localStorage or window.localStorage undifined. I understand that it doesn't work because it tries to execute the code on the server side. How to force it to use the client side code only? I saw that I could useEffect but I don't understand how to use it in my case.

CodePudding user response:

Use (typeof window === 'undefined') condition to check if you can access window which you will be able to on the client side but won't be on the server side. I use it often so it works. For instance you could do something like this depending on the condition check:

// save to storage
export const saveToStorage = (key, value) => {
    if(typeof window !== 'undefined') {
        return window.localStorage.setItem(key, value);
    }
}

// get from storage
export const getFromStorage = (key) => {
    if (typeof window !== 'undefined') {
        return window.localStorage.getItem(key);
    }
}

CodePudding user response:

NextJS can run on nodeJS (server) where the window is not available, you need to make sure it will only run on the client-side (might be by checking if window is not undefined) but you need to be aware that your requests won't work on the server-side.

I recommend saving your token on cookies if you need SSR.

if (typeof window !== "undefined") {
  // Client-side-only code
}
  • Related