Welcome to the next step in securing your Flask application! In the last lesson, you learned how to create a basic login endpoint that validates user credentials. Today, we'll take it a step further by introducing JSON Web Tokens (JWT) to enhance the security of your application.
Let's briefly recap our Flask app setup and the initial code we wrote.
Python1from flask import Flask, request, jsonify 2from marshmallow import Schema, fields, ValidationError 3from marshmallow.validate import Length 4 5# Initialize a Flask app instance 6app = Flask(__name__) 7 8# Mock database of users 9database = [ 10 {"id": 1, "username": "cosmo", "password": "space-corgi"} 11] 12 13# Define a schema for validating login data 14class LoginSchema(Schema): 15 username = fields.Str(required=True, validate=Length(min=1)) 16 password = fields.Str(required=True, validate=Length(min=1)) 17 18# Create an instance of LoginSchema 19login_schema = LoginSchema()
This code initializes a Flask app, sets up a mock database, and uses Marshmallow to validate login data. If you need a refresher on any of these concepts, feel free to revisit the previous lesson.
Before we dive into JWT, let's understand Bearer Tokens. A bearer token is like a "movie ticket" that you present to gain entry. Whoever "bears" this token can access certain resources.
Instead of sending your username and password with every request—which is risky—you log in once and receive a bearer token. This token is then included in the headers of future requests to prove your identity.
JWT is a type of bearer token. By using tokens, you improve security and efficiency since your credentials are not repeatedly transmitted, and servers can quickly verify token validity.
A JSON Web Token (JWT) is a compact, URL-safe means of representing claims between two parties. It's primarily used for securely transmitting information between a client and a server. A JWT token consists of three parts: a Header, a Payload, and a Signature.
By encoding this information, JWT protects user data and offers a reliable way to verify user identities.
Now, let's introduce the Flask-JWT-Extended library, which we'll use to generate and handle JWT tokens. In case you want to install Flask-JWT-Extended
in your machine, you can use the following command:
Bash1pip install flask-jwt-extended
In the CodeSignal environment, this library is pre-installed, but it's good practice to know how to do this for your local development.
To manage JWTs in your Flask application, you'll be using the JWTManager
from the Flask-JWT-Extended
library. This will handle the creation, validation, and revocation of JWTs.
Python1from flask_jwt_extended import JWTManager 2 3# Set the secret key for signing JWTs 4app.config['JWT_SECRET_KEY'] = 'super-secret' 5 6# Initialize the JWTManager with the Flask app 7jwt = JWTManager(app)
Here’s a step-by-step explanation:
Set the Secret Key: app.config['JWT_SECRET_KEY'] = 'super-secret'
JWT_SECRET_KEY
is a critical part of your security. It's used to sign the JWTs so they can be verified by your Flask app. Make sure to use a strong, unpredictable secret key in a production environment.Initialize JWTManager: jwt = JWTManager(app)
JWTManager
with your Flask app, you integrate JWT handling capabilities, like creating and validating tokens.By configuring JWTManager
, you prepare your Flask app to securely handle JWTs. Now, let's enhance our /login
endpoint to generate and return a JWT upon successful authentication.
Before we start generating JWT tokens, let's revisit the login endpoint we made in the last lesson. Here, we validate user credentials and return a success message if they are correct.
Python1# Define a route to receive login credentials 2@app.route('/login', methods=['POST']) 3def login(): 4 try: 5 # Validate and deserialize the input data according to the schema 6 data = login_schema.load(request.get_json()) 7 except ValidationError as err: 8 # If validation fails, return an error message and a 400 status code 9 return jsonify(error=err.messages), 400 10 11 # Extract username and password from the validated data 12 username = data['username'] 13 password = data['password'] 14 15 # Find the user in the mock database 16 user = next((user for user in database if user["username"] == username), None) 17 18 # Check if the user exists and if the password matches 19 if user and user["password"] == password: 20 # Login successful 21 return jsonify(message="Login successful"), 200 22 else: 23 # Return an error if the user does not exist or the password is incorrect 24 return jsonify(error="Bad username or password"), 401
Now, let's enhance our /login
endpoint to generate and return a JWT token upon successful authentication.
Here’s our adapted endpoint:
Python1from flask_jwt_extended import create_access_token 2 3# Define a route to receive login credentials 4@app.route('/login', methods=['POST']) 5def login(): 6 # -- previous input validation and user verification code goes here -- 7 8 # Check if the user exists and if the password matches 9 if user and user["password"] == password: 10 # Create an access token for the user 11 access_token = create_access_token(identity=username) 12 # Return the access token with a success message 13 return jsonify(access_token=access_token), 200 14 else: 15 # Return an error if the user does not exist or the password is incorrect 16 return jsonify(error="Bad username or password"), 401
Key changes:
create_access_token
: To generate a JWT token.create_access_token(identity=username)
, by setting the identity
to the username
, the token can later be used to identify the user making requests.With these changes, our login endpoint now provides a JWT token, enhancing the security and efficiency of our application.
When a client successfully logs in by providing valid credentials to the /login
endpoint, the response will include the generated JWT token. Here's what the response might look like:
JSON1{ 2 "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." 3}
The client should keep this token securely and send it in the Authorization
header as Bearer <token>
for future requests to access protected resources.
In this lesson, you learned how to enhance your Flask login endpoint by generating and returning JWT tokens. We covered:
Flask-JWT-Extended
.JWTManager
in your Flask app.Now that you're equipped with the knowledge of JWT-based authentication, it's time to put it into practice. Keep testing and experimenting with the code, and always double-check the security aspects of your implementation.
Happy coding!