[{"data":1,"prerenderedAt":1010},["ShallowReactive",2],{"guide-jwt-structure-explained":3},{"id":4,"title":5,"body":6,"date":1002,"description":1003,"extension":1004,"meta":1005,"navigation":837,"path":1006,"readingTime":462,"seo":1007,"stem":1008,"__hash__":1009},"guides\u002Fguides\u002Fjwt-structure-explained.md","JWT Structure Explained: Header, Payload, and Signature",{"type":7,"value":8,"toc":973},"minimark",[9,14,18,21,32,35,39,42,48,109,112,116,119,169,174,217,225,247,258,261,267,271,278,282,285,391,398,402,476,503,507,535,538,542,548,552,555,559,565,569,575,582,586,592,596,602,679,683,866,870,876,897,900,904,908,914,918,923,927,932,936,957,961,969],[10,11,13],"h2",{"id":12},"what-is-a-jwt","What Is a JWT?",[15,16,17],"p",{},"A JSON Web Token (JWT) is a compact, URL-safe string that carries information between two parties. Defined in RFC 7519, JWTs are the backbone of modern authentication and authorization flows.",[15,19,20],{},"A JWT looks like this:",[22,23,28],"pre",{"className":24,"code":26,"language":27},[25],"language-text","eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n","text",[29,30,26],"code",{"__ignoreMap":31},"",[15,33,34],{},"That long string is three separate parts joined by dots. Each part serves a distinct purpose.",[10,36,38],{"id":37},"the-three-parts-of-a-jwt","The Three Parts of a JWT",[15,40,41],{},"Every JWT follows the same structure:",[22,43,46],{"className":44,"code":45,"language":27},[25],"header.payload.signature\n",[29,47,45],{"__ignoreMap":31},[49,50,51,67],"table",{},[52,53,54],"thead",{},[55,56,57,61,64],"tr",{},[58,59,60],"th",{},"Part",[58,62,63],{},"Encoded With",[58,65,66],{},"Purpose",[68,69,70,85,97],"tbody",{},[55,71,72,79,82],{},[73,74,75],"td",{},[76,77,78],"strong",{},"Header",[73,80,81],{},"Base64URL",[73,83,84],{},"Identifies the token type and signing algorithm",[55,86,87,92,94],{},[73,88,89],{},[76,90,91],{},"Payload",[73,93,81],{},[73,95,96],{},"Carries the actual data (claims)",[55,98,99,104,106],{},[73,100,101],{},[76,102,103],{},"Signature",[73,105,81],{},[73,107,108],{},"Ensures the token has not been tampered with",[15,110,111],{},"Let's break down each one.",[10,113,115],{"id":114},"the-header","The Header",[15,117,118],{},"The header tells the recipient how to process the token. It contains two fields:",[22,120,124],{"className":121,"code":122,"language":123,"meta":31,"style":31},"language-json shiki shiki-themes github-light github-dark","{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n","json",[29,125,126,135,152,163],{"__ignoreMap":31},[127,128,131],"span",{"class":129,"line":130},"line",1,[127,132,134],{"class":133},"sVt8B","{\n",[127,136,138,142,145,149],{"class":129,"line":137},2,[127,139,141],{"class":140},"sj4cs","  \"alg\"",[127,143,144],{"class":133},": ",[127,146,148],{"class":147},"sZZnC","\"HS256\"",[127,150,151],{"class":133},",\n",[127,153,155,158,160],{"class":129,"line":154},3,[127,156,157],{"class":140},"  \"typ\"",[127,159,144],{"class":133},[127,161,162],{"class":147},"\"JWT\"\n",[127,164,166],{"class":129,"line":165},4,[127,167,168],{"class":133},"}\n",[170,171,173],"h3",{"id":172},"header-claims","Header Claims",[49,175,176,189],{},[52,177,178],{},[55,179,180,183,186],{},[58,181,182],{},"Claim",[58,184,185],{},"Description",[58,187,188],{},"Common Values",[68,190,191,204],{},[55,192,193,198,201],{},[73,194,195],{},[29,196,197],{},"alg",[73,199,200],{},"Algorithm used to sign the token",[73,202,203],{},"HS256, RS256, ES256",[55,205,206,211,214],{},[73,207,208],{},[29,209,210],{},"typ",[73,212,213],{},"Token type",[73,215,216],{},"JWT",[15,218,219,224],{},[76,220,221,223],{},[29,222,197],{}," (Algorithm)"," — This is the most critical field. It tells the verifier which algorithm was used to create the signature. Common choices include:",[226,227,228,235,241],"ul",{},[229,230,231,234],"li",{},[76,232,233],{},"HS256",": HMAC with SHA-256 (symmetric — same secret for signing and verification)",[229,236,237,240],{},[76,238,239],{},"RS256",": RSA with SHA-256 (asymmetric — private key signs, public key verifies)",[229,242,243,246],{},[76,244,245],{},"ES256",": ECDSA with SHA-256 (asymmetric — smaller signatures than RSA)",[15,248,249,254,255,257],{},[76,250,251,253],{},[29,252,210],{}," (Type)"," — Almost always set to ",[29,256,216],{},". Some implementations omit it, but including it is a best practice for clarity.",[15,259,260],{},"The header is then Base64URL-encoded:",[22,262,265],{"className":263,"code":264,"language":27},[25],"Base64URL({\"alg\":\"HS256\",\"typ\":\"JWT\"})\n→ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\n",[29,266,264],{"__ignoreMap":31},[10,268,270],{"id":269},"the-payload","The Payload",[15,272,273,274,277],{},"The payload contains the ",[76,275,276],{},"claims"," — statements about an entity (typically a user) and additional metadata. Claims come in three categories:",[170,279,281],{"id":280},"registered-claims-standard","Registered Claims (Standard)",[15,283,284],{},"These are reserved claim names defined by RFC 7519:",[49,286,287,298],{},[52,288,289],{},[55,290,291,293,296],{},[58,292,182],{},[58,294,295],{},"Full Name",[58,297,185],{},[68,299,300,313,326,339,352,365,378],{},[55,301,302,307,310],{},[73,303,304],{},[29,305,306],{},"iss",[73,308,309],{},"Issuer",[73,311,312],{},"Who issued the token",[55,314,315,320,323],{},[73,316,317],{},[29,318,319],{},"sub",[73,321,322],{},"Subject",[73,324,325],{},"The principal the token is about (usually a user ID)",[55,327,328,333,336],{},[73,329,330],{},[29,331,332],{},"aud",[73,334,335],{},"Audience",[73,337,338],{},"Intended recipient of the token",[55,340,341,346,349],{},[73,342,343],{},[29,344,345],{},"exp",[73,347,348],{},"Expiration",[73,350,351],{},"Time after which the token is no longer valid",[55,353,354,359,362],{},[73,355,356],{},[29,357,358],{},"nbf",[73,360,361],{},"Not Before",[73,363,364],{},"Time before which the token is not valid",[55,366,367,372,375],{},[73,368,369],{},[29,370,371],{},"iat",[73,373,374],{},"Issued At",[73,376,377],{},"Time the token was issued",[55,379,380,385,388],{},[73,381,382],{},[29,383,384],{},"jti",[73,386,387],{},"JWT ID",[73,389,390],{},"Unique identifier for the token (prevents replay)",[15,392,393,394,397],{},"All time-based claims use ",[76,395,396],{},"Unix timestamps"," (seconds since epoch).",[170,399,401],{"id":400},"example-payload","Example Payload",[22,403,405],{"className":121,"code":404,"language":123,"meta":31,"style":31},"{\n  \"sub\": \"1234567890\",\n  \"name\": \"John Doe\",\n  \"role\": \"admin\",\n  \"iat\": 1516239022,\n  \"exp\": 1516242622\n}\n",[29,406,407,411,423,435,447,460,471],{"__ignoreMap":31},[127,408,409],{"class":129,"line":130},[127,410,134],{"class":133},[127,412,413,416,418,421],{"class":129,"line":137},[127,414,415],{"class":140},"  \"sub\"",[127,417,144],{"class":133},[127,419,420],{"class":147},"\"1234567890\"",[127,422,151],{"class":133},[127,424,425,428,430,433],{"class":129,"line":154},[127,426,427],{"class":140},"  \"name\"",[127,429,144],{"class":133},[127,431,432],{"class":147},"\"John Doe\"",[127,434,151],{"class":133},[127,436,437,440,442,445],{"class":129,"line":165},[127,438,439],{"class":140},"  \"role\"",[127,441,144],{"class":133},[127,443,444],{"class":147},"\"admin\"",[127,446,151],{"class":133},[127,448,450,453,455,458],{"class":129,"line":449},5,[127,451,452],{"class":140},"  \"iat\"",[127,454,144],{"class":133},[127,456,457],{"class":140},"1516239022",[127,459,151],{"class":133},[127,461,463,466,468],{"class":129,"line":462},6,[127,464,465],{"class":140},"  \"exp\"",[127,467,144],{"class":133},[127,469,470],{"class":140},"1516242622\n",[127,472,474],{"class":129,"line":473},7,[127,475,168],{"class":133},[226,477,478,483,493,498],{},[229,479,480,482],{},[29,481,319],{}," identifies the user",[229,484,485,488,489,492],{},[29,486,487],{},"name"," and ",[29,490,491],{},"role"," are custom claims",[229,494,495,497],{},[29,496,371],{}," records when the token was issued",[229,499,500,502],{},[29,501,345],{}," sets the token to expire 1 hour after issuance",[170,504,506],{"id":505},"public-and-private-claims","Public and Private Claims",[226,508,509,523],{},[229,510,511,514,515,518,519,522],{},[76,512,513],{},"Public claims",": Registered in the IANA JSON Web Token Registry to avoid collisions (e.g., ",[29,516,517],{},"email",", ",[29,520,521],{},"roles",")",[229,524,525,528,529,518,532,522],{},[76,526,527],{},"Private claims",": Custom names agreed upon by the parties (e.g., ",[29,530,531],{},"department",[29,533,534],{},"plan_id",[15,536,537],{},"Always avoid collision by choosing claim names that won't conflict with registered claims.",[170,539,541],{"id":540},"important-payload-is-not-encrypted","Important: Payload Is Not Encrypted",[15,543,544,545],{},"The payload is Base64URL-encoded, not encrypted. Anyone who intercepts the token can read its contents. ",[76,546,547],{},"Never store sensitive data (passwords, API keys, SSNs) in a JWT payload.",[10,549,551],{"id":550},"the-signature","The Signature",[15,553,554],{},"The signature verifies that the token hasn't been altered. It is computed from the header and payload:",[170,556,558],{"id":557},"hmac-hs256-example","HMAC (HS256) Example",[22,560,563],{"className":561,"code":562,"language":27},[25],"HMACSHA256(\n  base64UrlEncode(header) + \".\" + base64UrlEncode(payload),\n  secret\n)\n",[29,564,562],{"__ignoreMap":31},[170,566,568],{"id":567},"rsa-rs256-example","RSA (RS256) Example",[22,570,573],{"className":571,"code":572,"language":27},[25],"RSASHA256(\n  base64UrlEncode(header) + \".\" + base64UrlEncode(payload),\n  privateKey\n)\n",[29,574,572],{"__ignoreMap":31},[15,576,577,578,581],{},"The signature ensures ",[76,579,580],{},"integrity"," — if anyone changes even a single character in the header or payload, the signature will no longer match.",[170,583,585],{"id":584},"verification-flow","Verification Flow",[22,587,590],{"className":588,"code":589,"language":27},[25],"1. Split the JWT by dots → [header, payload, signature]\n2. Recompute the signature using header + payload + secret\u002Fkey\n3. Compare the recomputed signature with the received signature\n4. Match → token is valid and untampered\n5. No match → token has been modified → reject\n",[29,591,589],{"__ignoreMap":31},[10,593,595],{"id":594},"base64url-encoding-explained","Base64URL Encoding Explained",[15,597,598,599,601],{},"JWTs use ",[76,600,81],{}," encoding, not standard Base64. The differences matter:",[49,603,604,616],{},[52,605,606],{},[55,607,608,611,613],{},[58,609,610],{},"Standard Base64",[58,612,81],{},[58,614,615],{},"Reason",[68,617,618,635,652,668],{},[55,619,620,625,630],{},[73,621,622],{},[29,623,624],{},"+",[73,626,627],{},[29,628,629],{},"-",[73,631,632,634],{},[29,633,624],{}," is interpreted as space in URLs",[55,636,637,642,647],{},[73,638,639],{},[29,640,641],{},"\u002F",[73,643,644],{},[29,645,646],{},"_",[73,648,649,651],{},[29,650,641],{}," is a URL path separator",[55,653,654,660,663],{},[73,655,656,659],{},[29,657,658],{},"="," padding",[73,661,662],{},"Removed",[73,664,665,667],{},[29,666,658],{}," is percent-encoded in URLs",[55,669,670,673,676],{},[73,671,672],{},"Output not URL-safe",[73,674,675],{},"Output is URL-safe",[73,677,678],{},"JWTs travel in URLs and cookies",[170,680,682],{"id":681},"manual-decode-example","Manual Decode Example",[22,684,688],{"className":685,"code":686,"language":687,"meta":31,"style":31},"language-javascript shiki shiki-themes github-light github-dark","function decodeBase64Url(str) {\n  \u002F\u002F Restore standard Base64\n  let base64 = str.replace(\u002F-\u002Fg, '+').replace(\u002F_\u002Fg, '\u002F');\n  \u002F\u002F Restore padding\n  while (base64.length % 4) base64 += '=';\n  return JSON.parse(atob(base64));\n}\n\nconst header = decodeBase64Url('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9');\n\u002F\u002F { alg: \"HS256\", typ: \"JWT\" }\n","javascript",[29,689,690,710,716,772,777,806,828,832,839,860],{"__ignoreMap":31},[127,691,692,696,700,703,707],{"class":129,"line":130},[127,693,695],{"class":694},"szBVR","function",[127,697,699],{"class":698},"sScJk"," decodeBase64Url",[127,701,702],{"class":133},"(",[127,704,706],{"class":705},"s4XuR","str",[127,708,709],{"class":133},") {\n",[127,711,712],{"class":129,"line":137},[127,713,715],{"class":714},"sJ8bj","  \u002F\u002F Restore standard Base64\n",[127,717,718,721,724,726,729,732,734,736,739,741,744,746,749,752,754,756,758,760,762,764,766,769],{"class":129,"line":154},[127,719,720],{"class":694},"  let",[127,722,723],{"class":133}," base64 ",[127,725,658],{"class":694},[127,727,728],{"class":133}," str.",[127,730,731],{"class":698},"replace",[127,733,702],{"class":133},[127,735,641],{"class":147},[127,737,629],{"class":738},"sA_wV",[127,740,641],{"class":147},[127,742,743],{"class":694},"g",[127,745,518],{"class":133},[127,747,748],{"class":147},"'+'",[127,750,751],{"class":133},").",[127,753,731],{"class":698},[127,755,702],{"class":133},[127,757,641],{"class":147},[127,759,646],{"class":738},[127,761,641],{"class":147},[127,763,743],{"class":694},[127,765,518],{"class":133},[127,767,768],{"class":147},"'\u002F'",[127,770,771],{"class":133},");\n",[127,773,774],{"class":129,"line":165},[127,775,776],{"class":714},"  \u002F\u002F Restore padding\n",[127,778,779,782,785,788,791,794,797,800,803],{"class":129,"line":449},[127,780,781],{"class":694},"  while",[127,783,784],{"class":133}," (base64.",[127,786,787],{"class":140},"length",[127,789,790],{"class":694}," %",[127,792,793],{"class":140}," 4",[127,795,796],{"class":133},") base64 ",[127,798,799],{"class":694},"+=",[127,801,802],{"class":147}," '='",[127,804,805],{"class":133},";\n",[127,807,808,811,814,817,820,822,825],{"class":129,"line":462},[127,809,810],{"class":694},"  return",[127,812,813],{"class":140}," JSON",[127,815,816],{"class":133},".",[127,818,819],{"class":698},"parse",[127,821,702],{"class":133},[127,823,824],{"class":698},"atob",[127,826,827],{"class":133},"(base64));\n",[127,829,830],{"class":129,"line":473},[127,831,168],{"class":133},[127,833,835],{"class":129,"line":834},8,[127,836,838],{"emptyLinePlaceholder":837},true,"\n",[127,840,842,845,848,851,853,855,858],{"class":129,"line":841},9,[127,843,844],{"class":694},"const",[127,846,847],{"class":140}," header",[127,849,850],{"class":694}," =",[127,852,699],{"class":698},[127,854,702],{"class":133},[127,856,857],{"class":147},"'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'",[127,859,771],{"class":133},[127,861,863],{"class":129,"line":862},10,[127,864,865],{"class":714},"\u002F\u002F { alg: \"HS256\", typ: \"JWT\" }\n",[10,867,869],{"id":868},"how-the-three-parts-work-together","How the Three Parts Work Together",[22,871,874],{"className":872,"code":873,"language":27},[25],"┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│    HEADER    │  .  │   PAYLOAD    │  .  │  SIGNATURE   │\n│  (algorithm) │     │   (claims)   │     │  (proof)     │\n└──────────────┘     └──────────────┘     └──────────────┘\n       ↓                    ↓                     ↓\n  Base64URL           Base64URL            HMAC\u002FRSA of\n  encoded             encoded              header.payload\n",[29,875,873],{"__ignoreMap":31},[226,877,878,885,891],{},[229,879,880,881,884],{},"The ",[76,882,883],{},"header"," tells the verifier which algorithm to use",[229,886,880,887,890],{},[76,888,889],{},"payload"," carries the claims the application needs",[229,892,880,893,896],{},[76,894,895],{},"signature"," proves the first two parts were issued by a trusted source",[15,898,899],{},"If any part changes, the signature breaks — and the token is rejected.",[10,901,903],{"id":902},"common-jwt-myths","Common JWT Myths",[170,905,907],{"id":906},"myth-jwts-are-encrypted","Myth: JWTs Are Encrypted",[15,909,910,913],{},[76,911,912],{},"Reality",": JWTs are encoded, not encrypted. Anyone can decode the header and payload without a secret key. Use JWE (JSON Web Encryption) if you need confidentiality.",[170,915,917],{"id":916},"myth-you-cannot-trust-a-jwt-without-a-database-lookup","Myth: You Cannot Trust a JWT Without a Database Lookup",[15,919,920,922],{},[76,921,912],{},": With asymmetric algorithms (RS256), the verifier only needs the public key — no database call needed. This is the key advantage of self-contained tokens.",[170,924,926],{"id":925},"myth-longer-secrets-mean-better-security","Myth: Longer Secrets Mean Better Security",[15,928,929,931],{},[76,930,912],{},": With HMAC, yes — use at least 256-bit secrets. With RSA or ECDSA, key length matters differently. Follow the algorithm's best practices, not guesswork.",[10,933,935],{"id":934},"related-guides","Related Guides",[226,937,938,945,951],{},[229,939,940],{},[941,942,944],"a",{"href":943},"\u002Fguides\u002Fjwt-security-best-practices","JWT Security Best Practices",[229,946,947],{},[941,948,950],{"href":949},"\u002Fguides\u002Fjwt-vs-oauth-tokens","JWT vs OAuth Tokens",[229,952,953],{},[941,954,956],{"href":955},"\u002Fguides\u002Fbase64url-difference","Base64URL Difference",[10,958,960],{"id":959},"try-it-yourself","Try It Yourself",[15,962,963,964,968],{},"Want to see the structure of a real JWT? Paste any token into our free ",[941,965,967],{"href":966},"\u002Ftools\u002Fjwt-decoder","JWT Decoder"," to instantly inspect its header, payload, and claims — all processed securely in your browser with no data sent to any server.",[970,971,972],"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);}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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":31,"searchDepth":137,"depth":137,"links":974},[975,976,977,980,986,991,994,995,1000,1001],{"id":12,"depth":137,"text":13},{"id":37,"depth":137,"text":38},{"id":114,"depth":137,"text":115,"children":978},[979],{"id":172,"depth":154,"text":173},{"id":269,"depth":137,"text":270,"children":981},[982,983,984,985],{"id":280,"depth":154,"text":281},{"id":400,"depth":154,"text":401},{"id":505,"depth":154,"text":506},{"id":540,"depth":154,"text":541},{"id":550,"depth":137,"text":551,"children":987},[988,989,990],{"id":557,"depth":154,"text":558},{"id":567,"depth":154,"text":568},{"id":584,"depth":154,"text":585},{"id":594,"depth":137,"text":595,"children":992},[993],{"id":681,"depth":154,"text":682},{"id":868,"depth":137,"text":869},{"id":902,"depth":137,"text":903,"children":996},[997,998,999],{"id":906,"depth":154,"text":907},{"id":916,"depth":154,"text":917},{"id":925,"depth":154,"text":926},{"id":934,"depth":137,"text":935},{"id":959,"depth":137,"text":960},"2026-05-27","Understand how JSON Web Tokens work. Break down the three parts of a JWT: header, payload, and signature.","md",{"immutable":837},"\u002Fguides\u002Fjwt-structure-explained",{"title":5,"description":1003},"guides\u002Fjwt-structure-explained","QcZ7nw7kiFfrrS5fwIQ0yH1nFz4iNf8UnuEdEpaMp3o",1780401325082]