11
2- // JWT Debugger
2+ // // JWT Debugger
3+
34
45document . addEventListener ( 'DOMContentLoaded' , function ( ) {
56 const jwtInput = document . getElementById ( 'jwtInput' ) ;
67 const headerInput = document . getElementById ( 'jwtHeaderInput' ) ;
78 const payloadInput = document . getElementById ( 'jwtPayloadInput' ) ;
89 const secretInput = document . getElementById ( 'jwtSecretInput' ) ;
9- const encodedOutput = document . getElementById ( 'jwtEncoded' ) ;
10+ const publicKeyInput = document . getElementById ( 'jwtPublicKeyInput' ) ;
11+ const privateKeyInput = document . getElementById ( 'jwtPrivateKeyInput' ) ;
1012 const encodingSelect = document . getElementById ( 'secretEncoding' ) ;
13+ const algorithmSelect = document . getElementById ( 'jwtAlgorithm' ) ;
14+ const encodedOutput = document . getElementById ( 'jwtEncoded' ) ;
1115 const verifyStatus = document . getElementById ( 'jwtVerifyStatus' ) ;
12-
16+
1317 document . getElementById ( 'decode-jwt' ) ?. addEventListener ( 'click' , decodeJWT ) ;
1418 document . getElementById ( 'verify-jwt' ) ?. addEventListener ( 'click' , verifyJWT ) ;
1519 document . getElementById ( 'encode-jwt' ) ?. addEventListener ( 'click' , encodeJWT ) ;
16-
20+
21+ function getAlgorithm ( ) {
22+ return algorithmSelect ?. value || 'HS256' ;
23+ }
24+
25+ function getKeyForSign ( alg ) {
26+ if ( alg . startsWith ( 'HS' ) ) {
27+ const secret = secretInput . value . trim ( ) ;
28+ const encoding = encodingSelect . value ;
29+ const keyObj = { } ;
30+ keyObj [ encoding ] = secret ;
31+ return keyObj ;
32+ } else if ( alg . startsWith ( 'RS' ) || alg . startsWith ( 'PS' ) || alg . startsWith ( 'ES' ) ) {
33+ return privateKeyInput . value . trim ( ) ;
34+ } else {
35+ throw new Error ( `Unsupported algorithm for signing: ${ alg } ` ) ;
36+ }
37+ }
38+
39+ function getKeyForVerify ( alg ) {
40+ if ( alg . startsWith ( 'HS' ) ) {
41+ const secret = secretInput . value . trim ( ) ;
42+ const encoding = encodingSelect . value ;
43+ const keyObj = { } ;
44+ keyObj [ encoding ] = secret ;
45+ return keyObj ;
46+ } else if ( alg . startsWith ( 'RS' ) || alg . startsWith ( 'PS' ) || alg . startsWith ( 'ES' ) ) {
47+ return publicKeyInput . value . trim ( ) ;
48+ } else {
49+ throw new Error ( `Unsupported algorithm for verification: ${ alg } ` ) ;
50+ }
51+ }
52+
1753 function decodeJWT ( ) {
18- const jwt = jwtInput . value . trim ( ) ;
19- const parts = jwt . split ( '.' ) ;
20- if ( parts . length !== 3 ) {
21- return showError ( 'Invalid JWT format (expected 3 parts)' ) ;
22- }
23-
24- try {
25- const header = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( parts [ 0 ] ) ) ;
26- const payload = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( parts [ 1 ] ) ) ;
27-
28- headerInput . value = JSON . stringify ( header , null , 2 ) ;
29- payloadInput . value = JSON . stringify ( payload , null , 2 ) ;
30- showStatus ( '' , '✅ Decoded successfully (not verified)' ) ;
31- } catch ( err ) {
32- showError ( 'Failed to decode JWT: ' + err . message ) ;
33- }
54+ const jwt = jwtInput . value . trim ( ) ;
55+ const parts = jwt . split ( '.' ) ;
56+ if ( parts . length !== 3 ) {
57+ return showError ( 'Invalid JWT format (expected 3 parts)' ) ;
58+ }
59+
60+ try {
61+ const header = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( parts [ 0 ] ) ) ;
62+ const payload = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( parts [ 1 ] ) ) ;
63+
64+ headerInput . value = JSON . stringify ( header , null , 2 ) ;
65+ payloadInput . value = JSON . stringify ( payload , null , 2 ) ;
66+ showStatus ( '' , '✅ Decoded successfully (not verified)' ) ;
67+ } catch ( err ) {
68+ showError ( 'Failed to decode JWT: ' + err . message ) ;
69+ }
3470 }
35-
71+
3672 function verifyJWT ( ) {
37- try {
38- const jwt = jwtInput . value . trim ( ) ;
39- const secret = secretInput . value . trim ( ) ;
40- const encoding = encodingSelect . value ;
41- if ( ! jwt || ! secret ) {
42- return showError ( 'JWT and secret are required.' ) ;
43- }
44-
45- const keyObj = { } ;
46- keyObj [ encoding ] = secret ;
47-
48- const isValid = KJUR . jws . JWS . verify ( jwt , keyObj , [ 'HS256' ] ) ;
49-
50- if ( isValid ) {
51- const [ headerB64 , payloadB64 ] = jwt . split ( '.' ) ;
52- const header = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( headerB64 ) ) ;
53- const payload = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( payloadB64 ) ) ;
54-
55- headerInput . value = JSON . stringify ( header , null , 2 ) ;
56- payloadInput . value = JSON . stringify ( payload , null , 2 ) ;
57- showStatus ( true , '✅ Signature is valid' ) ;
58- } else {
59- showStatus ( false , '❌ Signature is invalid' ) ;
60- }
61- } catch ( err ) {
62- showError ( 'Verification failed: ' + err . message ) ;
73+ try {
74+ const jwt = jwtInput . value . trim ( ) ;
75+ const key = getKeyForVerify ( getAlgorithm ( ) ) ;
76+ const alg = getAlgorithm ( ) ;
77+
78+ const isValid = KJUR . jws . JWS . verify ( jwt , key , [ alg ] ) ;
79+
80+ if ( isValid ) {
81+ const [ headerB64 , payloadB64 ] = jwt . split ( '.' ) ;
82+ const header = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( headerB64 ) ) ;
83+ const payload = KJUR . jws . JWS . readSafeJSONString ( b64urlDecode ( payloadB64 ) ) ;
84+
85+ headerInput . value = JSON . stringify ( header , null , 2 ) ;
86+ payloadInput . value = JSON . stringify ( payload , null , 2 ) ;
87+ showStatus ( true , '✅ Signature is valid' ) ;
88+ } else {
89+ showStatus ( false , '❌ Signature is invalid' ) ;
6390 }
91+ } catch ( err ) {
92+ showError ( 'Verification failed: ' + err . message ) ;
93+ }
6494 }
65-
95+
6696 function encodeJWT ( ) {
67- try {
68- const header = JSON . parse ( headerInput . value . trim ( ) ) ;
69- const payload = JSON . parse ( payloadInput . value . trim ( ) ) ;
70- const secret = secretInput . value . trim ( ) ;
71- const encoding = encodingSelect . value ;
72-
73- const sHeader = JSON . stringify ( header ) ;
74- const sPayload = JSON . stringify ( payload ) ;
75-
76- const keyObj = { } ;
77- keyObj [ encoding ] = secret ;
78-
79- const jwt = KJUR . jws . JWS . sign ( header . alg || 'HS256' , sHeader , sPayload , keyObj ) ;
80-
81- jwtInput . value = jwt ;
82- showStatus ( '' , '✅ JWT encoded successfully' ) ;
83- } catch ( err ) {
84- showError ( 'Encoding failed: ' + err . message ) ;
85- }
97+ try {
98+ const header = JSON . parse ( headerInput . value . trim ( ) ) ;
99+ const payload = JSON . parse ( payloadInput . value . trim ( ) ) ;
100+ const alg = getAlgorithm ( ) ;
101+
102+ header . alg = alg ; // force-match selected alg
103+ const sHeader = JSON . stringify ( header ) ;
104+ const sPayload = JSON . stringify ( payload ) ;
105+ const key = getKeyForSign ( alg ) ;
106+
107+ const jwt = KJUR . jws . JWS . sign ( alg , sHeader , sPayload , key ) ;
108+
109+ jwtInput . value = jwt ;
110+ if ( encodedOutput ) encodedOutput . innerText = jwt ;
111+ showStatus ( '' , '✅ JWT encoded successfully' ) ;
112+ } catch ( err ) {
113+ showError ( 'Encoding failed: ' + err . message ) ;
114+ }
86115 }
87-
116+
88117 function b64urlDecode ( str ) {
89- str = str . replace ( / - / g, '+' ) . replace ( / _ / g, '/' ) ;
90- while ( str . length % 4 !== 0 ) str += '=' ;
91- return atob ( str ) ;
118+ str = str . replace ( / - / g, '+' ) . replace ( / _ / g, '/' ) ;
119+ while ( str . length % 4 !== 0 ) str += '=' ;
120+ return atob ( str ) ;
92121 }
93-
122+
94123 function showError ( msg ) {
95- verifyStatus . innerText = '❌ ' + msg ;
96- verifyStatus . className = 'text-danger font-weight-bold' ;
124+ verifyStatus . innerText = '❌ ' + msg ;
125+ verifyStatus . className = 'text-danger font-weight-bold' ;
97126 }
98-
127+
99128 function showStatus ( valid , msg ) {
100- verifyStatus . innerText = valid === true
101- ? '✅ Signature is valid'
102- : valid === false
103- ? '❌ Signature is invalid'
104- : msg || '' ;
105- verifyStatus . className = valid === true
106- ? 'text-success font-weight-bold'
107- : 'text-danger font-weight-bold' ;
129+ verifyStatus . innerText = valid === true
130+ ? '✅ Signature is valid'
131+ : valid === false
132+ ? '❌ Signature is invalid'
133+ : msg || '' ;
134+ verifyStatus . className = valid === true
135+ ? 'text-success font-weight-bold'
136+ : 'text-danger font-weight-bold' ;
108137 }
109- } ) ;
138+ } ) ;
139+
0 commit comments