skip to Main Content

I’m having connection problems with my api in nodejs after I created a service layer in my react app.

This is the folder structure:

index.html
└── src
    ├── Components
    │   ├── Pages
    │   │   ├── Home.jsx
    │   │   ├── Provider.jsx
    │   │   ├── login.jsx
    │   │   ├── signup.jsx
    │   │   ...
    │   ├── ProviderComponents
    │   │   ├── WorkListProvider.jsx
    │   │   ...
    ├── Context
    │   └── UserContext.jsx
    └── Services
        └── Api
            ├── authService.js
            ├── config
            │   └── axiosConfig.js
            └── providerService.js

src/Service/Api/config/axiosConfig.js

import axios from "axios";
import Cookies from "js-cookie";
const token = Cookies.get("token");

// create axios instance
export const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  headers: {
    Authorization : `Bearer ${token}`
  },
});


const errorHandler = (error) => {
  const statusCode = error.response?.status;

  if (statusCode && statusCode !== 401) {
    throw error
  }

  return Promise.reject(error);
};


api.interceptors.response.use(undefined, (error) => {
  return errorHandler(error);
});

src/Service/Api/providerServices

import { api } from "./config/axiosConfig";

export const providerService = {
  getJobs: async () => {
    const response = await api.request({
      url: "/provider/myJobs",
      method: "GET",
    });
    return response.data;
  },
  // other services instances
}

call to providerService in src/Components/providerComponents/WorkListProvider.jsx:

useEffect(() => {
  providerService
    .getJobs()
    .then((workList) => {
      setWorkData(workList);
    })
    .catch((error) => {
      console.error(error);
    });
}, []);

src/Service/Api/authService:

import { api } from "./config/axiosConfig";

export const authService = {
  login: async (data) => {
    const response = await api.request({
      url: `/login`,
      data,
      method: "POST",
    });
    console.log(response.data)
    return response.data;
  },
  // other instances services
};

use authServices.login() in Login.jsx

const handleSubmit = (e) => {
  e.preventDefault();
  authService
    .login(values)
    .then((response) => {
      Cookies.set("token", response.token, { expires: 1 });
      changeLoggedIn(true);
      navigate("/");
    })
    .catch((error) => setErrorMessage(error.response.data.data.error));
};

When I login, it returns a 500 error (internal server error) with a ‘jwt malformed’ message. But when I refresh the page, it’s fixed and i get a correct response from the server.

2

Answers


  1. Think about the timing of this…

    const token = Cookies.get("token");
    

    How can you use Cookies.get("token") before it is set? Secondly, you don’t want or need an Authorization header for logging in.

    I would make two changes…

    1. Provide a separate Axios instance for auth requests that excludes the authorization header
    2. Move the authorization header to an interceptor so it is calculated at runtime rather than build time.
    const baseURL = import.meta.env.VITE_API_URL;
    
    export const api = axios.create({ baseURL });
    export const authApi = axios.create({ baseURL });
    
    api.interceptors.request.use((config) => ({
      ...config,
      headers: {
        Authorization: `Bearer ${Cookies.get("token")}`,
        ...config.headers,
      },
    }), null, { synchronous: true });
    

    In authService, use the authApi instance instead

    import { authApi } from "./config/axiosConfig";
    
    export const authService = {
      login: async (data) => {
        const { data } = await authApi.post("/login", data);
        console.log("[authService#login]", data)
        return data;
      },
      // other instances services
    };
    
    Login or Signup to reply.
  2. The issue you’re experiencing could be related to the timing of the token retrieval and the request being sent. When you log in, the token is retrieved from the cookies, but it’s possible that the API request is being sent before the token is available. This can result in a "jwt malformed" error because the token is either missing or invalid.

    To fix this issue, you can modify your code to ensure that the token is available before sending the request. One approach is to use a promise-based approach to retrieve the token and then make the API request. Here’s an updated version of your code that implements this approach:

    // src/Service/Api/config/axiosConfig.js
    import axios from "axios";
    import Cookies from "js-cookie";
    
    // Create an axios instance
    export const api = axios.create({
      baseURL: import.meta.env.VITE_API_URL,
    });
    
    const errorHandler = (error) => {
      const statusCode = error.response?.status;
    
      if (statusCode && statusCode !== 401) {
        throw error;
      }
    
      return Promise.reject(error);
    };
    
    api.interceptors.response.use(undefined, (error) => {
      return errorHandler(error);
    });
    
    // Retrieve the token from cookies
    const getToken = () => {
      return Cookies.get("token");
    };
    
    // Add token to the request headers
    api.interceptors.request.use((config) => {
      const token = getToken();
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    });
    
    // ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search