1

I have a function that sends a post request to my backend, it contains the JWT token, then the backend checks if this token is correct. Unfortunately, the isAuthenticated() function only works if I return a Promise. But I want to check now in my ProtectedRoute.tsx if the token was correct. How does this work with a Promise?

isAuthenticated():

import axios from "axios"

let token = localStorage.getItem("jwt-token");

export const isAuthenticated = async (): Promise<boolean> => {
    if (!token) {
        return false;
    } else {
        let tokenCheck = false;
        await axios.post("/api/users/tokencheck", { token: token }).then((res) => {
            if (res.data === "Valid Token" || res.status === 200) {
                tokenCheck = true
            } else {
                tokenCheck = false
            }
        })
        return tokenCheck
    }
}

ProtectedRoute.tsx :

import React from 'react'
import { Redirect, Route } from 'react-router-dom'
import { isAuthenticated } from "./Auth"

interface Props {
    component: React.FC;
    path: string;
}

const ProtectedRoute: React.FC<Props> = (props: Props) => {
    return (
        <React.Fragment>
            {isAuthenticated()
                ? <Route path={props.path} exact component={props.component} />
                : <Redirect to="/" />
            }
        </React.Fragment>
    )
}

export default ProtectedRoute

backend:

export const tokenCheck = (req: Request, res: Response) => {
    let { token } = req.body
    jwt.verify(token!, process.env.JWTSECRET!, (err: any, decoded: any) => {
        if (err) {
            res.status(401).json("Invalid token");
        } else {
            res.status(200).json("Valid Token")
        }
    })
}
Sarun UK
  • 6,210
  • 7
  • 23
  • 48
avydesign
  • 59
  • 2
  • 7
  • 1
    Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – evolutionxbox Sep 28 '20 at 11:07
  • 1
    Consider returning the value inside your `then`, and then return the output of `await axios.post`? – evolutionxbox Sep 28 '20 at 11:10
  • store isAuthenticated into redux or use Context, ProtectedRoute watch the result – 欧阳斌 Sep 28 '20 at 11:12
  • isAuthenticated() is declared as returning a promise, but it doesn't return a promise: it returns true or false. – Richard Hunter Sep 28 '20 at 15:39

1 Answers1

0

storing isAuthenticated at TokenContext,

import React from 'react';

const TokenContext = React.createContext<{
  token: string;
  saveToken: (token: string) => void;
  isAuthenticated: boolean;
}>(null as never);
const TokenProvider: React.FC = ({ children }) => {
  const [token, setToken] = React.useState(
    () => localStorage.getItem('jwt-token') || ''
  );
  const [isAuthenticated, setIsAuthenticated] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  React.useEffect(() => {
    if (!token || isAuthenticated) {
      return;
    }
    setLoading(true);
    axios.post(...).then(
      (res) => {
        setIsAuthenticated(res.ok);
        setLoading(false);
      },
      (err: Error) => {
        setLoading(false);
        setError(err.message)
      }
    );
  }, [token, isAuthenticated]);
  const saveToken = React.useCallback((v: string) => {
    localStorage.setItem('jwt-token', v);
    setToken(v);
    setIsAuthenticated(true);
  }, []);
  if (loading) {
    return <>Authorizing....</>;
  }
  if (error){
    return <>{error}</>
  }
  return (
    <TokenContext.Provider value={{ token, isAuthenticated, saveToken }}>
      {children}
    </TokenContext.Provider>
  );
};

interface Props {
  component: React.FC;
  path: string;
}

const ProtectedRoute: React.FC<Props> = (props: Props) => {
  const { isAuthenticated } = React.useContext(TokenContext);
  return (
    <>
      {isAuthenticated
        ? <Route path={props.path} exact component={props.component} />
        : <Redirect to="/" />
      }
    </>
  )
}

const App: React.FC = ()=> {
  <TokenProvider>
      <div className="App">
        <Router>
          <Switch>
            <Route exact path="/" component={Login} />
            <ProtectedRoute path="/dashboard" component={Dashboard} />
            <Route component={NoMatch} />
          </Switch>
        </Router>
      </div>
    </TokenProvider>
}
avydesign
  • 59
  • 2
  • 7
欧阳斌
  • 2,231
  • 1
  • 8
  • 8
  • It works but I have a second route the login route and now the forwarding does not work from login to ProtectedRoute => {isAuthenticated ? /dashboard is ProtectedRoute – avydesign Sep 28 '20 at 11:46