Mensaje de error
secretOrPublicKey must be an asymmetric key when using ES256
Qué significa
Le pides a jsonwebtoken que verifique (o que firme: el mensaje gemelo dice secretOrPrivateKey) un token ES256, pero el material de clave que proporcionas es un secreto simétrico: una cadena simple o un Buffer que no es un PEM/KeyObject. ES256 es ECDSA sobre P-256: necesita un par de claves EC, no un secreto compartido.
Por qué ocurre
Un secreto de la época de HMAC que quedó en la configuración
frecuenteEl servicio usaba HS256 con un secreto compartido, alguien cambió alg a ES256 y JWT_SECRET sigue conteniendo «supersecret». Una cadena aleatoria no es una clave EC, y jsonwebtoken se niega a fingir que lo es.
El código lee la variable de configuración equivocada
frecuenteEl PEM existe, pero el código lee una variable que contiene otra cosa: un ID de clave o una URL de JWKS (https://issuer/.well-known/jwks.json es una cadena, no una clave). Una variable vacía produce un error distinto: «secret or public key must be provided».
El PEM se estropeó al pasar por la configuración
frecuenteUn PEM que llega con secuencias \n literales, entre comillas o con la sangría de un archivo YAML ya no se analiza como clave, así que jsonwebtoken 9 trata la cadena como un secreto compartido y devuelve este error. Restaura los saltos de línea y quita las comillas antes de pasarlo.
Una JWK pasada donde se espera un PEM/KeyObject
ocasionalUna JWK es un objeto JSON; si la serializas como cadena y se la pasas a jwt.verify(), obtienes una cadena que no es ni PEM ni KeyObject. Primero hay que convertirla (crypto.createPublicKey({ key: jwk, format: "jwk" })).
Cómo solucionarlo
- 1.
Cargar una clave pública EC real
Verifica ES256 con un PEM (SPKI) o un KeyObject. Si tienes una JWK —por ejemplo, de un endpoint JWKS—, conviértela primero con node:crypto.
js import { createPublicKey } from "node:crypto"; const key = createPublicKey({ key: jwk, format: "jwk" }); // or a PEM string jwt.verify(token, key, { algorithms: ["ES256"] }); - 2.
Resolver las claves del JWKS con una función auxiliar
Si tu emisor publica las claves en una URL de JWKS, no pases la URL como clave: resuelve la clave de cada token por su kid.
js import { createRemoteJWKSet, jwtVerify } from "jose"; const jwks = createRemoteJWKSet(new URL("https://issuer.example/.well-known/jwks.json")); const { payload } = await jwtVerify(token, jwks, { algorithms: ["ES256"] }); - 3.
O bien: en realidad querías HS256
Si tanto el emisor como el verificador son tu propio servicio y el secreto compartido es intencionado, fija el algoritmo con algorithm: "HS256" en ambos lados en lugar de ES256. Mezclar las dos familias es justo lo que impide este error, incluido el clásico escenario de ataque por confusión de claves.