DEV Community

Cover image for My own realtime chat with react, graphql and postgresql [part 8 - Routing and session token]
David Alejandro Quiñonez
David Alejandro Quiñonez

Posted on

My own realtime chat with react, graphql and postgresql [part 8 - Routing and session token]

As we saw in the previous part, we were able to execute the sign in mutation (i hope you tried to build the sign up mutation by your self, in any case at the end i will post the repo ;)).

Now in this part we'll see how to use the routing system programmatically in react and how to store in the local storage the user's token.

First of all we need to provide a way to access the session from any component inside the app, so we dont have to repeat a lot of code i propose to use context API. If you have another idea in order to achive the global session access let me know in the comments!

For this, lets create our auth context.

./utils/Auth.context.js


import React from "react";
const AuthContext = React.createContext();
export default AuthContext;
Enter fullscreen mode Exit fullscreen mode

Now we can provide this context to all our components.The goal using context is to get the token authetication value that's updated in our database every sign in and sign up for each user.

This token has to be persisten in order to remember our login even if we close the app. For this we'll use localstorage.

Let's see that in the code:

./App.jsx

import { ApolloProvider } from "@apollo/client";
import React, { useState } from "react";
import { HashRouter } from "react-router-dom";
import AppRouter from "./AppRouter";
import { client } from "./graphql/client";
import appRoutes from "./routes/app.routes";
import AuthContext from "./utils/Auth.context";

const App = () => {
  const [authToken, setAuthenticated] = useState(null);

  const handleAuthFlow = (authToken) => {
    setAuthenticated(authToken);
    if (authToken) {
      localStorage.setItem("authToken", JSON.stringify(authToken));
    } else {
      localStorage.removeItem("authToken");
    }
  };

  return (
    <div className="App">
      <AuthContext.Provider value={{ authToken, handleAuthFlow }}>
        <ApolloProvider client={client}>
          <HashRouter basename="/">
            <AppRouter routes={appRoutes} />
          </HashRouter>
        </ApolloProvider>
      </AuthContext.Provider>
    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode
  1. The authToken variable is the token we'll get from the graphql mutations response.
  2. The handleAuthFlow function will save or remove the token from the localstorage.
  3. The AuthContext.Provider will provide our token and our handleAuthFlow so we dont repeat a lot of code.

Now with this setup we can access the provider from our login container.

./containers/Login/Login.jsx

...
const Login = (props) => {
...
const { handleAuthFlow } = useContext(AuthContext);
const [submitted, setSubmitted] = useState(false);

useEffect(() => {const authToken = JSON.parse(localStorage.getItem("authToken"));
    if (authToken) {
      props.history.push("/chatroom");
    }
  }, [props.history]);

useEffect(() => {
   if (!loading) {
      if (data?.signInUser.usr) {
        handleAuthFlow(data.signInUser.token);
        props.history.push("/chatroom");
    } else if (submited) {
        console.log("nope");
        setSubmitted(false);
     }
    }
  }, [data, loading, handleAuthFlow, props.history, submitted]);

const onSubmitSignin = (fields) => {
   signInUser({
      variables: { usr: fields.username, password: fields.password }});
    setSubmitted(true);
  };
...

}
...
Enter fullscreen mode Exit fullscreen mode

Let's explain the changes:

  1. With the useContext hook we can access the data provided from the AuthContext.
  2. The submited flag will allow us to check when the form was submitted so we can show messages in case the mutation response comes empty.
  3. Using the first useEffect hook we can 'watch' over a state, so if the token is saved we navigate to the Chatroom container using the history from the react-router provider.
  4. With the second useEffect hook we wait for the response of the signInUser mutation, and then decide if navigate or show a message.

So now we can actually login, but let's also setup the logout:

./containers/Chatroom/Chatroom.jsx

import React, { useContext } from "react";
import AuthContext from "../../utils/Auth.context";

const Chatroom = () => {
  const { handleAuthFlow } = useContext(AuthContext);

  const logout = () => {
    handleAuthFlow(null);
  };
  return (
    <div>
      chatroom
      <p onClick={logout}>logout</p>
    </div>
  );
};

export default Chatroom;
Enter fullscreen mode Exit fullscreen mode
  1. Using the handleAuthFlow with a null param will erease the token from the local storage, and because of the PrivateRoute HOC we'll see the automatic redirection to the login container!

And that's it, we have an authentication flow with graphql and react, in the next part we'll be setting the real time chat!!

Top comments (0)