I have compiled the theory of all Authentication methods in the blog
Why JWT?
Works for mobile based, web based and microservices based auth
Relatively easy to implement
Commonly used in industry
Implementation
Install Flask-Jwt Library
Copy pip install Flask-JWT
Initiallize JWT object
JWT needs a private key to decode the JWT token. Here it's super-secret
. In production systems we usually have this key in a seperate file. If a secret key of an application is exposed anyone can start using the APIs generating API tokens
Copy # File :: app.py
app.config['SECRET_KEY'] = 'super-secret'
app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=3000)
Create a User Model in models.py
Copy # File :: models.py
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
# email = db.Column(db.String(80), unique=True, nullable=False)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120))
Write an authenticate function.
Flask-JWT uses two functions for auth purposes
1. Authenticate
Logs in the user for the first time and returns the user object. Internally, JWT uses this object to create JWT token.
2. Identity
Identity function is used on all protected APIs. Internally flask-jwt decodes JWT token and gets the user_id and passes it to identity
is function.
Copy File :: api.py
from flask_jwt import jwt_required, JWT, current_identity
def identity(payload):
user_id = payload['identity']
return User.query.filter_by(id=user_id).first()
def authenticate(username, password):
user = User.query.filter_by(username=username).first()
if user and user.password == password:
return user
jwt = JWT(app, authenticate, identity)
Write Signup and Authenticated views
Copy # File :: api.py
@app.route("/signup", methods=["POST"])
def signup():
params = request.json()
try:
user = User(**params)
db.session.add(user)
db.session.commit()
except IntegrityError:
return {"Status": "Error", "result": "User already exists"}, 400
return {"Status": "Success", "result": "User created"}
Inorder to autheticate your APIs you need to add the decorator jwt_required
to the view function
Copy @app.route("/work")
@jwt_required()
def list_work_items():
result = WorkItem.query.filter_by(created_by=current_identity.id).all()
response = [{"id": res.id, "title":res.title} for res in result]
return {"Status": "Success", "result": response}
/auth
API uses the above function to authenticate a user, returns JWT token
/auth
is an API that comes as default in the flask-jwt package. To login a user make an API call with username and password
Copy params = {
"username": "joe",
"password": "pass"
}
requests.post("/auth", json=params)
The future requests can use JWT Token for authentication
Copy headers = {
"Authorization" : "JWT <token>"
}
requests.get("/workitems", headers=headers)