DEV Community

Denzel
Denzel

Posted on

User Authentication in flask

Intro

User authentication is used in many web applications. Companies like Google, Meta, Amazon, and other companies all use user authentication to keep track of user information such as Usernames, ID's, passwords, and many other things. It's important to learn user authentication for company projects or personal ones.

How it works

User authentication is simply the process of identifying the user and accessing their information. Imagine a user entering a site like Facebook. They log in to their account then once they're in they can view all their personal information like posts, likes, and profile information. Then once they're done, they log out and cannot view their personal information until they log back in. While the user is browsing through Facebook user authentication happening in the background. At the start, the user is introduced to a login page where they first have to enter the correct information for their account. If the information is incorrect, Facebook cannot authenticate the user. Once the user enters the correct information Facebook logs them in their account, the application keeps the user's sensitive information until the user logs back out.

Getting Started with login

The first thing we need is a view to handle the login route in our backend. We can make a class called that handles POST requests for /login:

class Login(Resource):
    def post(self):
        username = request.get_json().get('username')
        password = request.get_json().get('password')

        user = User.query.filter_by(username=username).first()

        if user and user.authenticate(password):
            session['user_id'] = user.id
            return user.to_dict(), 200
        else:
            return {'error': 'Unauthorized'}, 401

api.add_resource(Login, '/login')
Enter fullscreen mode Exit fullscreen mode

Let's break down the code. class Login(Resource): This code tells us that we are making a class called "Login" that inherits "Resource". Whenever a class inherits Resource it lets us know that the class will be handling HTTP requests. Next we have:

def post(self):
      username = request.get_json().get('username')
      password = request.get_json().get('password')
Enter fullscreen mode Exit fullscreen mode

This tells us that we will be using a post method and it gets JSON data that has username and password parameters. Lastly, we have the authentication part:

        user = User.query.filter_by(username=username).first() 
        if user and user.authenticate(password):
            session['user_id'] = user.id
            return user.to_dict(), 200
        else:
            return {'error': 'Unauthorized'}, 401
Enter fullscreen mode Exit fullscreen mode

We first look in our database and see if we can authenticate a user that has the username from the JSON data with this line of code:

user = User.query.filter_by(username=username).first()
Enter fullscreen mode Exit fullscreen mode

Then if we find that the user is in our database and the user's password matches, we set the session to the user's id and return the user's information along with a status code 200. But if we cannot find the user we will return a JSON response with an error and a status code of 401. To finish with our backend, we add

api.add_resource(Login, '/login')
Enter fullscreen mode Exit fullscreen mode

This code means that if the user tries to access the endpoint /login it will run the class.

Now onto our frontend:

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>
Enter fullscreen mode Exit fullscreen mode

The Login component first creates a username state variable and a setUsername function to update the state. Next, we can take a look at the handleSubmit(e) function. First, we use e.preventDefault(); to prevent the default behavior of the event. Then we can fetch our /login endpoint:

   fetch("/login", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ username }),
  })
Enter fullscreen mode Exit fullscreen mode

This code tells us that we will be making a POST request that expects the header Content-Type to be JSON data. Then the body: JSON.stringify({ username }) converts the username state variable into JSON string. .then((r) => r.json()) then parses the JSON data. Once the JSON is parsed, .then((user) => onLogin(user)); calls the onLogin function prop with a user argument.

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
Enter fullscreen mode Exit fullscreen mode

Lastly, the Login function will return this form that takes in the username input and calls the handleSubmit function once the <button type="submit">Login</button> is pressed.

How to stay logged in

To stay logged in we can make this simple route:

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')
Enter fullscreen mode Exit fullscreen mode

The CheckSession class is similar to the Login class we made in our backend except instead of defining a post method we will be defining a get method. We first look if the user is in our database then if we find the user we can either return a user dictionary or return a message that says "Not Authorized" with a status code of 401 if the user was not found in the database.

Finishing with logout

The last thing to do now is log out. When you've finished browsing through a website the last thing to do to keep others from accessing your information is to logout. We can log out by creating this route:

class Logout(Resource):
    session['user_id'] = None
    return jsonify({'message': '204: No Content'}), 204

api.add_resource(Logout, '/logout')
Enter fullscreen mode Exit fullscreen mode

As you can see it's very simple. This class sets the session's user_id to None and returns a message that says "No Content" and a status code of 204. This means that there will be no user in the current session. Now let's make the front end part:

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

  return (
    <header>
      <button onClick={handleLogout}>Logout</button>
    </header>
  );
}
Enter fullscreen mode Exit fullscreen mode

This code is essentially the opposite of logging in. We first send a fetch request to the /logout endpoint with the method of DELETE. After the request is made we use .then and call the onLogout function prop. Lastly, we need to make a button that will call the handleLogout function and once this button is pressed the user will officially be logged out.

Conclusion

To be a software developer, it is crucial to learn how User authentication works. It is used in many applications to protect users such as yourself from breaches of private and sensitive data as well as keep your information secure. By understanding how user authentication works, you have added one more skill to your arsenal as a software developer.

Resources

What is user authentication?

Explore how user authentication identifies and verifies users to ensure they have permission to access the information and systems they are requesting.

favicon techtarget.com

Notion – The all-in-one workspace for your notes, tasks, wikis, and databases.

A new tool that blends your everyday work apps into one. It's the all-in-one workspace for you and your team

favicon furry-shrimp-4f0.notion.site



Flatiron School Resources:

Bootcamps in Software, Cyber, Data & Design | Flatiron School

Flatiron School is a coding bootcamp with online and on-campus courses in coding, data science, cybersecurity, and product design courses.

favicon flatironschool.com

Top comments (0)