Cifrar JSON Web Token con Flask

author
By admin
17 de marzo de 2025
image

Este token esta cifrado (JWE), no esta firmado (JWS), se cifra con la clave publica del certificado que este punto final, (API REST) crea, la clave privada del certificado permanece siempre en el servidor.


  • JWE, quien tenga la clave privada puede leer los datos
  • JWS, quien tenga el token puede leer los datos


Entonces firmando el token(que este ejemplo no contempla), y luego cifrándolo tenemos un token mas seguro.


En este escenario (prototipo), se mantiene el mismo token(por usuario) por sesión, el nombre del token es un string aleatorio que no se repite, cada usuario autenticado tiene su token, criptografía de clave pública(asimétrica).


Encrypted Token

# JWCrypto
from jwcrypto import jwt, jwe, jwk
from jwcrypto.common import json_encode, json_decode
import json, os

@auth.route('/getToken', methods=['POST'])
  def getToken():
    user = db_session.query(userModel).filter_by(id = request.get_json().get("id")).first()         
    if user:
      payload1 = {'id': user.id, 'email': user.email, 'role': user.role}
      payload = str(payload1)
      key = jwk.JWK.generate(kty='EC', crv='P-256')
      public_key = key.export(private_key=False)
      private_key = key.export(private_key=True)
      # keys users
      path = os.getcwd()+'/jwt/'+str(user.id)
      os.makedirs(path, exist_ok=True) 
      b = bytes(private_key, 'utf-8')
      token = path+'/'+request.get_json().get("user_session").split(".")[1]
      with open(token, 'wb') as key_file:
        key_file.write(b)
      # encrypt with public_key
      key_public = json.loads(public_key)
      expkey = {
        "y": key_public.get('y'),
        "x": key_public.get('x'),
        "crv": key_public.get('crv'),
        "kty": key_public.get('kty')
      }
      key_object_public_key = jwk.JWK(**expkey)
      protected_header = {
        "typ": "JWE",
        "alg": "ECDH-ES+A256KW",
        "enc": "A256CBC-HS512",
        "kid": "12",
      }
      jwetoken = jwe.JWE(payload.encode('utf-8'),recipient=key_object_public_key,protected=protected_header)
      enc = jwetoken.serialize()
      resp = jsonify({"auth": enc, "crt": request.get_json().get("user_session").split(".")[1]})
      return resp, 200
    else:
      return 'Incorrect user', 401

Decorador token_required, desciframos el token con la clave privada

def token_required(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        json_object = json.loads(kwargs["id"])
        access_token = request.headers['Authorization']
        token = access_token.split()[1]
        jwe_data = token
        try:
            path = os.getcwd()+'/jwt/'+json_object["id"]
            token = path+'/'+str(json_object["user_session"])
            with open(token, "rb") as key_file:
                key_data = key_file.read()
        except:
            logging.error(f"Error loading key file")
        # Object private key
        private_key = json.loads(key_data)
        expkey = {
            "y": private_key.get('y'),
            "x": private_key.get('x'),
            "crv": private_key.get('crv'),
            "kty": private_key.get('kty'),
            "d": private_key.get('d')
            }
        key = jwk.JWK(**expkey)
        jwetoken = jwe.JWE()
        try:
            jwetoken.deserialize(jwe_data, key=key)
        except:
            logging.error(f"FAILED - Decryption failed")
            return 'FAILED - Decryption failed', 403
        payload = jwetoken.payload
        return fn(*args, **kwargs)
    return wrapper

Utilizacion

class user(Resource):
    # Get resource
    #@admin_required
    @token_required
    def get(self, id):
        ...
  
 
Share this post :

Subscribe to receive future updates

Lorem ipsum dolor sited Sed ullam corper consectur adipiscing Mae ornare massa quis lectus.

No spam guaranteed, So please don’t send any spam mail.