[{"data":1,"prerenderedAt":619},["ShallowReactive",2],{"blog-jwt-token-structure-explained":3},{"id":4,"title":5,"body":6,"category":606,"date":607,"description":608,"extension":609,"meta":610,"navigation":611,"path":612,"readingTime":613,"seo":614,"stem":615,"tool":616,"updated":617,"__hash__":618},"blog\u002Fblog\u002Fjwt-token-structure-explained.md","JWT Token Structure Explained",{"type":7,"value":8,"toc":584},"minimark",[9,13,16,21,32,35,46,60,64,67,117,154,157,161,164,169,296,300,303,359,363,366,373,377,380,386,389,392,396,421,424,428,432,447,451,461,465,475,479,482,496,505,508,525,529,534,545,550,561,565,573,577,580],[10,11,12],"p",{},"JSON Web Tokens (JWTs) are the standard way to pass authentication and authorization data between services. If you work with APIs, single sign-on, or microservices, you encounter JWTs daily. Yet many developers treat them as opaque strings without understanding their structure — which leads to security vulnerabilities and debugging frustration.",[10,14,15],{},"This guide explains exactly what is inside a JWT, how the three parts work together, and the mistakes that cause real-world security incidents.",[17,18,20],"h2",{"id":19},"what-is-a-jwt","What is a JWT?",[10,22,23,24,31],{},"A JWT (pronounced \"jot\") is a compact, URL-safe token defined by ",[25,26,30],"a",{"href":27,"rel":28},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc7519",[29],"nofollow","RFC 7519",". It carries a set of claims (key-value pairs) that are digitally signed so the recipient can verify their authenticity without contacting the issuer.",[10,33,34],{},"A JWT looks like this:",[36,37,42],"pre",{"className":38,"code":40,"language":41},[39],"language-text","eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n","text",[43,44,40],"code",{"__ignoreMap":45},"",[10,47,48,49,53,54,53,57,53],{},"It is three Base64url-encoded segments separated by dots: ",[50,51,52],"strong",{},"Header",".",[50,55,56],{},"Payload",[50,58,59],{},"Signature",[17,61,63],{"id":62},"part-1-the-header","Part 1: The Header",[10,65,66],{},"The header is a JSON object that identifies the token type and the signing algorithm:",[36,68,72],{"className":69,"code":70,"language":71,"meta":45,"style":45},"language-json shiki shiki-themes github-light github-dark","{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n","json",[43,73,74,83,100,111],{"__ignoreMap":45},[75,76,79],"span",{"class":77,"line":78},"line",1,[75,80,82],{"class":81},"sVt8B","{\n",[75,84,86,90,93,97],{"class":77,"line":85},2,[75,87,89],{"class":88},"sj4cs","  \"alg\"",[75,91,92],{"class":81},": ",[75,94,96],{"class":95},"sZZnC","\"HS256\"",[75,98,99],{"class":81},",\n",[75,101,103,106,108],{"class":77,"line":102},3,[75,104,105],{"class":88},"  \"typ\"",[75,107,92],{"class":81},[75,109,110],{"class":95},"\"JWT\"\n",[75,112,114],{"class":77,"line":113},4,[75,115,116],{"class":81},"}\n",[118,119,120,139,148],"ul",{},[121,122,123,126,127,130,131,134,135,138],"li",{},[43,124,125],{},"alg"," — the algorithm used to create the signature. Common values: ",[43,128,129],{},"HS256"," (HMAC-SHA256, symmetric), ",[43,132,133],{},"RS256"," (RSA-SHA256, asymmetric), ",[43,136,137],{},"ES256"," (ECDSA P-256, asymmetric).",[121,140,141,144,145,53],{},[43,142,143],{},"typ"," — always ",[43,146,147],{},"\"JWT\"",[121,149,150,153],{},[43,151,152],{},"kid"," — (optional) key ID, used when the issuer rotates signing keys.",[10,155,156],{},"The header is Base64url-encoded to form the first segment.",[17,158,160],{"id":159},"part-2-the-payload-claims","Part 2: The Payload (Claims)",[10,162,163],{},"The payload contains the claims — statements about the user or session. Claims come in three categories:",[165,166,168],"h3",{"id":167},"registered-claims-rfc-7519","Registered claims (RFC 7519)",[170,171,172,188],"table",{},[173,174,175],"thead",{},[176,177,178,182,185],"tr",{},[179,180,181],"th",{},"Claim",[179,183,184],{},"Name",[179,186,187],{},"Example",[189,190,191,207,222,237,252,267,281],"tbody",{},[176,192,193,199,202],{},[194,195,196],"td",{},[43,197,198],{},"iss",[194,200,201],{},"Issuer",[194,203,204],{},[43,205,206],{},"\"https:\u002F\u002Fauth.example.com\"",[176,208,209,214,217],{},[194,210,211],{},[43,212,213],{},"sub",[194,215,216],{},"Subject (user ID)",[194,218,219],{},[43,220,221],{},"\"user_42\"",[176,223,224,229,232],{},[194,225,226],{},[43,227,228],{},"aud",[194,230,231],{},"Audience",[194,233,234],{},[43,235,236],{},"\"https:\u002F\u002Fapi.example.com\"",[176,238,239,244,247],{},[194,240,241],{},[43,242,243],{},"exp",[194,245,246],{},"Expiration (Unix timestamp)",[194,248,249],{},[43,250,251],{},"1716239022",[176,253,254,259,262],{},[194,255,256],{},[43,257,258],{},"nbf",[194,260,261],{},"Not Before",[194,263,264],{},[43,265,266],{},"1716235422",[176,268,269,274,277],{},[194,270,271],{},[43,272,273],{},"iat",[194,275,276],{},"Issued At",[194,278,279],{},[43,280,266],{},[176,282,283,288,291],{},[194,284,285],{},[43,286,287],{},"jti",[194,289,290],{},"JWT ID (unique identifier)",[194,292,293],{},[43,294,295],{},"\"a1b2c3d4\"",[165,297,299],{"id":298},"public-claims","Public claims",[10,301,302],{},"Custom claims registered with IANA or using collision-resistant names:",[36,304,306],{"className":69,"code":305,"language":71,"meta":45,"style":45},"{\n  \"email\": \"alice@example.com\",\n  \"roles\": [\"admin\", \"editor\"],\n  \"org_id\": \"org_123\"\n}\n",[43,307,308,312,324,344,354],{"__ignoreMap":45},[75,309,310],{"class":77,"line":78},[75,311,82],{"class":81},[75,313,314,317,319,322],{"class":77,"line":85},[75,315,316],{"class":88},"  \"email\"",[75,318,92],{"class":81},[75,320,321],{"class":95},"\"alice@example.com\"",[75,323,99],{"class":81},[75,325,326,329,332,335,338,341],{"class":77,"line":102},[75,327,328],{"class":88},"  \"roles\"",[75,330,331],{"class":81},": [",[75,333,334],{"class":95},"\"admin\"",[75,336,337],{"class":81},", ",[75,339,340],{"class":95},"\"editor\"",[75,342,343],{"class":81},"],\n",[75,345,346,349,351],{"class":77,"line":113},[75,347,348],{"class":88},"  \"org_id\"",[75,350,92],{"class":81},[75,352,353],{"class":95},"\"org_123\"\n",[75,355,357],{"class":77,"line":356},5,[75,358,116],{"class":81},[165,360,362],{"id":361},"private-claims","Private claims",[10,364,365],{},"Agreed-upon claims between parties, not registered anywhere.",[10,367,368,369,372],{},"The payload is Base64url-encoded — ",[50,370,371],{},"not encrypted",". Anyone who has the token can decode and read the claims. Never put secrets, passwords, or sensitive PII in JWT claims.",[17,374,376],{"id":375},"part-3-the-signature","Part 3: The Signature",[10,378,379],{},"The signature verifies that the token was not tampered with. For HMAC-SHA256:",[36,381,384],{"className":382,"code":383,"language":41},[39],"HMAC-SHA256(\n  base64url(header) + \".\" + base64url(payload),\n  secret\n)\n",[43,385,383],{"__ignoreMap":45},[10,387,388],{},"For RSA-SHA256, the issuer signs with a private key, and the recipient verifies with the corresponding public key.",[10,390,391],{},"The signature prevents modification: if an attacker changes a claim in the payload, the signature will not match when the recipient recalculates it.",[17,393,395],{"id":394},"how-jwt-authentication-works","How JWT Authentication Works",[397,398,399,402,405,408,415],"ol",{},[121,400,401],{},"The user logs in with credentials.",[121,403,404],{},"The auth server validates credentials and creates a JWT with the user's claims.",[121,406,407],{},"The auth server signs the JWT and returns it to the client.",[121,409,410,411,414],{},"The client sends the JWT in the ",[43,412,413],{},"Authorization: Bearer \u003Ctoken>"," header on subsequent requests.",[121,416,417,418,420],{},"The API server validates the signature, checks ",[43,419,243],{},", and uses the claims for authorization.",[10,422,423],{},"This is stateless: the API server does not need to query a database or session store on every request. The JWT carries all the information needed.",[17,425,427],{"id":426},"common-jwt-security-mistakes","Common JWT Security Mistakes",[165,429,431],{"id":430},"_1-not-validating-the-signature","1. Not validating the signature",[10,433,434,435,438,439,442,443,446],{},"Decoding a JWT is not the same as verifying it. Always validate the signature before trusting the claims. Libraries like ",[43,436,437],{},"jsonwebtoken"," (Node.js), ",[43,440,441],{},"PyJWT"," (Python), and ",[43,444,445],{},"golang-jwt"," (Go) do this automatically — but only if you pass the correct secret or public key.",[165,448,450],{"id":449},"_2-using-the-none-algorithm","2. Using the \"none\" algorithm",[10,452,453,454,457,458,460],{},"The ",[43,455,456],{},"alg: \"none\""," attack exploits servers that accept unsigned tokens. Always reject tokens with ",[43,459,456],{}," and validate that the algorithm matches what you expect.",[165,462,464],{"id":463},"_3-storing-jwts-in-localstorage","3. Storing JWTs in localStorage",[10,466,467,470,471,474],{},[43,468,469],{},"localStorage"," is accessible to any JavaScript on the page, including XSS-injected scripts. For browser-based apps, store JWTs in ",[43,472,473],{},"httpOnly"," cookies (not accessible to JavaScript) or use short-lived tokens with refresh token rotation.",[165,476,478],{"id":477},"_4-long-lived-tokens-without-revocation","4. Long-lived tokens without revocation",[10,480,481],{},"JWTs cannot be revoked once issued — the server has no session to invalidate. Mitigations:",[118,483,484,490,493],{},[121,485,486,487,489],{},"Keep ",[43,488,243],{}," short (5-15 minutes for access tokens)",[121,491,492],{},"Use refresh tokens (stored securely, revocable in database)",[121,494,495],{},"Maintain a token blocklist for critical revocations",[165,497,499,500,502,503],{"id":498},"_5-not-checking-exp-and-aud","5. Not checking ",[43,501,243],{}," and ",[43,504,228],{},[10,506,507],{},"Always validate:",[118,509,510,515,520],{},[121,511,512,514],{},[43,513,243],{}," — reject expired tokens",[121,516,517,519],{},[43,518,228],{}," — reject tokens intended for a different service",[121,521,522,524],{},[43,523,198],{}," — reject tokens from unexpected issuers",[17,526,528],{"id":527},"when-to-use-jwts-and-when-not-to","When to Use JWTs (and When Not To)",[10,530,531],{},[50,532,533],{},"Good use cases:",[118,535,536,539,542],{},[121,537,538],{},"Stateless API authentication between microservices",[121,540,541],{},"Single sign-on (SSO) across multiple applications",[121,543,544],{},"Short-lived authorization tokens",[10,546,547],{},[50,548,549],{},"Bad use cases:",[118,551,552,555,558],{},[121,553,554],{},"Session management for a single web app (server-side sessions are simpler and revocable)",[121,556,557],{},"Storing large amounts of data (JWTs are sent on every request — keep them small)",[121,559,560],{},"Situations where immediate revocation is required",[17,562,564],{"id":563},"inspecting-jwts","Inspecting JWTs",[10,566,567,568,572],{},"When debugging authentication issues, you need to see what is inside a token. ",[25,569,571],{"href":570},"\u002Ftools\u002Fjwt-decoder","StackCache JWT Inspector"," decodes the header and payload, displays the claims in a readable format, shows expiration status, and highlights potential issues — all locally in your browser. Your token never leaves your device.",[17,574,576],{"id":575},"summary","Summary",[10,578,579],{},"A JWT is three Base64url-encoded parts: a header (algorithm), a payload (claims), and a signature (integrity proof). Understanding this structure helps you debug authentication failures, avoid security mistakes, and make informed decisions about when JWTs are the right choice for your architecture.",[581,582,583],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .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":45,"searchDepth":85,"depth":85,"links":585},[586,587,588,593,594,595,603,604,605],{"id":19,"depth":85,"text":20},{"id":62,"depth":85,"text":63},{"id":159,"depth":85,"text":160,"children":589},[590,591,592],{"id":167,"depth":102,"text":168},{"id":298,"depth":102,"text":299},{"id":361,"depth":102,"text":362},{"id":375,"depth":85,"text":376},{"id":394,"depth":85,"text":395},{"id":426,"depth":85,"text":427,"children":596},[597,598,599,600,601],{"id":430,"depth":102,"text":431},{"id":449,"depth":102,"text":450},{"id":463,"depth":102,"text":464},{"id":477,"depth":102,"text":478},{"id":498,"depth":102,"text":602},"5. Not checking exp and aud",{"id":527,"depth":85,"text":528},{"id":563,"depth":85,"text":564},{"id":575,"depth":85,"text":576},"Security","2026-09-08","Understand the three parts of a JWT token — header, payload, and signature. Learn how JWTs work, when to use them, and common security mistakes.","md",{},true,"\u002Fblog\u002Fjwt-token-structure-explained",7,{"title":5,"description":608},"blog\u002Fjwt-token-structure-explained","jwt-decoder",null,"w-yZxxJ7zibtyR8nYc_myUmzmaP0mFMk-jBxN9EPqYA",1788868139280]