User authentication in flask / react
Published: 2023-07-19 14:46:46

In order to allow users to login to a website and identify themselves, we can implement authentication into our application. To do this, we need to implement the use of cookies and sessions. Cookies are information that gets sent to client from the server. That information gets stored on the browser and each request that follows get sent back to the server. A session allows users to be remembered, where cookies can track user interaction throughout the duration of their session. 

In order to begin the process of authenticating users, we must set up a POST login in the backend. Doing this would look something like this: 

```
class Login(Resource):

    def post(self):
        user = User.query.filter(
            User.username == request.get_json()['username']
        ).first()

        session['user_id'] = user.id
        return user.to_dict()
```
This allows users to post a username and begin a session. On the frontend side, it would look something like this:

```
function Login({ onLogin }) {
  const [username, setUsername] = useState("");

  function handleSubmit(e) {
    e.preventDefault();
    fetch("/login", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ username }),
    })
      .then((r) => r.json())
      .then((user) => onLogin(user));
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
}
```
This creates a form for the user to enter in their information, and once they click submit their login info will be posted to the back-end and the session will begin. 

A problem that arises after logging in is if the user refreshes the page, the front-end has no way of remembering who they are. In order to solve this problem, we can implement a class starting in the back-end called "check_session". The code for this class would look something like this:

```
class CheckSession(Resource):

    def get(self):
        user = User.query.filter(User.id == session.get('user_id')).first()
        if user:
            return user.to_dict()
        else:
            return {'message': '401: Not Authorized'}, 401

api.add_resource(CheckSession, '/check_session')
```
On the front-end:

```
function App() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch("/check_session").then((response) => {
      if (response.ok) {
        response.json().then((user) => setUser(user));
      }
    });
  }, []);

  if (user) {
    return <h2>Welcome, {user.username}!</h2>;
  } else {
    return <Login onLogin={setUser} />;
  }
}
```
Here, we are using state to keep the user logged in after checking to see if there is a session running.

Lastly, to log the user out of the session the solution is simple. From the backend, the code will look like this:

```
class Logout(Resource):

    def delete(self):
        session['user_id'] = None
        return {'message': '204: No Content'}, 204

api.add_resource(Logout, '/logout')
```
Simply put - the backend sets the session equal to none. On the front end, the code looks something like this:

```
function Navbar({ onLogout }) {
  function handleLogout() {
    fetch("/logout", {
      method: "DELETE",
    }).then(() => onLogout());
  }

  return (
    <header>
      <button onClick={handleLogout}>Logout</button>
    </header>
  );
}
```
Once the user clicks on the button, they will log themselves out and the session will end.