I have the following Next.js/Clerk.js middleware:
import { authMiddleware } from "@clerk/nextjs";
import { jwtVerify } from "jose";
export default authMiddleware({
publicRoutes: ["/", "/contact", "/pricing", "/api/webhooks/user", "/api/reviews/add", "/api/user"],
afterAuth (auth, req, evt) {
const secret = new TextEncoder().encode (process.env.CLERK_PUBLIC_KEY)
const decoded = jwtVerify ("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXYiOiJkdmJfMlpFZkVyUG91dHBuaFptQXZzdk0zMkVadkVhIiwiaWQiOiJjbGllbnRfMlpFZkpieUFQUXRWbVB4Q3R2SER4SE04a2tCIiwicm90YXRpbmdfdG9rZW4iOiJmaWNid25rZDE0aTVpNm5rZzJicjc1ODl5NWZqeGloemloZDk2dnprIn0.qURs213vHtEe_2DTmOVN8jCPCJhQfIIEjWLMIXgIVYs86U1J3P5BV9EHexjvXda416D4wHAFdxUhUzjKj42CNM4TYTrrsXRT4m_fMNq78NrvwMf7ge2tmcSYNf04c7gqInQzJMNiKILZbQXN0yxExZ1lBbPesg-ZCsx5HZ1544-g0yrcZvxu7HkSwIG56C3ITae51rtMj4lpxyYUxdR9MZ0JZ-HH2XlCT_F3BMDUn_IHNXj2IDF6gI-1kx3UWwYZ5uCyTipbsuOwgFCINFA2m8h3IM0jS9KXGLNrixaej9M0uDEcYkxVRvSwNKJfeHmnhJefYEk82192XpmXJDft8Q", secret)
console.log(decoded)
}
});
export const config = {
matcher: ["/((?!.*\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
I’m using hose to verify a the JWT. But when the middleware is called I get an error:
Promise {
[Symbol(async_id_symbol)]: 290979,
[Symbol(trigger_async_id_symbol)]: 290975,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: undefined,
[Symbol(kResourceStore)]: {
headers: [Getter],
cookies: [Getter],
mutableCookies: [Getter],
draftMode: [Getter]
}
}
TypeError: Key for the RS256 algorithm must be of type CryptoKey. Received an instance of Uint8Array
What’s wrong here?
2
Answers
The error indicates that the
jwtVerify
function from thejose
library expects a key of typeCryptoKey
for the RS256 algorithm, but you are providing aUint8Array
.In your code, you are using
new TextEncoder().encode(process.env.CLERK_PUBLIC_KEY)
to convert your key to aUint8Array
. However, for RS256 JWT verification, you need to convert this key to aCryptoKey
.You can achieve this by using the Web Crypto API to import the key. Here’s how you can modify your code:
First, import the key as a
CryptoKey
:Then, use this
publicKey
withjwtVerify
:Your updated middleware should look something like this:
Use the jose library like this. Look inside your JWT first, to get the correct algorithm from the JWT header, and the issuer / audience from the payload:
The first time you call
validateJWT
the library will download token signing public keys and cache them. This will simplify your code and also make it more resilient, since it will continue to work when clerk renews its token signing keypair.