Add support for HS256 algorithm to JWKSet #368
-
Hey there 👋 I would love to be able to use an HS256 secret and rotate it in the future by using the JWKSet and
This is the TS code to reproduce the error (please keep in mind the code is not meant for production: I played with the library to understand its capabilities 😊) // Secret key to sign the JWT
const secret = await jose.generateSecret('HS256') as KeyLike
const JWK1 = await jose.exportJWK(secret)
JWK1.kid = 'secret-key-1'
// sign JWT with initial secret key
const jwt = await new jose.SignJWT({ foo: 'bar' })
.setProtectedHeader({ alg: 'HS256', kid: JWK1.kid })
.setIssuedAt()
.setIssuer('urn:example:issuer')
.setAudience('urn:example:audience')
.setExpirationTime('2h')
.sign(secret)
console.info(jwt)
// New secret Key for future JWT to initiate the rotation
const newSecret = await jose.generateSecret('HS256') as KeyLike
const JWK2 = await jose.exportJWK(newSecret)
JWK2.kid = 'secret-key-2'
// Initiate keystore with all available keys to mimick a rotation
const keystore = jose.createLocalJWKSet({
keys: [JWK1, JWK2],
})
// Verify JWT with keystore
const { payload, protectedHeader } = await jose.jwtVerify(jwt, keystore, {
issuer: 'urn:example:issuer',
audience: 'urn:example:audience',
})
console.log(protectedHeader)
console.log(payload) Why doesn't JWKSet support the HS256/oct algorithm? Is it part of the specification or is it something we can add support for? Happy to help if that's possible 😉 Side question: I didn't find a better way to set the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
The createLocalJWKSet and createRemoteJWKSet functions return a get key function configured to resolve a single public key from a JSON Web Key Set, the use case for these is (pre-)fetching public keys from third party servers for JWS JWT verification, in these scenarios only public keys must be present in the JWKS. That's why these two functions do not and will not support symmetric keys (and therefore algorithms). From the jwtVerify documentation you can see that this get key function is something you can construct yourself following this interface. And it is as simple as the following snippet if you only want to do symmetric algorithms. import * as jose from 'jose'
// two 32 random byte secrets encoded as base64url
const secret1 = ['secret-kid-1', 'DkgIh73_RfBJqD5VDCBxUZ6hVXHI5YdU-166YT05Wag']
const secret2 = ['secret-kid-2', 'DB8xFUfJiBQiiMrSMOSgnukvTnYWdYXyOp_rs-5TKMM']
const secrets = new Map();
secrets.set(secret1[0], jose.base64url.decode(secret1[1]))
secrets.set(secret2[0], jose.base64url.decode(secret2[1]))
function getKey(protectedHeader) {
const { kid } = protectedHeader;
const match = secrets.get(kid)
if (!match) throw new Error('no resolved JWK')
return match
}
jose.jwtVerify(jwt, getKey) |
Beta Was this translation helpful? Give feedback.
The createLocalJWKSet and createRemoteJWKSet functions return a get key function configured to resolve a single public key from a JSON Web Key Set, the use case for these is (pre-)fetching public keys from third party servers for JWS JWT verification, in these scenarios only public keys must be present in the JWKS. That's why these two functions do not and will not support symmetric keys (and therefore algorithms).
From the jwtVerify documentation you can see that this get key function is something you can construct yourself following this interface. And it is as simple as the following snippet if you only want to do symmetric algorithms.