[{"data":1,"prerenderedAt":829},["ShallowReactive",2],{"navigation":3,"-jwt-jws-algorithms":167,"-jwt-jws-algorithms-surround":826},[4,22,78,106,141,148],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","0.Getting-Started\u002F0.index",[9,10,14,18],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","0.Getting-Started\u002F1.installation",{"title":15,"path":16,"stem":17},"Quickstart","\u002Fgetting-started\u002Fquickstart","0.Getting-Started\u002F2.quickstart",{"title":19,"path":20,"stem":21},"Core concepts","\u002Fgetting-started\u002Fcore-concepts","0.Getting-Started\u002F3.core-concepts",{"title":23,"path":24,"stem":25,"children":26,"icon":28},"JWT","\u002Fjwt","1.JWT\u002F0.index",[27,29,52],{"title":23,"path":24,"stem":25,"icon":28},"i-carbon-certificate",{"title":30,"path":31,"stem":32,"children":33,"icon":35},"JWS","\u002Fjwt\u002Fjws","1.JWT\u002F1.JWS\u002F0.index",[34,36,40,44,48],{"title":30,"path":31,"stem":32,"icon":35},"i-carbon-document-signed",{"title":37,"path":38,"stem":39},"Signing","\u002Fjwt\u002Fjws\u002Fsigning","1.JWT\u002F1.JWS\u002F1.signing",{"title":41,"path":42,"stem":43},"Verifying","\u002Fjwt\u002Fjws\u002Fverifying","1.JWT\u002F1.JWS\u002F2.verifying",{"title":45,"path":46,"stem":47},"Multi-signature","\u002Fjwt\u002Fjws\u002Fmulti-signature","1.JWT\u002F1.JWS\u002F3.multi-signature",{"title":49,"path":50,"stem":51},"Algorithms","\u002Fjwt\u002Fjws\u002Falgorithms","1.JWT\u002F1.JWS\u002F4.algorithms",{"title":53,"path":54,"stem":55,"children":56,"icon":58},"JWE","\u002Fjwt\u002Fjwe","1.JWT\u002F2.JWE\u002F0.index",[57,59,63,67,71,75],{"title":53,"path":54,"stem":55,"icon":58},"i-carbon-locked",{"title":60,"path":61,"stem":62},"Encrypting","\u002Fjwt\u002Fjwe\u002Fencrypting","1.JWT\u002F2.JWE\u002F1.encrypting",{"title":64,"path":65,"stem":66},"Decrypting","\u002Fjwt\u002Fjwe\u002Fdecrypting","1.JWT\u002F2.JWE\u002F2.decrypting",{"title":68,"path":69,"stem":70},"Multi-recipient","\u002Fjwt\u002Fjwe\u002Fmulti-recipient","1.JWT\u002F2.JWE\u002F3.multi-recipient",{"title":72,"path":73,"stem":74},"ECDH-ES and end-to-end encryption","\u002Fjwt\u002Fjwe\u002Fecdh-es","1.JWT\u002F2.JWE\u002F4.ecdh-es",{"title":49,"path":76,"stem":77},"\u002Fjwt\u002Fjwe\u002Falgorithms","1.JWT\u002F2.JWE\u002F5.algorithms",{"title":79,"path":80,"stem":81,"children":82,"icon":84},"Examples","\u002Fexamples","10.Examples\u002F0.index",[83,85,90,94,98,102],{"title":79,"path":80,"stem":81,"icon":84},"i-carbon-code-reference",{"title":86,"path":87,"stem":88,"icon":89},"Authentication basics","\u002Fexamples\u002Fauthentication-basics","10.Examples\u002F1.authentication-basics","i-lucide-code",{"title":91,"path":92,"stem":93,"icon":89},"Consuming a JWKS endpoint","\u002Fexamples\u002Fjwks-endpoint","10.Examples\u002F2.jwks-endpoint",{"title":95,"path":96,"stem":97,"icon":89},"Refresh token pattern","\u002Fexamples\u002Frefresh-token-pattern","10.Examples\u002F3.refresh-token-pattern",{"title":99,"path":100,"stem":101,"icon":89},"End-to-end encryption","\u002Fexamples\u002Fend-to-end-encryption","10.Examples\u002F4.end-to-end-encryption",{"title":103,"path":104,"stem":105,"icon":89},"Signed receipts","\u002Fexamples\u002Fsigned-receipts","10.Examples\u002F5.signed-receipts",{"title":107,"path":108,"stem":109,"children":110,"icon":112},"JWK","\u002Fjwk","2.JWK\u002F0.index",[111,113,117,121,125,129,133,137],{"title":107,"path":108,"stem":109,"icon":112},"i-carbon-two-factor-authentication",{"title":114,"path":115,"stem":116},"Generating keys","\u002Fjwk\u002Fgenerating","2.JWK\u002F1.generating",{"title":118,"path":119,"stem":120},"Importing and exporting","\u002Fjwk\u002Fimport-export","2.JWK\u002F2.import-export",{"title":122,"path":123,"stem":124},"PEM conversion","\u002Fjwk\u002Fpem","2.JWK\u002F3.pem",{"title":126,"path":127,"stem":128},"Key wrapping","\u002Fjwk\u002Fwrapping","2.JWK\u002F4.wrapping",{"title":130,"path":131,"stem":132},"Password derivation","\u002Fjwk\u002Fpassword-derivation","2.JWK\u002F5.password-derivation",{"title":134,"path":135,"stem":136},"JWK Sets","\u002Fjwk\u002Fjwk-sets","2.JWK\u002F6.jwk-sets",{"title":138,"path":139,"stem":140},"JWK cache","\u002Fjwk\u002Fcache","2.JWK\u002F7.cache",{"title":142,"path":143,"stem":144,"children":145,"icon":147},"Utilities","\u002Futilities","3.Utilities\u002F0.index",[146],{"title":142,"path":143,"stem":144,"icon":147},"i-carbon-tool-box",{"title":149,"path":150,"stem":151,"children":152,"icon":154},"Adapters","\u002Fadapters","99.Adapters\u002F0.index",[153,155,159,163],{"title":149,"path":150,"stem":151,"icon":154},"i-carbon-plug",{"title":156,"path":157,"stem":158},"H3 sessions","\u002Fadapters\u002Fh3-sessions","99.Adapters\u002F1.h3-sessions",{"title":160,"path":161,"stem":162},"Lifecycle hooks","\u002Fadapters\u002Fhooks","99.Adapters\u002F2.hooks",{"title":164,"path":165,"stem":166},"Lower-level functions","\u002Fadapters\u002Flower-level","99.Adapters\u002F3.lower-level",{"id":168,"title":49,"body":169,"description":536,"extension":821,"meta":822,"navigation":823,"path":50,"seo":824,"stem":51,"__hash__":825},"content\u002F1.JWT\u002F1.JWS\u002F4.algorithms.md",{"type":170,"value":171,"toc":812},"minimark",[172,177,212,217,365,379,383,392,398,423,442,450,454,457,490,493,499,503,526,712,717,723,753,758,779,783,801,808],[173,174,176],"h1",{"id":175},"jws-algorithms","JWS algorithms",[178,179,180,181,185,186,193,194,197,198,201,202,205,206,211],"p",{},"The ",[182,183,184],"code",{},"alg"," header parameter on a JWS names the signing algorithm. unjwt supports the full ",[187,188,192],"a",{"href":189,"rel":190},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7518",[191],"nofollow","RFC 7518"," registry (minus ",[182,195,196],{},"none",", which is unsafe by design) plus ",[182,199,200],{},"Ed25519"," \u002F ",[182,203,204],{},"EdDSA"," from ",[187,207,210],{"href":208,"rel":209},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc8037",[191],"RFC 8037",".",[213,214,216],"h2",{"id":215},"registry","Registry",[218,219,220,239],"table",{},[221,222,223],"thead",{},[224,225,226,230,233,236],"tr",{},[227,228,229],"th",{},"Family",[227,231,232],{},"Identifiers",[227,234,235],{},"Key type",[227,237,238],{},"Notes",[240,241,242,270,295,318,343],"tbody",{},[224,243,244,248,260,267],{},[245,246,247],"td",{},"HMAC",[245,249,250,253,254,253,257],{},[182,251,252],{},"HS256",", ",[182,255,256],{},"HS384",[182,258,259],{},"HS512",[245,261,262,263,266],{},"Symmetric (",[182,264,265],{},"kty: \"oct\"",")",[245,268,269],{},"Fastest, simplest. Same key signs and verifies.",[224,271,272,275,286,292],{},[245,273,274],{},"RSA PKCS#1 v1.5",[245,276,277,253,280,253,283],{},[182,278,279],{},"RS256",[182,281,282],{},"RS384",[182,284,285],{},"RS512",[245,287,288,289,266],{},"RSA keypair (",[182,290,291],{},"kty: \"RSA\"",[245,293,294],{},"Widely supported but deterministic. Prefer RSA-PSS for new keys.",[224,296,297,300,311,315],{},[245,298,299],{},"RSA-PSS",[245,301,302,253,305,253,308],{},[182,303,304],{},"PS256",[182,306,307],{},"PS384",[182,309,310],{},"PS512",[245,312,288,313,266],{},[182,314,291],{},[245,316,317],{},"Probabilistic — modern RSA signature scheme.",[224,319,320,323,334,340],{},[245,321,322],{},"ECDSA",[245,324,325,253,328,253,331],{},[182,326,327],{},"ES256",[182,329,330],{},"ES384",[182,332,333],{},"ES512",[245,335,336,337,266],{},"EC keypair (",[182,338,339],{},"kty: \"EC\"",[245,341,342],{},"Much smaller keys than RSA for equivalent security.",[224,344,345,347,353,359],{},[245,346,204],{},[245,348,349,253,351],{},[182,350,200],{},[182,352,204],{},[245,354,355,356,266],{},"OKP keypair (",[182,357,358],{},"kty: \"OKP\"",[245,360,361,362,364],{},"Modern, fast, constant-time. ",[182,363,200],{}," is the concrete scheme.",[366,367,368],"note",{},[178,369,370,371,373,374,378],{},"Identifiers like ",[182,372,252],{}," are ",[375,376,377],"strong",{},"one name for one specific algorithm",": HMAC with SHA-256. The suffix number is the hash size (256, 384, 512). Larger isn't always better — SHA-256 is plenty for most purposes, and it's faster.",[213,380,382],{"id":381},"choosing","Choosing",[178,384,385,388,389,391],{},[375,386,387],{},"Building an API with self-issued tokens"," — use ",[182,390,252],{},". Simple, fast, one secret to manage. This is the default choice for 80% of apps.",[178,393,394,397],{},[375,395,396],{},"Third parties should verify without being able to sign"," — use an asymmetric scheme. In order of preference for new systems:",[399,400,402,408,413,418],"steps",{"level":401},"4",[403,404,405,407],"h4",{},[182,406,200],{}," — modern, small keys, constant-time, no parameter choices to get wrong.",[403,409,410,412],{},[182,411,327],{}," — widely supported, small signatures, safe defaults.",[403,414,415,417],{},[182,416,304],{}," — when RSA is mandated (regulated environments, legacy compatibility).",[403,419,420,422],{},[182,421,279],{}," — when a counterparty requires PKCS#1 v1.5 specifically.",[178,424,425,428,429,431,432,434,435,438,439,211],{},[375,426,427],{},"Key rotation across a fleet of services"," — ",[182,430,279],{}," or ",[182,433,304],{}," with a published ",[187,436,437],{"href":92},"JWKS endpoint",". Verifiers cache the JWKS; you rotate by publishing a new ",[182,440,441],{},"kid",[178,443,444,447,448,211],{},[375,445,446],{},"Post-quantum migration"," — no JWS algorithm is post-quantum secure today. Hybrid signing (sign with both classical and PQC in a multi-signature envelope) is the migration path — see ",[187,449,45],{"href":46},[213,451,453],{"id":452},"performance-at-a-glance","Performance at a glance",[178,455,456],{},"Rough relative costs per signature on a typical server (ordered fastest → slowest):",[399,458,459,464,469,474,481],{"level":401},[403,460,461,463],{},[182,462,252],{}," — single HMAC pass. Microseconds.",[403,465,466,468],{},[182,467,200],{}," — constant-time EC operation. Low microseconds.",[403,470,471,473],{},[182,472,327],{}," — ECDSA. Low microseconds.",[403,475,476,201,478,480],{},[182,477,304],{},[182,479,279],{}," — RSA signing dominates the cost. ~100× slower than HS256.",[403,482,483,201,485,201,487,489],{},[182,484,333],{},[182,486,285],{},[182,488,310],{}," — largest hash variant of each family.",[178,491,492],{},"Verification is typically cheaper than signing for asymmetric schemes, but the exact ratio varies.",[494,495,496],"tip",{},[178,497,498],{},"Don't optimize the algorithm choice before measuring. For the vast majority of services, any of the above is fast enough — the token-per-second budget is usually constrained by your own crypto library's scheduling, not the algorithm.",[213,500,502],{"id":501},"generating-a-key-per-algorithm","Generating a key per algorithm",[178,504,505,506,511,512,514,515,518,519,522,523,211],{},"All the examples below use ",[187,507,508],{"href":115},[182,509,510],{},"generateJWK",", which returns a key with ",[182,513,184],{}," baked in — so ",[182,516,517],{},"sign()","\u002F",[182,520,521],{},"verify()"," don't need ",[182,524,525],{},"options.alg",[527,528,529,580,636,674],"CodeGroup",{},[530,531,537],"pre",{"className":532,"code":533,"filename":534,"language":535,"meta":536,"style":536},"language-ts shiki shiki-themes github-light github-dark github-dark","const key = await generateJWK(\"HS256\");\n\u002F\u002F { kty: \"oct\", k: \"...\", alg: \"HS256\", kid: \"...\" }\n","hs256.ts","ts","",[182,538,539,573],{"__ignoreMap":536},[540,541,544,548,552,555,558,562,566,570],"span",{"class":542,"line":543},"line",1,[540,545,547],{"class":546},"so5gQ","const",[540,549,551],{"class":550},"suiK_"," key",[540,553,554],{"class":546}," =",[540,556,557],{"class":546}," await",[540,559,561],{"class":560},"shcOC"," generateJWK",[540,563,565],{"class":564},"slsVL","(",[540,567,569],{"class":568},"sfrk1","\"HS256\"",[540,571,572],{"class":564},");\n",[540,574,576],{"class":542,"line":575},2,[540,577,579],{"class":578},"sCsY4","\u002F\u002F { kty: \"oct\", k: \"...\", alg: \"HS256\", kid: \"...\" }\n",[530,581,584],{"className":532,"code":582,"filename":583,"language":535,"meta":536,"style":536},"const { privateKey, publicKey } = await generateJWK(\"RS256\", { modulusLength: 2048 });\n\u002F\u002F privateKey: JWK_RSA_Private ({ kty: \"RSA\", d, n, e, p, q, dp, dq, qi, alg, kid })\n\u002F\u002F publicKey:  JWK_RSA_Public  ({ kty: \"RSA\", n, e, alg, kid })\n","rs256.ts",[182,585,586,625,630],{"__ignoreMap":536},[540,587,588,590,593,596,598,601,604,607,609,611,613,616,619,622],{"class":542,"line":543},[540,589,547],{"class":546},[540,591,592],{"class":564}," { ",[540,594,595],{"class":550},"privateKey",[540,597,253],{"class":564},[540,599,600],{"class":550},"publicKey",[540,602,603],{"class":564}," } ",[540,605,606],{"class":546},"=",[540,608,557],{"class":546},[540,610,561],{"class":560},[540,612,565],{"class":564},[540,614,615],{"class":568},"\"RS256\"",[540,617,618],{"class":564},", { modulusLength: ",[540,620,621],{"class":550},"2048",[540,623,624],{"class":564}," });\n",[540,626,627],{"class":542,"line":575},[540,628,629],{"class":578},"\u002F\u002F privateKey: JWK_RSA_Private ({ kty: \"RSA\", d, n, e, p, q, dp, dq, qi, alg, kid })\n",[540,631,633],{"class":542,"line":632},3,[540,634,635],{"class":578},"\u002F\u002F publicKey:  JWK_RSA_Public  ({ kty: \"RSA\", n, e, alg, kid })\n",[530,637,640],{"className":532,"code":638,"filename":639,"language":535,"meta":536,"style":536},"const { privateKey, publicKey } = await generateJWK(\"Ed25519\");\n\u002F\u002F kty: \"OKP\", crv: \"Ed25519\", alg: \"Ed25519\"\n","ed25519.ts",[182,641,642,669],{"__ignoreMap":536},[540,643,644,646,648,650,652,654,656,658,660,662,664,667],{"class":542,"line":543},[540,645,547],{"class":546},[540,647,592],{"class":564},[540,649,595],{"class":550},[540,651,253],{"class":564},[540,653,600],{"class":550},[540,655,603],{"class":564},[540,657,606],{"class":546},[540,659,557],{"class":546},[540,661,561],{"class":560},[540,663,565],{"class":564},[540,665,666],{"class":568},"\"Ed25519\"",[540,668,572],{"class":564},[540,670,671],{"class":542,"line":575},[540,672,673],{"class":578},"\u002F\u002F kty: \"OKP\", crv: \"Ed25519\", alg: \"Ed25519\"\n",[530,675,678],{"className":532,"code":676,"filename":677,"language":535,"meta":536,"style":536},"const { privateKey, publicKey } = await generateJWK(\"ES256\");\n\u002F\u002F kty: \"EC\", crv: \"P-256\", alg: \"ES256\"\n","es256.ts",[182,679,680,707],{"__ignoreMap":536},[540,681,682,684,686,688,690,692,694,696,698,700,702,705],{"class":542,"line":543},[540,683,547],{"class":546},[540,685,592],{"class":564},[540,687,595],{"class":550},[540,689,253],{"class":564},[540,691,600],{"class":550},[540,693,603],{"class":564},[540,695,606],{"class":546},[540,697,557],{"class":546},[540,699,561],{"class":560},[540,701,565],{"class":564},[540,703,704],{"class":568},"\"ES256\"",[540,706,572],{"class":564},[540,708,709],{"class":542,"line":575},[540,710,711],{"class":578},"\u002F\u002F kty: \"EC\", crv: \"P-256\", alg: \"ES256\"\n",[713,714,716],"h3",{"id":715},"curves","Curves",[178,718,719,722],{},[182,720,721],{},"ES*"," uses NIST curves:",[724,725,726,735,742],"ul",{},[727,728,729,731,732],"li",{},[182,730,327],{}," → ",[182,733,734],{},"P-256",[727,736,737,731,739],{},[182,738,330],{},[182,740,741],{},"P-384",[727,743,744,731,746,749,750,752],{},[182,745,333],{},[182,747,748],{},"P-521"," (note: 521, not 512 — the curve name is ",[182,751,748],{}," in JOSE)",[178,754,755,757],{},[182,756,204],{}," uses Edwards curves:",[724,759,760,765],{},[727,761,762,764],{},[182,763,200],{}," — the common case. Recommended.",[727,766,767,770,771,774,775,778],{},[182,768,769],{},"Ed448"," — larger, slower, and currently ",[375,772,773],{},"experimental in Node.js"," (emits an ",[182,776,777],{},"ExperimentalWarning",").",[213,780,782],{"id":781},"which-identifier-goes-in-the-header","Which identifier goes in the header?",[178,784,785,787,788,790,791,793,794,800],{},[182,786,517],{}," always writes the signer's algorithm into the protected header as ",[182,789,184],{},". ",[182,792,521],{}," reads it back and checks it against the allowlist (",[187,795,797],{"href":796},"\u002Fjwt\u002Fjws\u002Fverifying#algorithm-allowlist",[182,798,799],{},"algorithms"," option, or inferred from the key).",[178,802,803,804,807],{},"Never attempt to infer the algorithm yourself by parsing the header — that's the attack vector behind the \"",[182,805,806],{},"alg: none","\" family of JWT CVEs. Let unjwt do the match.",[809,810,811],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":536,"searchDepth":575,"depth":575,"links":813},[814,815,816,817,820],{"id":215,"depth":575,"text":216},{"id":381,"depth":575,"text":382},{"id":452,"depth":575,"text":453},{"id":501,"depth":575,"text":502,"children":818},[819],{"id":715,"depth":632,"text":716},{"id":781,"depth":575,"text":782},"md",{},{},{"title":49,"description":536},"S0JIL9229eydKMpHhSpKz7uIVlw7SkMyA682B9RlGnI",[827,828],{"title":45,"path":46,"stem":47,"description":536,"children":-1},{"title":53,"path":54,"stem":55,"description":536,"icon":58,"children":-1},1776888561558]