JWT Token Refresh

Asked

Viewed 1,119 times

1

I have an API that issues a JWT token with a maximum validity of 2h per token, after which it is no longer processed by my application. I need that every time this token is expired, a new token is generated.

However, how to implement a JWT token refresh function in some authentication context?

I got something similar using "useEffect" in my authentication context, but a new token is only generated after the entire application is restarted. I would like the function to be checked always when changing route (React-router-dom V6).

I leave below all my context, and also the repository in which all the code is hosted.

import React, { createContext, useState, useEffect, useContext } from 'react';
import ContextDevTool from 'react-context-devtool';
import decode from 'jwt-decode';
import api from '../services/api';

import Loading from '../pages/Loading';

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [authenticated, setAuthenticated] = useState(false);
  const [token, setToken] = useState('');
  const [expiredToken, setExpiredToken] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadStorage() {
      const storagedToken = localStorage.getItem('token');

      if (storagedToken) {
        const decodedToken = decode(storagedToken);

        await new Promise((resolve) => setTimeout(resolve, 2000));

        // if token expiry date is lower than actual date
        if (decodedToken.exp <= Math.floor(new Date() / 1000)) setExpiredToken(true);

        setAuthenticated(true);
        setToken(decodedToken);
        api.defaults.headers['Authorization'] = `Bearer ${storagedToken}`;
      }

      setLoading(false);
    }

    loadStorage();
  }, []);

  async function Login(username, password) {
    const { data } = await api.get(`login?usuario=${username}&senha=${password}`);
    const decodedToken = decode(data.token);

    setAuthenticated(true);
    setToken(decodedToken);
    api.defaults.headers['Authorization'] = `Bearer ${data.token}`;
    localStorage.setItem('token', data.token);
  }

  async function refreshToken() {
    console.log('token refreshed');
  }

  async function Logout() {
    localStorage.clear();
    setAuthenticated(false);
    setToken('');
  }

  while (loading) return <Loading />;

  if (expiredToken) {
    refreshToken();
    setExpiredToken(false);
  }

  return (
    <AuthContext.Provider value={{ authenticated, token, expiredToken, Login, Logout }}>
      <ContextDevTool context={AuthContext} id="auth" displayName="Authentication Context" />
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);

  return context;
}

https://github.com/medeiroshudson/React-Context

From now on, thank you.

1 answer

2

Hello I suggest to make a Privateroute, so to each route called in the Routes would go by that Privateroute and there in you would call a method to renew the token.

import { Route, Redirect } from "react-router-dom";

import RenovaToken from "./RenovaToken.js";
import Loading from "./Loading";

const PrivateRoute = ({ children, ...rest }) => {
 return (
     <Route
         {...rest}
         render={({ location }) => {
             return RenovaToken() ? (
                 children
             ) : (
                 <Redirect
                     to={{
                         pathname: "/login",
                         state: { from: location },
                     }}
                 />
             );
         }}
     />
 );
};
export default PrivateRoute;

And in Renovatoken you create the function that returns whether it has been updated or not.

In the file you call the routes you import that Privateroute and calls the routes so

<PrivateRoute exact path="/home">
    </Home>
</PrivateRoute>
  • 1

    Let me get this straight... This function will redirect the user to login if the token is expired?

  • @Hudsonright depends on the function you created that renews the token, if there is any reason why the token cannot be renewed, you redirect to some error page, then just exchange the /login for a component. If there is no reason just take the if and call the direct function and then Children

Browser other questions tagged

You are not signed in. Login or sign up in order to post.