PageSourceSearch

https://exploremydata.com/assets/jwtDecode-AEK_t6hg.js

js exploremydata.com collected 2026-09-25 20:07:14 UTC 6,101 bytes, 3 lines download raw bytes

1import{emptyPreview as w,textBlob as A}from"./util-CkZ8KZK2.js";function u(t){const n=new ArrayBuffer(t.byteLength);return new Uint8Array(n).set(t),n}function p(t){const n=t.replace(/-/g,"+").replace(/_/g,"/"),a=n+"=".repeat((4-n.length%4)%4);let e;try{e=typeof atob=="function"?atob(a):Buffer.from(a,"base64").toString("binary")}catch{throw new Error("One of the token's segments is not valid base64url.")}const r=new Uint8Array(e.length);for(let s=0;s<e.length;s+=1)r[s]=e.charCodeAt(s);return r}function S(t,n){const a=p(t),e=new TextDecoder().decode(a);let r;try{r=JSON.parse(e)}catch{throw new Error(`The ${n} decodes to text that is not JSON: ${e.slice(0,80)}`)}if(r===null||typeof r!="object"||Array.isArray(r))throw new Error(`The ${n} is not a JSON object.`);return r}function b(t){const n=t.trim().replace(/^Bearer\s+/i,"");if(n.length===0)throw new Error("Paste a token into the box.");const a=n.split(".");if(a.length!==3)throw new Error(`A JWT has three segments separated by dots, and this has ${a.length}. If you pasted a whole Authorization header, the token is the part after "Bearer ". If it has five segments it is a JWE, which is encrypted rather than signed and cannot be read without the decryption key.`);const[e,r,s]=a;return{header:S(e,"header"),payload:S(r,"payload"),raw:{header:e,payload:r,signature:s}}}const v={exp:"expires",nbf:"not valid before",iat:"issued at",auth_time:"authenticated at",updated_at:"updated at"};function l(t){const n=Math.abs(Math.round(t)),a=[[31536e3,"year"],[2592e3,"month"],[86400,"day"],[3600,"hour"],[60,"minute"],[1,"second"]];for(const[e,r]of a)if(n>=e){const s=Math.floor(n/e);return`${s} ${r}${s===1?"":"s"}`}return"0 seconds"}function k(t,n){const a=[];for(const[e,r]of Object.entries(v)){const s=t[e];if(typeof s!="number"||!Number.isFinite(s))continue;const h=s>1e11?s/1e3:s,o=h-n;let i,c=!1;e==="exp"?(c=o<=0,i=o<=0?`expired ${l(o)} ago`:`valid for another ${l(o)}`):e==="nbf"?(c=o>0,i=o>0?`not usable for another ${l(o)}`:`usable since ${l(o)} ago`):i=o<=0?`${l(o)} ago`:`${l(o)} from now`,a.push({name:`${e} (${r})`,seconds:h,iso:new Date(h*1e3).toISOString().replace(".000",""),verdict:i,expired:c})}return a}const g={HS256:"SHA-256",HS384:"SHA-384",HS512:"SHA-512"},E={RS256:"SHA-256",RS384:"SHA-384",RS512:"SHA-512"},$={PS256:"SHA-256",PS384:"SHA-384",PS512:"SHA-512"},H={ES256:{hash:"SHA-256",curve:"P-256"},ES384:{hash:"SHA-384",curve:"P-384"},ES512:{hash:"SHA-512",curve:"P-521"}};function x(t){const n=/-----BEGIN ([A-Z ]+)-----([\s\S]*?)-----END \1-----/.exec(t.trim());if(!n)throw new Error("That does not look like a PEM key. It should start with a -----BEGIN PUBLIC KEY----- line and end with the matching END line.");const a=n[1],e=n[2].replace(/\s+/g,"");return{der:p(e.replace(/\+/g,"-").replace(/\//g,"_")),label:a}}function f(){const t=globalThis.crypto;if(!(t!=null&&t.subtle))throw new Error("This browser does not expose WebCrypto, so signatures cannot be checked here.");return t.subtle}async function P(t,n,a){const e=String(t.header.alg??""),r=new TextEncoder().encode(`${t.raw.header}.${t.raw.payload}`),s=p(t.raw.signature);if(e==="none")return{status:"invalid",detail:'The header says alg is "none", which means the token is not signed at all. Any system that accepts it accepts a token anybody can forge. This is a finding, not a pass.'};if(g[e]){if(n.trim().length===0)return{status:"skipped",detail:`${e} is an HMAC. Paste the shared secret to check the signature.`};const c=await f().importKey("raw",new TextEncoder().encode(n),{name:"HMAC",hash:g[e]},!1,["verify"]);return await f().verify("HMAC",c,u(s),u(r))?{status:"valid",detail:`The ${e} signature matches that secret.`}:{status:"invalid",detail:`The ${e} signature does not match that secret.`}}const h=E[e],o=$[e],i=H[e];if(h||o||i){if(a.trim().length===0)return{status:"skipped",detail:`${e} is asymmetric. Paste the PEM public key (or the certificate's public key) to check the signature.`};const{der:c}=x(a),d=i?{name:"ECDSA",namedCurve:i.curve}:{name:o?"RSA-PSS":"RSASSA-PKCS1-v1_5",hash:h??o},y=await f().importKey("spki",u(c),d,!1,["verify"]),m=i?{name:"ECDSA",hash:i.hash}:o?{name:"RSA-PSS",saltLength:o==="SHA-256"?32:o==="SHA-384"?48:64}:{name:"RSASSA-PKCS1-v1_5"};
1return await f().verify(m,y,u(s),u(r))?{status:"valid",detail:`The ${e} signature matches that public key.`}:{status:"invalid",detail:`The ${e} signature does not match that public key.`}}return{status:"skipped",detail:`${e||"The header's alg"} is not one this page can check. HS256/384/512, RS256/384/512, PS256/384/512 and ES256/384/512 are supported.`}}function T(t,n,a){const e=[];if(e.push("HEADER"),e.push(JSON.stringify(t.header,null,2)),e.push(""),e.push("PAYLOAD"),e.push(JSON.stringify(t.payload,null,2)),n.length>0){e.push(""),e.push("TIME CLAIMS");for(const r of n)e.push(`${r.name}: ${r.iso}, ${r.verdict}`)}return e.push(""),e.push("SIGNATURE"),e.push(a.status==="valid"?`Verified. ${a.detail}`:a.status==="invalid"?`Not verified. ${a.detail}`:a.detail),`${e.join(`
2`)}
3`}const M=async t=>{t.ctx.onProgress("Decoding the token…");const n=typeof t.text=="string"?t.text:t.file?await t.file.text():"",a=b(n),e=Date.now()/1e3,r=k(a.payload,e);t.ctx.onProgress("Checking the signature…");let s;try{s=await P(a,t.options.secret??"",t.options.publicKey??"")}catch(d){s={status:"error",detail:d instanceof Error?d.message:String(d)}}const h=T(a,r,s),o=r.find(d=>d.name.startsWith("exp")),i=[String(a.header.alg??"no alg"),`${Object.keys(a.payload).length} claim${Object.keys(a.payload).length===1?"":"s"}`,...o?[o.verdict]:[],s.status==="valid"?"signature verified":s.status==="invalid"?"signature does NOT match":"signature not checked"],c=[];return(s.status==="invalid"||s.status==="error")&&c.push(s.detail),o!=null&&o.expired&&c.push(`This token is expired: ${o.verdict}.`),{status:"ok",output:{filename:"jwt.txt",blob:A(h,"text/plain"),text:h,copyKind:"text",previewText:h,preview:w(),summary:i,warnings:c}}};export{p as base64UrlDecode,T as buildJwtReport,b as decodeJwt,M as default,l as humanDuration,x as pemToDer,k as readTimeClaims,P as verifyJwt};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.