I've been able to verify a GCP ID token on jwt.io's web UI okay, but am struggling to replicated it in code in JS.
I've used both the jose
and the jsrsasign
libraries to little success.
A bit of my own code to get the basics
function decodeJWT(jwtString: string) {
const jwt = jwtString.match(
/(?<header>[^.]+)\.(?<payload>[^.]+)\.(?<signature>[^.]+)/
).groups;
// For simplicity trust that the urlBase64toStr function works
// The parsed JWT is identical to what I see on jwt.io
jwt.header = JSON.parse(urlBase64toStr(jwt.header));
jwt.payload = JSON.parse(urlBase64toStr(jwt.payload));
return jwt;
}
const jwt = decodeJWT('<....JWT string here......>')
const encoder = new TextEncoder();
const byteArrays = {
signature: encoder.encode(jwt.signature),
body: encoder.encode(
JSON.stringify(jwt.header) + "." + JSON.stringify(jwt.payload)
)
};
// Google's public certs at https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
const cert = '-----BEGIN CERTIFICATE-----\n<........>'
Verifying with jose
gives false
const joseKey = await jose.importX509(cert, "RS256");
console.log(
await crypto.subtle.verify(
joseKey.algorithm.name,
joseKey,
byteArrays.signature,
byteArrays.body
)
)
// Note the following works
console.log(jose.jwtVerify(jwtRaw, joseKey))
Using jsrsaassign
also gives false
var c = new jsrsasign.X509();
c.readCertPEM(cert);
var jsRsaAssignKey = await crypto.subtle.importKey(
"jwk",
jsrsasign.KEYUTIL.getJWKFromKey(c.getPublicKey()),
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
true,
["verify"]
); // Gets RSAKey first, then transforms into a JWK, then imported to get CryptoKey
console.log(
await crypto.subtle.verify(
jsRsaAssignKey.algorithm.name,
jsRsaAssignKey,
byteArrays.signature,
byteArrays.body
)
)
Where am I going wrong here?
Note: Please do not suggest a NodeJS library. The environment I need to run the script in doesn't support Node core modules.