Search code examples
node.jsnext.jsjwtcryptographyjose

Create a NodeJS KeyObject from a string


How do I create a NodeJS Crypto KeyObject from the randomish string in my .env file?

I was using jsonwebtoken to create/verify JWTs, but it can't run in nextjs middleware edge functions, so I want to migrate to using jose. The problem is that in jose you can't sign a JWT with a secret string from your .env file, you need to create a cryptographic KeyObject and use that to sign the JWT.

// example env file
JWT_SECRET=Swe4g7c?UBm5Nrd96vhsVDtkyJFbqKMTm!TMw5BDRLtaCFAXNvbq?s4rGKQSZnUP

I tried to create a KeyObject with the API below, but I got an error from jose:

import crypto from 'crypto'; 
const key = crypto.createSecretKey(process.env.JWT_SECRET, 'utf-8'); 
const jwt = new jose.SignJWT(payload).sign(key); 

// Error: KeyObject or CryptoKey instance for asymmetric algorithms must not be of type "secret."

I also tried to use a Uint8Array, since the jose docs say I can, but I get this error:

const key = new TextEncoder().encode(process.env.JWT_SECRET);
const jwt = new jose.SignJWT(payload).sign(key); 

// Error: Key must be one of type KeyObject or CryptoKey. Received an instance of Uint8Array.`

Thanks in advance for any help, comments, links, resources!


Solution

  • The only thing you're missing is setting the JOSE protected header with an appropriate symmetric JWS algorithm (alg).

    The example show how that's done and the appropriate symmetric algorithm is HS256.

    import * as jose from "jose";
    
    const secret = new TextEncoder().encode(
      "Swe4g7c?UBm5Nrd96vhsVDtkyJFbqKMTm!TMw5BDRLtaCFAXNvbq?s4rGKQSZnUP"
    );
    
    const jwt = await new jose.SignJWT({ foo: "bar" })
      .setProtectedHeader({ alg: "HS256" })
      .sign(secret);
    console.log(jwt); // eyJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.iPFY1ibZc5dTBzRD46ma-Du0avf20nYKtQQsgnyf7ZM