Json Web Tokens
Tags: webdev, beginners, python, flask
Published: 2024-05-11 08:07:39

#### ⭐Contribute to [source code](https://github.com/Ezek-iel/VividBlog)
---

## What are JWT's 

JWT's represent a way to authorize clients without sharing sensitive information.  There are some resources that the clients need to send that need some authentication of some sort. 
For example in a blog application, The user needs to be logged in to create and publish a blog. JWT's can help to verify authentication to make sure that the request is valid.

---
![JWT Sequence Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9groupyubwvw4ldlucwy.png)

1. The User logs in to his account on the client
2. The client sends the user's credential to the server to validate login
3. Server validates login and sends token
4. User performs an action that requireqs authentication
5. Client creates a request and puts token in the header of the request
6. Server validates JWT, performs necessary action and returns appropriate response
7. Client displays result to the user.

---

There is also the **Time Limit** of a JWT which means the time span for the token to be valid in which after the time span the user will need to enter his credentials again

---
## Using JWT in Flask

To use JWT in flask-api, install the [flask_jwt_extended](https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage.html)  extension

```bash
pip install flask-jwt-extended
```

in your `.env` file or where you keep secret keys, insert 2 fields.

```bash
JWT_SECRET_KEY=aRandomHash
JWT_ACCESS_TOKEN_EXPIRES=30
```

The `JWT_SECRET_KEY` is just as important as the `SECRET_KEY` for the flask app. The `JWT_ACCESS_TOKEN_EXPIRES` is used to decide the timespan for a valid JWT.

in your `config.py` file or `app.py`

`config.py`

```python
class Config:

    SECRET_KEY = os.getenv("SECRET_KEY")
    JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY")
    JWT_ACCESS_TOKEN_EXPIRES = timedelta(minutes = int(os.getenv("JWT_ACCESS_TOKEN_EXPIRES"))) # remember to import timedelta from datetime module

    @staticmethod
    def init_app(app):
        pass
```

**or**

`app.py`

```python
from flask-jwt-extended import JWTManager
from datetime import timedelta
# Other imports

app.config['JWT_SECRET_KEY'] = os.getenv("JWT_SECRET_KEY")
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes = int(os.getenv("JWT_ACCESS_TOKEN_EXPIRES")))
app = Flask(__name__)
jwt = JWTManager(app)
```

In the `login` endpoint of your api, insert this

```python
from flask_jwt_extended import create_access_token
from flask_restful import Resource
from flask import request

class Login(Resource):

    def post(self):
        if request.is_json:
            username = request.json['username']
            user = User.query.filter_by(username = username).first()  # Retrieve user from the database

        if user and user.verify_password(request.json['password']): #check if user exists and password is correct
            access_token = create_access_token(identity = username) # create JWT Token and send to user
            return {'access_token' : access_token}, 200
            
	# Handle Errors
	
        elif not user: 
            return {'Message' : 'User not found'}, 404

        elif not user.verify_password(request.json['password']):
            return {'Message' : 'Incorrect password'}, 401
```

> [Flask-RESTful](https://flask-restful.readthedocs.io) was used to create the api's, not regular flask

In any area of your app that needs authorization and authentication, do this

```python
 @jwt_required() # to indicate that jwt is required for this request
    def post(self):  

        data = request.get_json() # collect blog data
        blog_schema = CreateBlogSchema() # create marshmallow schema to validate blog schema
        
        try:
            new_blog = blog_schema.load(data) # try to create a new blog

        except ValidationError as error:
            abort(400, error.messages)m# catch errors if any and return them as response messages

       db.session.add(new_blog)
       db.session.commit()
       return {'Message' : 'Operation Successful'}, 201
```
---
[Marshmallow](https://marshmallow.readthedocs.io/en/stable/quickstart.html#required-fields) was used for the schema and [FLask-SQlalchemy](https://flask-sqlalchemy.palletsprojects.com/en/3.1.x/) was used for the databases.

**If you have any questions feel free to drop them down 👇 in the comments**