Security
HTTP
Authentication
Flask
APIs
JWT
JWT es solo una de las maneras en las que puedes implementar seguridad y autenticación, especificamente tokens de acceso en tu API.
Es un estándar abierto para crear tokens que se utilizan en la autenticación y autorización de aplicaciones web y APIs. JWT es un tipo de token que incluye una estructura que puede ser descifrada por el servidor y permite autenticar la identidad del usuario de una aplicación.
A diferencia de otros tipos de tokens, como los básicos o los Bearer, los tokens JWT son más grandes y contienen toda la información necesaria sin necesidad de una base de datos externa.
Un token JWT consta de tres partes separadas por puntos:
HEADER: Almacena el tipo de token y el algoritmo de encriptación.
PAYLOAD: Contiene datos que identifican al usuario, como su ID o nombre de usuario.
SIGNATURE: Firma digital generada con las dos secciones anteriores para verificar si el contenido ha sido modificado1.
Para usar JWT en una API Flask, puedes seguir estos pasos:
Incluye la librería JWT en la configuración de tu aplicación Flask.
Crea un endpoint para generar nuevos tokens.
Usa el decorador @jwt_required() en rutas privadas.
Recomendamos firmemente el uso de la librería JWT extended para implementar la autenticación JWT en tu API de Python Flask, el proceso se puede dividir en los siguientes pasos:
1from flask_jwt_extended import JWTManager 2 3# Ya debes tener esta línea en tu proyecto, no tienes que añadirla de nuevo 4app = Flask(__name__) 5 6# Configura la extensión Flask-JWT-Extended 7app.config["JWT_SECRET_KEY"] = "super-secret" # ¡Cambia las palabras "super-secret" por otra cosa! 8jwt = JWTManager(app)
El endpoint debe ser un POST porque estás creando tokens (POST es para crear).
1POST /token 2Content-type: application/json 3Body: 4{ 5 "username": "alesanchezr", 6 "password": "12341234" 7}
Así es como podría verse el endpoint en Python:
1from flask_jwt_extended import create_access_token 2 3# Crea una ruta para autenticar a los usuarios y devolver el token JWT 4# La función create_access_token() se utiliza para generar el JWT 5@app.route("/token", methods=["POST"]) 6def create_token(): 7 username = request.json.get("username", None) 8 password = request.json.get("password", None) 9 10 # Consulta la base de datos por el nombre de usuario y la contraseña 11 user = User.query.filter_by(username=username, password=password).first() 12 13 if user is None: 14 # el usuario no se encontró en la base de datos 15 return jsonify({"msg": "Bad username or password"}), 401 16 17 # Crea un nuevo token con el id de usuario dentro 18 access_token = create_access_token(identity=user.id) 19 return jsonify({ "token": access_token, "user_id": user.id })
@jwt_required()
en rutas privadasAhora... cualquier endpoint que requiera autorización (endpoints privados) debería usar el decorador @jwt_required()
.
Podrás recuperar la información del usuario autentificado (si es válido) usando la función get_jwt_identity
.
1from flask_jwt_extended import jwt_required, get_jwt_identity 2 3# Protege una ruta con jwt_required, bloquea las peticiones sin un JWT válido 4@app.route("/protected", methods=["GET"]) 5@jwt_required() 6def protected(): 7 # Accede a la identidad del usuario actual con get_jwt_identity 8 current_user_id = get_jwt_identity() 9 user = User.query.get(current_user_id) 10 11 return jsonify({"id": user.id, "username": user.username }), 200
En el lado del front-end necesitamos dos pasos principales: Crear un nuevo token (también conocido como "login") y añadir el token a los headers cuando se obtenga cualquier otro endpoint privado.
Basándonos en los endpoints que construimos anteriormente, tenemos que hacer POST /token
con la información del nombre de usuario y la contraseña en el body de la petición.
1const login = async (username, password) => { 2 const resp = await fetch(`https://your_api.com/token`, { 3 method: "POST", 4 headers: { "Content-Type": "application/json" }, 5 body: JSON.stringify({ username, password }) 6 }) 7 8 if(!resp.ok) throw Error("There was a problem in the login request") 9 10 if(resp.status === 401){ 11 throw("Invalid credentials") 12 } 13 else if(resp.status === 400){ 14 throw ("Invalid email or password format") 15 } 16 const data = await resp.json() 17 // Guarda el token en la localStorage 18 // También deberías almacenar el usuario en la store utilizando la función setItem 19 localStorage.setItem("jwt-token", data.token); 20 21 return data 22}
Supongamos que estoy usando la aplicación de front-end y acabo de iniciar sesión, pero ahora quiero obtener algún endpoint privado o protegido:
1// Asumiendo que "/protected" es un endpoint privado 2const getMyTasks = async () => { 3 // Recupera el token desde la localStorage 4 const token = localStorage.getItem('jwt-token'); 5 6 const resp = await fetch(`https://your_api.com/protected`, { 7 method: 'GET', 8 headers: { 9 "Content-Type": "application/json", 10 'Authorization': 'Bearer ' + token // ⬅⬅⬅ authorization token 11 } 12 }); 13 14 if(!resp.ok) { 15 throw Error("There was a problem in the login request") 16 } else if(resp.status === 403) { 17 throw Error("Missing or invalid token"); 18 } else { 19 throw Error("Unknown error"); 20 } 21 22 const data = await resp.json(); 23 console.log("This is the data you requested", data); 24 return data 25}
¡Eso es todo! Como puedes ver, es muy sencillo integrar JWT en tu aplicación usando Flask/Python, solo tres pasos en el backend y dos pasos en el frontend. Ante cualquier duda puedes contactarme en Twitter @alesanchezr o utilizar el canal #public-support
en la comunidad Slack de 4Geeks Academy.