javascriptnext.jsjwtjose

Javascript Jose Sign And Encrypt JWT


I am using jose to sign and encrypt JWTs. However I am unable to sign and then encrypt my whole JWT.

I use this function to sign my jwt:

const secretKey = process.env.JWT_SECRET;
const key = new TextEncoder().encode(secretKey);

export async function _encrypt(payload: any) {
  return await new SignJWT(payload)
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime("10 sec from now")
    .sign(key);
}

I am using following code to encrypt it (when passing an JWT object it works):

const now = () => (Date.now() / 1000) | 0;

const alg = "dir";
const enc = "A256CBC-HS512";

...

sync function encrypt({
  payload,
  maxAge,
}: {
  payload: JWTPayload;
  maxAge: number;
}): Promise<string> {
  const secret: Uint8Array = randomBytes(32);
  const salt = randomBytes(16);
  const encryptionSecret: Uint8Array = await hkdf(
    "sha256",
    secret,
    salt,
    "Generated Encryption Key",
    32
  );
  
  return new EncryptJWT(payload)
    .setProtectedHeader({ alg, enc })
    .setIssuedAt()
    .setExpirationTime(now() + maxAge)
    .setJti(crypto.randomUUID())
    .encrypt(encryptionSecret);
}

The code does not work as intended because EncryptJWT does only accept an JWT object. This is also reflected in the console: error TypeError: JWT Claims Set MUST be an object


Solution

  • To sign then encrypt you want to use the SignJWT class to sign and then CompactEncrypt to encrypt the signed result. An example of this is in https://github.com/panva/jose/issues/112, just replace the key management with your secrets and use appropriate algorithms.