Cloudflare Workers上でWeb Crypto APIで公開鍵と秘密鍵を作成し、joseでJWTの作成と検証をしてみた。
import { Hono } from "hono";
import { RegExpRouter } from "hono/router/reg-exp-router";
import {SignJWT, jwtVerify} from "jose";
export const app = new Hono({ router: new RegExpRouter() });
app.get("/token", async (c) => {
let token;
let keyPair;
let strPublicKey;
try {
keyPair = await crypto.subtle.generateKey(
{
name: "RSA-PSS",
modulusLength: 2048, //can be 1024, 2048, or 4096
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
true,
["sign", "verify"]
);
let exported = await crypto.subtle.exportKey("spki", keyPair.publicKey);
let exportedAsString = ab2str(exported);
let exportedAsBase64 = btoa(exportedAsString);
strPublicKey = `-----BEGIN PUBLIC KEY-----${exportedAsBase64}-----END PUBLIC KEY-----`;
token = await new SignJWT({ "urn:example:claim": true })
.setProtectedHeader({ alg: "PS256" })
// .setProtectedHeader({ alg: "PS512" })
.setIssuedAt()
.setIssuer("urn:example:issuer")
.setAudience("urn:example:audience")
.setExpirationTime("2h")
.sign(keyPair.privateKey);
const { payload, protectedHeader } = await jwtVerify(
token,
keyPair.publicKey,
{
issuer: "urn:example:issuer",
audience: "urn:example:audience",
}
);
return c.json({
token,
payload,
protectedHeader,
publicKey: strPublicKey,
});
} catch (e) {
return c.html(JSON.stringify(e));
}
});
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
export default app;
以下、実行した結果
{
"token": "eyJhbGciOiJQUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjU2NTEyNzMwLCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSIsImV4cCI6MTY1NjUxOTkzMH0.ENAV1ikjtBNxlysex3b2FTd7hyVeswRGPXqb9Bu2VcOkBKC_zps7ypzCaIKIsgZ4cX55oQwBxEQbdeY3gYUH9HUJDEdv1K7zRxVDbcuzilRGtgpXfeZg7ymRHjDZLhX8DQN5QinVH_pyypu4mu3yEOrR3DzTtsjajRpfUknTW5LptKlE90MZY7PETrDZQXz2-CrRflTGtAHuLUcBYC_VKJrXhMnCV412VXV62TsrOxHeW_8WzOBtDBscIV5H4qH_NFRrAzsx2rk1YD09rpIwFmtU0LYrbGItCqis07u0j29wmADLq2FKJBuDRHeiRpQGnOUQ258pnDdW0w_fIdOWbw",
"payload": {
"urn:example:claim": true,
"iat": 1656512730,
"iss": "urn:example:issuer",
"aud": "urn:example:audience",
"exp": 1656519930
},
"protectedHeader": {
"alg": "PS256"
},
"publicKey": "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhO/yo4bsP7Dtz/bFuleWo8y3sFCOFPDFZg5lSJsIU9OoXWZ+gFs31amWAmVsiVPhjAZY2y/RgsVAOHcVX+5k/aGXvLLhDGeyrfA7oLy6O7koMuTNkhz+LocHjw2Lku7iYduM4LKD7luRPm2sA+8hjXi0Z068vjRsfa1rIn9iMmWswG6lDPxA8XnTqsCcdQQUc3WZxDEetmxdmH61N2IWJZ39dWlo9bDlIoU79y9n0y2LfusByEBBEKDHL1+aB5Ua4xsXM/cGW8UZkGlMioo6v76nUWVgq24TCZFmR6M6MCk03pS4mup2fa+Nn7GqLet9/SHB+w7ZoZ38EJEUbRRCQQIDAQAB-----END PUBLIC KEY-----"
}
jwt.ioでも検証してみた。