[{"data":1,"prerenderedAt":1358},["ShallowReactive",2],{"guide-debugging-jwt-auth-errors":3},{"id":4,"title":5,"body":6,"date":1350,"description":1351,"extension":1352,"meta":1353,"navigation":387,"path":1354,"readingTime":222,"seo":1355,"stem":1356,"__hash__":1357},"guides\u002Fguides\u002Fdebugging-jwt-auth-errors.md","Debugging JWT Authentication Errors: A Systematic Guide",{"type":7,"value":8,"toc":1317},"minimark",[9,14,18,22,25,226,229,257,261,266,281,285,457,461,518,522,572,576,579,593,596,599,603,610,655,660,772,782,824,828,831,844,847,892,895,909,912,951,955,958,968,971,1026,1030,1033,1041,1044,1051,1054,1130,1136,1192,1196,1199,1268,1272,1295,1299,1308,1313],[10,11,13],"h2",{"id":12},"jwt-errors-are-cryptic-by-default","JWT Errors Are Cryptic by Default",[15,16,17],"p",{},"When JWT authentication fails, you typically get a generic 401 response with little explanation. The token \"doesn't work,\" but the server rarely tells you why. This guide maps common failure patterns to their root causes so you can debug methodically instead of guessing.",[10,19,21],{"id":20},"decode-the-token-first","Decode the Token First",[15,23,24],{},"Before anything else, decode the token and inspect its claims. You need to see what the token contains — and what it doesn't.",[26,27,32],"pre",{"className":28,"code":29,"language":30,"meta":31,"style":31},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Quick browser decode (verification only — no signature check)\nfunction decodeJWT(token) {\n  const parts = token.split('.');\n  if (parts.length !== 3) throw new Error('Invalid JWT structure');\n  const payload = JSON.parse(atob(parts[1].replace(\u002F-\u002Fg, '+').replace(\u002F_\u002Fg, '\u002F')));\n  return payload;\n}\n","javascript","",[33,34,35,44,66,94,131,211,220],"code",{"__ignoreMap":31},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sJ8bj","\u002F\u002F Quick browser decode (verification only — no signature check)\n",[36,45,47,51,55,59,63],{"class":38,"line":46},2,[36,48,50],{"class":49},"szBVR","function",[36,52,54],{"class":53},"sScJk"," decodeJWT",[36,56,58],{"class":57},"sVt8B","(",[36,60,62],{"class":61},"s4XuR","token",[36,64,65],{"class":57},") {\n",[36,67,69,72,76,79,82,85,87,91],{"class":38,"line":68},3,[36,70,71],{"class":49},"  const",[36,73,75],{"class":74},"sj4cs"," parts",[36,77,78],{"class":49}," =",[36,80,81],{"class":57}," token.",[36,83,84],{"class":53},"split",[36,86,58],{"class":57},[36,88,90],{"class":89},"sZZnC","'.'",[36,92,93],{"class":57},");\n",[36,95,97,100,103,106,109,112,115,118,121,124,126,129],{"class":38,"line":96},4,[36,98,99],{"class":49},"  if",[36,101,102],{"class":57}," (parts.",[36,104,105],{"class":74},"length",[36,107,108],{"class":49}," !==",[36,110,111],{"class":74}," 3",[36,113,114],{"class":57},") ",[36,116,117],{"class":49},"throw",[36,119,120],{"class":49}," new",[36,122,123],{"class":53}," Error",[36,125,58],{"class":57},[36,127,128],{"class":89},"'Invalid JWT structure'",[36,130,93],{"class":57},[36,132,134,136,139,141,144,147,150,152,155,158,161,164,167,169,172,176,178,181,184,187,190,192,194,196,199,201,203,205,208],{"class":38,"line":133},5,[36,135,71],{"class":49},[36,137,138],{"class":74}," payload",[36,140,78],{"class":49},[36,142,143],{"class":74}," JSON",[36,145,146],{"class":57},".",[36,148,149],{"class":53},"parse",[36,151,58],{"class":57},[36,153,154],{"class":53},"atob",[36,156,157],{"class":57},"(parts[",[36,159,160],{"class":74},"1",[36,162,163],{"class":57},"].",[36,165,166],{"class":53},"replace",[36,168,58],{"class":57},[36,170,171],{"class":89},"\u002F",[36,173,175],{"class":174},"sA_wV","-",[36,177,171],{"class":89},[36,179,180],{"class":49},"g",[36,182,183],{"class":57},", ",[36,185,186],{"class":89},"'+'",[36,188,189],{"class":57},").",[36,191,166],{"class":53},[36,193,58],{"class":57},[36,195,171],{"class":89},[36,197,198],{"class":174},"_",[36,200,171],{"class":89},[36,202,180],{"class":49},[36,204,183],{"class":57},[36,206,207],{"class":89},"'\u002F'",[36,209,210],{"class":57},")));\n",[36,212,214,217],{"class":38,"line":213},6,[36,215,216],{"class":49},"  return",[36,218,219],{"class":57}," payload;\n",[36,221,223],{"class":38,"line":222},7,[36,224,225],{"class":57},"}\n",[15,227,228],{},"Check these fields immediately:",[230,231,232,239,245,251],"ul",{},[233,234,235,238],"li",{},[33,236,237],{},"exp"," — Is the token expired?",[233,240,241,244],{},[33,242,243],{},"iss"," — Does it match what the server expects?",[233,246,247,250],{},[33,248,249],{},"aud"," — Does it include this API's identifier?",[233,252,253,256],{},[33,254,255],{},"iat"," — When was it issued? Is the timestamp plausible?",[10,258,260],{"id":259},"error-1-token-expired","Error 1: Token Expired",[262,263,265],"h3",{"id":264},"symptoms","Symptoms",[230,267,268,278],{},[233,269,270,271,274,275],{},"Server returns 401 with message like ",[33,272,273],{},"\"jwt expired\""," or ",[33,276,277],{},"\"Token is expired\"",[233,279,280],{},"The token worked recently but stopped",[262,282,284],{"id":283},"diagnosis","Diagnosis",[26,286,288],{"className":28,"code":287,"language":30,"meta":31,"style":31},"const payload = decodeJWT(token);\nconst now = Math.floor(Date.now() \u002F 1000);\nconst expired = now >= payload.exp;\nconst expiresAt = new Date(payload.exp * 1000).toISOString();\n\nconsole.log(`Token expired: ${expired}`);\nconsole.log(`Expires at: ${expiresAt}`);\nconsole.log(`Current time: ${new Date().toISOString()}`);\n",[33,289,290,304,335,353,383,389,410,428],{"__ignoreMap":31},[36,291,292,295,297,299,301],{"class":38,"line":39},[36,293,294],{"class":49},"const",[36,296,138],{"class":74},[36,298,78],{"class":49},[36,300,54],{"class":53},[36,302,303],{"class":57},"(token);\n",[36,305,306,308,311,313,316,319,322,325,328,330,333],{"class":38,"line":46},[36,307,294],{"class":49},[36,309,310],{"class":74}," now",[36,312,78],{"class":49},[36,314,315],{"class":57}," Math.",[36,317,318],{"class":53},"floor",[36,320,321],{"class":57},"(Date.",[36,323,324],{"class":53},"now",[36,326,327],{"class":57},"() ",[36,329,171],{"class":49},[36,331,332],{"class":74}," 1000",[36,334,93],{"class":57},[36,336,337,339,342,344,347,350],{"class":38,"line":68},[36,338,294],{"class":49},[36,340,341],{"class":74}," expired",[36,343,78],{"class":49},[36,345,346],{"class":57}," now ",[36,348,349],{"class":49},">=",[36,351,352],{"class":57}," payload.exp;\n",[36,354,355,357,360,362,364,367,370,373,375,377,380],{"class":38,"line":96},[36,356,294],{"class":49},[36,358,359],{"class":74}," expiresAt",[36,361,78],{"class":49},[36,363,120],{"class":49},[36,365,366],{"class":53}," Date",[36,368,369],{"class":57},"(payload.exp ",[36,371,372],{"class":49},"*",[36,374,332],{"class":74},[36,376,189],{"class":57},[36,378,379],{"class":53},"toISOString",[36,381,382],{"class":57},"();\n",[36,384,385],{"class":38,"line":133},[36,386,388],{"emptyLinePlaceholder":387},true,"\n",[36,390,391,394,397,399,402,405,408],{"class":38,"line":213},[36,392,393],{"class":57},"console.",[36,395,396],{"class":53},"log",[36,398,58],{"class":57},[36,400,401],{"class":89},"`Token expired: ${",[36,403,404],{"class":57},"expired",[36,406,407],{"class":89},"}`",[36,409,93],{"class":57},[36,411,412,414,416,418,421,424,426],{"class":38,"line":222},[36,413,393],{"class":57},[36,415,396],{"class":53},[36,417,58],{"class":57},[36,419,420],{"class":89},"`Expires at: ${",[36,422,423],{"class":57},"expiresAt",[36,425,407],{"class":89},[36,427,93],{"class":57},[36,429,431,433,435,437,440,443,445,448,450,453,455],{"class":38,"line":430},8,[36,432,393],{"class":57},[36,434,396],{"class":53},[36,436,58],{"class":57},[36,438,439],{"class":89},"`Current time: ${",[36,441,442],{"class":49},"new",[36,444,366],{"class":53},[36,446,447],{"class":89},"().",[36,449,379],{"class":53},[36,451,452],{"class":89},"()",[36,454,407],{"class":89},[36,456,93],{"class":57},[262,458,460],{"id":459},"common-causes","Common Causes",[462,463,464,477],"table",{},[465,466,467],"thead",{},[468,469,470,474],"tr",{},[471,472,473],"th",{},"Cause",[471,475,476],{},"Fix",[478,479,480,489,500,510],"tbody",{},[468,481,482,486],{},[483,484,485],"td",{},"Access token expired normally",[483,487,488],{},"Implement token refresh flow",[468,490,491,494],{},[483,492,493],{},"Clock skew between servers",[483,495,496,497,499],{},"Allow 30-60 second leeway in ",[33,498,237],{}," check",[468,501,502,507],{},[483,503,504,505],{},"Token issued with wrong ",[33,506,237],{},[483,508,509],{},"Check auth server's token lifetime configuration",[468,511,512,515],{},[483,513,514],{},"Client clock misconfigured",[483,516,517],{},"Sync system time via NTP",[262,519,521],{"id":520},"clock-skew-fix","Clock Skew Fix",[26,523,525],{"className":28,"code":524,"language":30,"meta":31,"style":31},"const jwt = require('jsonwebtoken');\n\n\u002F\u002F Allow 30 seconds of clock skew\njwt.verify(token, secret, { clockTolerance: 30 });\n",[33,526,527,546,550,555],{"__ignoreMap":31},[36,528,529,531,534,536,539,541,544],{"class":38,"line":39},[36,530,294],{"class":49},[36,532,533],{"class":74}," jwt",[36,535,78],{"class":49},[36,537,538],{"class":53}," require",[36,540,58],{"class":57},[36,542,543],{"class":89},"'jsonwebtoken'",[36,545,93],{"class":57},[36,547,548],{"class":38,"line":46},[36,549,388],{"emptyLinePlaceholder":387},[36,551,552],{"class":38,"line":68},[36,553,554],{"class":42},"\u002F\u002F Allow 30 seconds of clock skew\n",[36,556,557,560,563,566,569],{"class":38,"line":96},[36,558,559],{"class":57},"jwt.",[36,561,562],{"class":53},"verify",[36,564,565],{"class":57},"(token, secret, { clockTolerance: ",[36,567,568],{"class":74},"30",[36,570,571],{"class":57}," });\n",[10,573,575],{"id":574},"error-2-invalid-signature","Error 2: Invalid Signature",[262,577,265],{"id":578},"symptoms-1",[230,580,581,590],{},[233,582,583,584,274,587],{},"Server returns 401 with ",[33,585,586],{},"\"invalid signature\"",[33,588,589],{},"\"jwt malformed\"",[233,591,592],{},"Token was not tampered with, but verification still fails",[262,594,284],{"id":595},"diagnosis-1",[15,597,598],{},"This is the most confusing error because the token looks valid when decoded. The payload is readable, but the signature doesn't match.",[262,600,602],{"id":601},"common-causes-and-fixes","Common Causes and Fixes",[15,604,605,609],{},[606,607,608],"strong",{},"Wrong secret key (HS256)",":",[26,611,613],{"className":28,"code":612,"language":30,"meta":31,"style":31},"\u002F\u002F Make sure the secret exactly matches what the issuer uses\n\u002F\u002F Include any whitespace or encoding issues\nconst secret = process.env.JWT_SECRET; \u002F\u002F Verify this matches\njwt.verify(token, secret);\n",[33,614,615,620,625,646],{"__ignoreMap":31},[36,616,617],{"class":38,"line":39},[36,618,619],{"class":42},"\u002F\u002F Make sure the secret exactly matches what the issuer uses\n",[36,621,622],{"class":38,"line":46},[36,623,624],{"class":42},"\u002F\u002F Include any whitespace or encoding issues\n",[36,626,627,629,632,634,637,640,643],{"class":38,"line":68},[36,628,294],{"class":49},[36,630,631],{"class":74}," secret",[36,633,78],{"class":49},[36,635,636],{"class":57}," process.env.",[36,638,639],{"class":74},"JWT_SECRET",[36,641,642],{"class":57},"; ",[36,644,645],{"class":42},"\u002F\u002F Verify this matches\n",[36,647,648,650,652],{"class":38,"line":96},[36,649,559],{"class":57},[36,651,562],{"class":53},[36,653,654],{"class":57},"(token, secret);\n",[15,656,657,609],{},[606,658,659],{},"Wrong public key (RS256)",[26,661,663],{"className":28,"code":662,"language":30,"meta":31,"style":31},"\u002F\u002F Fetch the correct public key from the issuer's JWKS endpoint\nconst jwksClient = require('jwks-rsa');\n\nconst client = jwksClient({\n  jwksUri: 'https:\u002F\u002Fauth.example.com\u002F.well-known\u002Fjwks.json'\n});\n\nconst key = await client.getSigningKey(kid);\nconst publicKey = key.getPublicKey();\njwt.verify(token, publicKey);\n",[33,664,665,670,688,692,706,714,719,723,744,762],{"__ignoreMap":31},[36,666,667],{"class":38,"line":39},[36,668,669],{"class":42},"\u002F\u002F Fetch the correct public key from the issuer's JWKS endpoint\n",[36,671,672,674,677,679,681,683,686],{"class":38,"line":46},[36,673,294],{"class":49},[36,675,676],{"class":74}," jwksClient",[36,678,78],{"class":49},[36,680,538],{"class":53},[36,682,58],{"class":57},[36,684,685],{"class":89},"'jwks-rsa'",[36,687,93],{"class":57},[36,689,690],{"class":38,"line":68},[36,691,388],{"emptyLinePlaceholder":387},[36,693,694,696,699,701,703],{"class":38,"line":96},[36,695,294],{"class":49},[36,697,698],{"class":74}," client",[36,700,78],{"class":49},[36,702,676],{"class":53},[36,704,705],{"class":57},"({\n",[36,707,708,711],{"class":38,"line":133},[36,709,710],{"class":57},"  jwksUri: ",[36,712,713],{"class":89},"'https:\u002F\u002Fauth.example.com\u002F.well-known\u002Fjwks.json'\n",[36,715,716],{"class":38,"line":213},[36,717,718],{"class":57},"});\n",[36,720,721],{"class":38,"line":222},[36,722,388],{"emptyLinePlaceholder":387},[36,724,725,727,730,732,735,738,741],{"class":38,"line":430},[36,726,294],{"class":49},[36,728,729],{"class":74}," key",[36,731,78],{"class":49},[36,733,734],{"class":49}," await",[36,736,737],{"class":57}," client.",[36,739,740],{"class":53},"getSigningKey",[36,742,743],{"class":57},"(kid);\n",[36,745,747,749,752,754,757,760],{"class":38,"line":746},9,[36,748,294],{"class":49},[36,750,751],{"class":74}," publicKey",[36,753,78],{"class":49},[36,755,756],{"class":57}," key.",[36,758,759],{"class":53},"getPublicKey",[36,761,382],{"class":57},[36,763,765,767,769],{"class":38,"line":764},10,[36,766,559],{"class":57},[36,768,562],{"class":53},[36,770,771],{"class":57},"(token, publicKey);\n",[15,773,774,777,778,781],{},[606,775,776],{},"Algorithm mismatch",": The token header specifies ",[33,779,780],{},"alg: \"RS256\"",", but the verifier defaults to HS256. Always specify the expected algorithm:",[26,783,785],{"className":28,"code":784,"language":30,"meta":31,"style":31},"\u002F\u002F WRONG — lets the header dictate the algorithm (alg: none attack)\njwt.verify(token, publicKey);\n\n\u002F\u002F CORRECT — explicitly specify allowed algorithms\njwt.verify(token, publicKey, { algorithms: ['RS256'] });\n",[33,786,787,792,800,804,809],{"__ignoreMap":31},[36,788,789],{"class":38,"line":39},[36,790,791],{"class":42},"\u002F\u002F WRONG — lets the header dictate the algorithm (alg: none attack)\n",[36,793,794,796,798],{"class":38,"line":46},[36,795,559],{"class":57},[36,797,562],{"class":53},[36,799,771],{"class":57},[36,801,802],{"class":38,"line":68},[36,803,388],{"emptyLinePlaceholder":387},[36,805,806],{"class":38,"line":96},[36,807,808],{"class":42},"\u002F\u002F CORRECT — explicitly specify allowed algorithms\n",[36,810,811,813,815,818,821],{"class":38,"line":133},[36,812,559],{"class":57},[36,814,562],{"class":53},[36,816,817],{"class":57},"(token, publicKey, { algorithms: [",[36,819,820],{"class":89},"'RS256'",[36,822,823],{"class":57},"] });\n",[10,825,827],{"id":826},"error-3-audience-mismatch","Error 3: Audience Mismatch",[262,829,265],{"id":830},"symptoms-2",[230,832,833,841],{},[233,834,835,274,838],{},[33,836,837],{},"\"jwt audience invalid\"",[33,839,840],{},"\"Audience not allowed\"",[233,842,843],{},"Token works for one API but not another",[262,845,284],{"id":846},"diagnosis-2",[26,848,850],{"className":28,"code":849,"language":30,"meta":31,"style":31},"const payload = decodeJWT(token);\nconsole.log('Token audience:', payload.aud);\nconsole.log('Expected audience:', expectedAud);\n",[33,851,852,864,878],{"__ignoreMap":31},[36,853,854,856,858,860,862],{"class":38,"line":39},[36,855,294],{"class":49},[36,857,138],{"class":74},[36,859,78],{"class":49},[36,861,54],{"class":53},[36,863,303],{"class":57},[36,865,866,868,870,872,875],{"class":38,"line":46},[36,867,393],{"class":57},[36,869,396],{"class":53},[36,871,58],{"class":57},[36,873,874],{"class":89},"'Token audience:'",[36,876,877],{"class":57},", payload.aud);\n",[36,879,880,882,884,886,889],{"class":38,"line":68},[36,881,393],{"class":57},[36,883,396],{"class":53},[36,885,58],{"class":57},[36,887,888],{"class":89},"'Expected audience:'",[36,890,891],{"class":57},", expectedAud);\n",[262,893,460],{"id":894},"common-causes-1",[230,896,897,900,903],{},[233,898,899],{},"The auth server was configured with the wrong audience identifier",[233,901,902],{},"Multiple APIs share tokens but have different audience requirements",[233,904,905,906,908],{},"The ",[33,907,249],{}," claim is an array, but the verifier expects a string (or vice versa)",[262,910,476],{"id":911},"fix",[26,913,915],{"className":28,"code":914,"language":30,"meta":31,"style":31},"\u002F\u002F Allow multiple audiences\njwt.verify(token, secret, {\n  audience: ['https:\u002F\u002Fapi.example.com', 'https:\u002F\u002Fadmin.example.com']\n});\n",[33,916,917,922,931,947],{"__ignoreMap":31},[36,918,919],{"class":38,"line":39},[36,920,921],{"class":42},"\u002F\u002F Allow multiple audiences\n",[36,923,924,926,928],{"class":38,"line":46},[36,925,559],{"class":57},[36,927,562],{"class":53},[36,929,930],{"class":57},"(token, secret, {\n",[36,932,933,936,939,941,944],{"class":38,"line":68},[36,934,935],{"class":57},"  audience: [",[36,937,938],{"class":89},"'https:\u002F\u002Fapi.example.com'",[36,940,183],{"class":57},[36,942,943],{"class":89},"'https:\u002F\u002Fadmin.example.com'",[36,945,946],{"class":57},"]\n",[36,948,949],{"class":38,"line":96},[36,950,718],{"class":57},[10,952,954],{"id":953},"error-4-issuer-mismatch","Error 4: Issuer Mismatch",[262,956,265],{"id":957},"symptoms-3",[230,959,960,965],{},[233,961,962],{},[33,963,964],{},"\"jwt issuer invalid\"",[233,966,967],{},"Token was issued by a different identity provider than expected",[262,969,284],{"id":970},"diagnosis-3",[26,972,974],{"className":28,"code":973,"language":30,"meta":31,"style":31},"const payload = decodeJWT(token);\nconsole.log('Token issuer:', payload.iss);\nconsole.log('Expected issuer:', expectedIss);\n\u002F\u002F Common issue: trailing slash mismatch\n\u002F\u002F \"https:\u002F\u002Fauth.example.com\u002F\" !== \"https:\u002F\u002Fauth.example.com\"\n",[33,975,976,988,1002,1016,1021],{"__ignoreMap":31},[36,977,978,980,982,984,986],{"class":38,"line":39},[36,979,294],{"class":49},[36,981,138],{"class":74},[36,983,78],{"class":49},[36,985,54],{"class":53},[36,987,303],{"class":57},[36,989,990,992,994,996,999],{"class":38,"line":46},[36,991,393],{"class":57},[36,993,396],{"class":53},[36,995,58],{"class":57},[36,997,998],{"class":89},"'Token issuer:'",[36,1000,1001],{"class":57},", payload.iss);\n",[36,1003,1004,1006,1008,1010,1013],{"class":38,"line":68},[36,1005,393],{"class":57},[36,1007,396],{"class":53},[36,1009,58],{"class":57},[36,1011,1012],{"class":89},"'Expected issuer:'",[36,1014,1015],{"class":57},", expectedIss);\n",[36,1017,1018],{"class":38,"line":96},[36,1019,1020],{"class":42},"\u002F\u002F Common issue: trailing slash mismatch\n",[36,1022,1023],{"class":38,"line":133},[36,1024,1025],{"class":42},"\u002F\u002F \"https:\u002F\u002Fauth.example.com\u002F\" !== \"https:\u002F\u002Fauth.example.com\"\n",[10,1027,1029],{"id":1028},"error-5-key-rotation-issues","Error 5: Key Rotation Issues",[262,1031,265],{"id":1032},"symptoms-4",[230,1034,1035,1038],{},[233,1036,1037],{},"Tokens suddenly fail after a key rotation event",[233,1039,1040],{},"Some tokens work and others don't",[262,1042,284],{"id":1043},"diagnosis-4",[15,1045,1046,1047,1050],{},"When the issuer rotates signing keys, the ",[33,1048,1049],{},"kid"," (key ID) in the JWT header identifies which key was used. If your application caches the public key, the cached key may be stale.",[262,1052,476],{"id":1053},"fix-1",[26,1055,1057],{"className":28,"code":1056,"language":30,"meta":31,"style":31},"\u002F\u002F Use jwks-rsa with caching and rate limiting\nconst client = jwksClient({\n  jwksUri: 'https:\u002F\u002Fauth.example.com\u002F.well-known\u002Fjwks.json',\n  cache: true,\n  cacheMaxAge: 86400000, \u002F\u002F 24 hours\n  rateLimit: true,\n  jwksRequestsPerMinute: 10\n});\n",[33,1058,1059,1064,1076,1086,1096,1109,1118,1126],{"__ignoreMap":31},[36,1060,1061],{"class":38,"line":39},[36,1062,1063],{"class":42},"\u002F\u002F Use jwks-rsa with caching and rate limiting\n",[36,1065,1066,1068,1070,1072,1074],{"class":38,"line":46},[36,1067,294],{"class":49},[36,1069,698],{"class":74},[36,1071,78],{"class":49},[36,1073,676],{"class":53},[36,1075,705],{"class":57},[36,1077,1078,1080,1083],{"class":38,"line":68},[36,1079,710],{"class":57},[36,1081,1082],{"class":89},"'https:\u002F\u002Fauth.example.com\u002F.well-known\u002Fjwks.json'",[36,1084,1085],{"class":57},",\n",[36,1087,1088,1091,1094],{"class":38,"line":96},[36,1089,1090],{"class":57},"  cache: ",[36,1092,1093],{"class":74},"true",[36,1095,1085],{"class":57},[36,1097,1098,1101,1104,1106],{"class":38,"line":133},[36,1099,1100],{"class":57},"  cacheMaxAge: ",[36,1102,1103],{"class":74},"86400000",[36,1105,183],{"class":57},[36,1107,1108],{"class":42},"\u002F\u002F 24 hours\n",[36,1110,1111,1114,1116],{"class":38,"line":213},[36,1112,1113],{"class":57},"  rateLimit: ",[36,1115,1093],{"class":74},[36,1117,1085],{"class":57},[36,1119,1120,1123],{"class":38,"line":222},[36,1121,1122],{"class":57},"  jwksRequestsPerMinute: ",[36,1124,1125],{"class":74},"10\n",[36,1127,1128],{"class":38,"line":430},[36,1129,718],{"class":57},[15,1131,1132,1133,1135],{},"Always extract the ",[33,1134,1049],{}," from the header and look up the corresponding key:",[26,1137,1139],{"className":28,"code":1138,"language":30,"meta":31,"style":31},"const decoded = jwt.decode(token, { complete: true });\nconst kid = decoded.header.kid;\nconst signingKey = await client.getSigningKey(kid);\n",[33,1140,1141,1163,1175],{"__ignoreMap":31},[36,1142,1143,1145,1148,1150,1153,1156,1159,1161],{"class":38,"line":39},[36,1144,294],{"class":49},[36,1146,1147],{"class":74}," decoded",[36,1149,78],{"class":49},[36,1151,1152],{"class":57}," jwt.",[36,1154,1155],{"class":53},"decode",[36,1157,1158],{"class":57},"(token, { complete: ",[36,1160,1093],{"class":74},[36,1162,571],{"class":57},[36,1164,1165,1167,1170,1172],{"class":38,"line":46},[36,1166,294],{"class":49},[36,1168,1169],{"class":74}," kid",[36,1171,78],{"class":49},[36,1173,1174],{"class":57}," decoded.header.kid;\n",[36,1176,1177,1179,1182,1184,1186,1188,1190],{"class":38,"line":68},[36,1178,294],{"class":49},[36,1180,1181],{"class":74}," signingKey",[36,1183,78],{"class":49},[36,1185,734],{"class":49},[36,1187,737],{"class":57},[36,1189,740],{"class":53},[36,1191,743],{"class":57},[10,1193,1195],{"id":1194},"debugging-checklist","Debugging Checklist",[15,1197,1198],{},"When a JWT fails, check these in order:",[1200,1201,1202,1208,1217,1226,1235,1243,1253,1262],"ol",{},[233,1203,1204,1207],{},[606,1205,1206],{},"Structure",": Does the token have exactly three dot-separated parts?",[233,1209,1210,1213,1214,1216],{},[606,1211,1212],{},"Expiration",": Is ",[33,1215,237],{}," in the past?",[233,1218,1219,1213,1222,1225],{},[606,1220,1221],{},"Not Before",[33,1223,1224],{},"nbf"," in the future?",[233,1227,1228,1231,1232,1234],{},[606,1229,1230],{},"Issuer",": Does ",[33,1233,243],{}," match the expected value (exact string, including trailing slashes)?",[233,1236,1237,1231,1240,1242],{},[606,1238,1239],{},"Audience",[33,1241,249],{}," include this API's identifier?",[233,1244,1245,1248,1249,1252],{},[606,1246,1247],{},"Algorithm",": Does the ",[33,1250,1251],{},"alg"," header match what the verifier expects?",[233,1254,1255,1258,1259,1261],{},[606,1256,1257],{},"Signature",": Is the correct key being used? Check ",[33,1260,1049],{}," against JWKS.",[233,1263,1264,1267],{},[606,1265,1266],{},"Clock Skew",": Are the client and server clocks synchronized?",[10,1269,1271],{"id":1270},"key-takeaways","Key Takeaways",[230,1273,1274,1277,1283,1286,1289,1292],{},[233,1275,1276],{},"Always decode and inspect the JWT payload before debugging authentication code",[233,1278,1279,1280,1282],{},"Clock skew between servers is the most common cause of unexpected ",[33,1281,237],{}," failures",[233,1284,1285],{},"Specify allowed algorithms explicitly during verification to prevent algorithm confusion attacks",[233,1287,1288],{},"Audience and issuer mismatches often involve subtle string differences (trailing slashes, http vs https)",[233,1290,1291],{},"Key rotation requires JWKS-based key lookup — never hardcode public keys",[233,1293,1294],{},"Follow the debugging checklist in order — most JWT errors have straightforward root causes",[10,1296,1298],{"id":1297},"try-it-yourself","Try It Yourself",[15,1300,1301,1302,1307],{},"Decode and inspect any JWT instantly with our free ",[1303,1304,1306],"a",{"href":1305},"\u002Ftools\u002Fjwt-decoder","JWT Decoder",". Paste a token to see its header, payload, and all claims — everything is processed locally in your browser with no server communication.",[15,1309,1310],{},[1303,1311,1312],{"href":1305},"Try the JWT Decoder →",[1314,1315,1316],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}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":31,"searchDepth":46,"depth":46,"links":1318},[1319,1320,1321,1327,1332,1338,1342,1347,1348,1349],{"id":12,"depth":46,"text":13},{"id":20,"depth":46,"text":21},{"id":259,"depth":46,"text":260,"children":1322},[1323,1324,1325,1326],{"id":264,"depth":68,"text":265},{"id":283,"depth":68,"text":284},{"id":459,"depth":68,"text":460},{"id":520,"depth":68,"text":521},{"id":574,"depth":46,"text":575,"children":1328},[1329,1330,1331],{"id":578,"depth":68,"text":265},{"id":595,"depth":68,"text":284},{"id":601,"depth":68,"text":602},{"id":826,"depth":46,"text":827,"children":1333},[1334,1335,1336,1337],{"id":830,"depth":68,"text":265},{"id":846,"depth":68,"text":284},{"id":894,"depth":68,"text":460},{"id":911,"depth":68,"text":476},{"id":953,"depth":46,"text":954,"children":1339},[1340,1341],{"id":957,"depth":68,"text":265},{"id":970,"depth":68,"text":284},{"id":1028,"depth":46,"text":1029,"children":1343},[1344,1345,1346],{"id":1032,"depth":68,"text":265},{"id":1043,"depth":68,"text":284},{"id":1053,"depth":68,"text":476},{"id":1194,"depth":46,"text":1195},{"id":1270,"depth":46,"text":1271},{"id":1297,"depth":46,"text":1298},"2026-05-28","Troubleshoot common JWT authentication failures. Learn to debug expired tokens, signature mismatches, audience errors, and key rotation issues.","md",{"immutable":387},"\u002Fguides\u002Fdebugging-jwt-auth-errors",{"title":5,"description":1351},"guides\u002Fdebugging-jwt-auth-errors","rXBoq8OCLaMFnY4rH4h5I-ORcUDmHtUvmteAZmL2_U8",1780401333413]