AtomLearnAtomLearn
DashboardGoalsPathAchievementsReviewSign In
DashboardFlaskJWT Authentication
FlaskNot Started

JWT Authentication

Stateless auth with JSON Web Tokens in Flask — issue, verify, protect routes

0%
Knowledge0%
Learn & Drill
Fluency0%
Drill & Speed
Retention0%
Mastery & Review
Confidence0%
All modes
Practice

Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.

Upgrade
Knowledge
Fluency
Retention

Knowledge Debt detected

You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.

Explanation

enables — no server-side sessions, just a signed token the client sends with every request.

Setup with flask-jwt-extended:

python from flask import Flask from flask_jwt_extended import JWTManager app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "use-a-real-secret-from-env" jwt = JWTManager(app)

Login — issue a token:

python from flask import Blueprint, request, jsonify from flask_jwt_extended import create_access_token, create_refresh_token from datetime import timedelta auth_bp = Blueprint("auth", __name__, url_prefix="/auth") @auth_bp.route("/login", methods=["POST"]) def login(): data = request.get_json() email = data.get("email") password = data.get("password") user = User.query.filter_by(email=email).first() if not user or not user.check_password(password): return jsonify({"error": "Invalid credentials"}), 401 access_token = create_access_token( identity=user.id, expires_delta=timedelta(hours=1) ) refresh_token = create_refresh_token(identity=user.id) return jsonify({ "access_token": access_token, "refresh_token": refresh_token, })

Protecting routes:

python from flask_jwt_extended import jwt_required, get_jwt_identity @app.route("/me") @jwt_required() def me(): user_id = get_jwt_identity() # the identity set at login user = User.query.get(user_id) return jsonify(user.to_dict())

Refresh token flow:

python @auth_bp.route("/refresh", methods=["POST"]) @jwt_required(refresh=True) def refresh(): user_id = get_jwt_identity() new_token = create_access_token(identity=user_id) return jsonify({"access_token": new_token})

Examples

Role-based authorization

Embed role claims at token creation; verify them on protected routes

from flask_jwt_extended import jwt_required, get_jwt
from functools import wraps
from flask import jsonify

def admin_required(fn):
    @wraps(fn)
    @jwt_required()
    def wrapper(*args, **kwargs):
        claims = get_jwt()
        if claims.get("role") != "admin":
            return jsonify({"error": "Admin access required"}), 403
        return fn(*args, **kwargs)
    return wrapper

# At login, add role to additional claims:
# additional_claims={"role": user.role}

@app.route("/admin/stats")
@admin_required
def admin_stats():
    return jsonify({"users": User.query.count()})

Password hashing with werkzeug

Never store plaintext passwords — werkzeug hashes with PBKDF2-SHA256 by default

from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model):
    id            = db.Column(db.Integer, primary_key=True)
    email         = db.Column(db.String(255), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)

    def set_password(self, password: str) -> None:
        self.password_hash = generate_password_hash(password)

    def check_password(self, password: str) -> bool:
        return check_password_hash(self.password_hash, password)

# Usage:
user = User(email="alice@example.com")
user.set_password("hunter2")
db.session.add(user)
db.session.commit()

# Login check:
user.check_password("hunter2")   # True
user.check_password("wrong")     # False

How well did you understand this?