JWT.encode y JWT.decode cubren HS, RS, PS y ES de 256/384/512 y ES256K sobre la gema openssl de Ruby. EdDSA ya no forma parte de la gema jwt: con solo la gema jwt 3.3.0 cargada, codificar EdDSA falló con Unsupported signing method, y funcionó tras añadir jwt-eddsa, cuya dependencia nativa ed25519 necesita un compilador de C al instalarse, algo que no tienen las imágenes de contenedor slim.
La verificación exige indicar el algoritmo: JWT.decode(token, key, true) sin algorithm: falló con Expected a different algorithm. Los tokens sin firmar se rechazan al verificar y solo se pueden leer con la verificación desactivada (JWT.decode(token, nil, false)), algo que el código nunca debería hacer con los tokens en los que confía. Los tipos de clave se comprueban: un token HS256 falsificado con el texto PEM de la clave EC falló con HMAC key expected to be a String cuando la clave de verificación era el objeto de la clave EC, pero pasar la cadena PEM como clave HS256 lo verificó, así que conserva las claves como objetos OpenSSL::PKey. ES256 rechaza una clave P-384 al firmar.
Las comprobaciones de los claims hay que activarlas: sin tolerancia, y exp es opcional salvo que figure en required_claims, como hace el ejemplo junto con el emisor. Se aceptan secretos HMAC de cualquier longitud —una clave de 5 bytes firmó y verificó sin ninguna advertencia—, así que comprueba los secretos con el comprobador de secretos JWT.
Las firmas ES256 son 64 bytes de r‖s en bruto; una firma DER falla con Signature verification failed. Pega un token en el decodificador de JWT para ver qué codificación lleva.