{"id":10239,"date":"2026-08-15T00:22:33","date_gmt":"2026-08-14T22:22:33","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/werkzeuge\/jwt-oauth-token-inspector\/"},"modified":"2026-08-15T00:22:33","modified_gmt":"2026-08-14T22:22:33","slug":"jwt-oauth-token-inspector","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/","title":{"rendered":"JWT- und OAuth-Token untersuchen"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Ein JSON Web Token ist unterschrieben, nicht verschl\u00fcsselt: wer es besitzt, liest den Inhalt. Hier werden Kopf und Rumpf entschl\u00fcsselt, die Laufzeit nachgerechnet und auf Wunsch die HS256-Signatur nachgerechnet, ohne dass das Geheimnis den Browser verl\u00e4sst.<\/p>\n<p>    <label for=\"jwt-eingabe\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Token (ein vorangestelltes Bearer wird \u00fcbergangen)<\/label><br \/>\n    <textarea id=\"jwt-eingabe\" class=\"form-control\" style=\"width: 100%; height: 130px; padding: 12px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; font-size: 0.85rem; box-sizing: border-box;\" placeholder=\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"><\/textarea><\/p>\n<p>    <label for=\"jwt-geheimnis\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin: 15px 0 5px;\">Gemeinsames Geheimnis f\u00fcr HS256 (optional)<\/label><br \/>\n    <input type=\"text\" id=\"jwt-geheimnis\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" placeholder=\"nur n\u00f6tig, um die Signatur nachzurechnen\"><\/p>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap; margin: 18px 0 0;\">\n        <button id=\"jwt-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: #0b1114; border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Untersuchen<\/button><br \/>\n        <button id=\"jwt-beispiel\" class=\"button\" type=\"button\" style=\"background: transparent; color: var(--text-primary, #e8e8ee); border: 1px solid var(--border, #2a2a35); padding: 12px 20px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Beispiel laden<\/button>\n    <\/div>\n<div id=\"jwt-ergebnis\" style=\"margin-top: 22px;\"><\/div>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Ein JSON Web Token ist unterschrieben, nicht verschl\u00fcsselt: wer es besitzt, liest den Inhalt. Hier werden Kopf und Rumpf entschl\u00fcsselt, die Laufzeit nachgerechnet und auf Wunsch die HS256-Signatur nachgerechnet, ohne dass das Geheimnis den Browser verl\u00e4sst.\",\"label_token\":\"Token (ein vorangestelltes Bearer wird \u00fcbergangen)\",\"label_geheimnis\":\"Gemeinsames Geheimnis f\u00fcr HS256 (optional)\",\"ph_geheimnis\":\"nur n\u00f6tig, um die Signatur nachzurechnen\",\"knopf\":\"Untersuchen\",\"beispiel\":\"Beispiel laden\",\"fehler_leer\":\"Es wurde kein Token eingegeben.\",\"fehler_form\":\"Ein JWT besteht aus mindestens zwei durch Punkte getrennten Teilen.\",\"fehler_jwe\":\"Das sieht nach einem verschl\u00fcsselten Token (JWE) mit f\u00fcnf Teilen aus, das sich ohne Schl\u00fcssel nicht lesen l\u00e4sst.\",\"fehler_base64\":\"Kopf oder Rumpf ist kein g\u00fcltiges websicheres Base64.\",\"fehler_kopf_json\":\"Der Kopf ist kein g\u00fcltiges JSON.\",\"fehler_rumpf_json\":\"Der Rumpf ist kein g\u00fcltiges JSON.\",\"h_befunde\":\"Befunde\",\"h_kopf\":\"Kopf\",\"h_ansprueche\":\"Anspr\u00fcche\",\"h_bereiche\":\"Bereiche\",\"h_signatur\":\"Signatur\",\"tag\":\"Tag\",\"tage\":\"Tage\",\"stunde\":\"Stunde\",\"stunden\":\"Stunden\",\"minute\":\"Minute\",\"minuten\":\"Minuten\",\"sekunden\":\"Sekunden\",\"b_alg_none\":\"Das Verfahren lautet none: dieses Token tr\u00e4gt \u00fcberhaupt keine Signatur und l\u00e4sst sich von jedem umschreiben.\",\"b_alg_fehlt\":\"Der Kopf nennt kein Verfahren, das akzeptiert keine Bibliothek.\",\"b_ohne_signatur\":\"Der dritte Teil fehlt, obwohl der Kopf ein Verfahren nennt - angekommen sind nur Kopf und Rumpf.\",\"b_ohne_exp\":\"Es gibt keinen exp-Anspruch: dieses Token l\u00e4uft von allein nie ab.\",\"b_abgelaufen\":\"Vor %s abgelaufen.\",\"b_laeuft_ab\":\"Noch %s g\u00fcltig.\",\"b_lang\":\"Die Restlaufzeit von %s ist f\u00fcr ein Zugriffstoken ungew\u00f6hnlich lang, das ist der Bereich eines Auffrischungstokens.\",\"b_noch_nicht\":\"Noch nicht g\u00fcltig, nbf liegt %s in der Zukunft.\",\"b_zukunft\":\"Der Ausstellungszeitpunkt liegt in der Zukunft, das deutet auf eine falsch gehende Uhr hin.\",\"b_heikel\":\"Der Rumpf tr\u00e4gt Felder mit Personenbezug: %s. Base64 ist keine Verschl\u00fcsselung, jeder Besitzer des Tokens liest sie mit.\",\"b_ohne_aud\":\"Es gibt keinen aud-Anspruch, das Token sagt also nicht, f\u00fcr welchen Dienst es gedacht war.\",\"b_ohne_iss\":\"Es gibt keinen iss-Anspruch, damit l\u00e4sst sich der Aussteller nicht pr\u00fcfen.\",\"s_erklaerung\":\"Das Entschl\u00fcsseln sagt nichts \u00fcber die Echtheit. Das tut allein die Signatur, und f\u00fcr ihre Pr\u00fcfung braucht es den Schl\u00fcssel: bei HS256 das gemeinsame Geheimnis, bei RS256 und ES256 den \u00f6ffentlichen Schl\u00fcssel des Ausstellers.\",\"s_pruefe\":\"wird gepr\u00fcft ...\",\"s_gueltig\":\"Die HS256-Signatur passt zum Geheimnis.\",\"s_ungueltig\":\"Die HS256-Signatur passt nicht zu diesem Geheimnis.\",\"s_keine_signatur\":\"Es ist kein Signaturteil vorhanden, es gibt nichts nachzurechnen.\",\"s_nur_hs256\":\"Nachgerechnet wird hier nur HS256; dieses Token nutzt %s und br\u00e4uchte den \u00f6ffentlichen Schl\u00fcssel des Ausstellers.\",\"s_kein_geheimnis\":\"F\u00fcr die Nachrechnung fehlt das gemeinsame Geheimnis.\",\"s_keine_krypto\":\"Dieser Browser bietet keine Krypto-Schnittstelle f\u00fcr die Nachrechnung.\"};<\/p>\n<p>    \/\/ --- reine Auswertung ---<\/p>\n<p>    \/\/ Felder, die einen Personenbezug tragen. Der Rumpf eines JWT ist nur\n    \/\/ kodiert, nicht verschluesselt - alles hier steht fuer jeden lesbar da,\n    \/\/ der den Token in die Finger bekommt.\n    const HEIKEL = ['email', 'e_mail', 'mail', 'name', 'given_name', 'family_name', 'nickname',\n        'preferred_username', 'phone', 'phone_number', 'address', 'birthdate', 'gender',\n        'picture', 'ssn', 'password', 'secret', 'api_key', 'credit_card'];<\/p>\n<p>    const ZEITFELDER = ['exp', 'iat', 'nbf', 'auth_time', 'updated_at'];<\/p>\n<p>    function vonBase64Url(text) {\n        let s = String(text).replace(\/-\/g, '+').replace(\/_\/g, '\/');\n        while (s.length % 4 !== 0) { s += '='; }\n        let roh;\n        try {\n            roh = atob(s);\n        } catch (e) {\n            return null;\n        }\n        \/\/ atob liefert Bytes; fuer Umlaute und alles jenseits von ASCII muss\n        \/\/ daraus noch UTF-8 werden.\n        try {\n            const bytes = new Uint8Array(roh.length);\n            for (let i = 0; i < roh.length; i++) { bytes[i] = roh.charCodeAt(i); }\n            return new TextDecoder('utf-8').decode(bytes);\n        } catch (e) {\n            return roh;\n        }\n    }\n\n    function datumText(sekunden) {\n        const ms = Number(sekunden) * 1000;\n        if (!isFinite(ms)) { return '-'; }\n        const d = new Date(ms);\n        function zwei(n) { return (n < 10 ? '0' : '') + n; }\n        return d.getUTCFullYear() + '-' + zwei(d.getUTCMonth() + 1) + '-' + zwei(d.getUTCDate())\n            + ' ' + zwei(d.getUTCHours()) + ':' + zwei(d.getUTCMinutes()) + ':' + zwei(d.getUTCSeconds()) + ' UTC';\n    }\n\n    function dauerText(sekunden) {\n        let s = Math.abs(Math.floor(sekunden));\n        const tage = Math.floor(s \/ 86400);\n        s -= tage * 86400;\n        const stunden = Math.floor(s \/ 3600);\n        s -= stunden * 3600;\n        const minuten = Math.floor(s \/ 60);\n        const teile = [];\n        if (tage) { teile.push(tage + ' ' + (tage === 1 ? T.tag : T.tage)); }\n        if (stunden) { teile.push(stunden + ' ' + (stunden === 1 ? T.stunde : T.stunden)); }\n        if (minuten &#038;&#038; !tage) { teile.push(minuten + ' ' + (minuten === 1 ? T.minute : T.minuten)); }\n        if (!teile.length) { teile.push((s % 60) + ' ' + T.sekunden); }\n        return teile.join(', ');\n    }\n\n    function feldZerlegen(text) {\n        const roh = String(text === undefined || text === null ? '' : text).trim();\n        const ergebnis = {\n            ok: false, fehler: '', teile: 0,\n            kopf: null, rumpf: null, signatur: '',\n            kopfRoh: '', rumpfRoh: '', befunde: [], ansprueche: []\n        };\n        if (roh === '') { ergebnis.fehler = T.fehler_leer; return ergebnis; }\n\n        \/\/ Ein vorangestelltes Bearer stoert nur.\n        const ohneBearer = roh.replace(\/^bearer\\s+\/i, '').trim();\n        const teile = ohneBearer.split('.');\n        ergebnis.teile = teile.length;\n\n        if (teile.length < 2) { ergebnis.fehler = T.fehler_form; return ergebnis; }\n        if (teile.length > 5) { ergebnis.fehler = T.fehler_jwe; return ergebnis; }<\/p>\n<p>        const kopfText = vonBase64Url(teile[0]);\n        const rumpfText = vonBase64Url(teile[1]);\n        if (kopfText === null || rumpfText === null) { ergebnis.fehler = T.fehler_base64; return ergebnis; }\n        ergebnis.kopfRoh = kopfText;\n        ergebnis.rumpfRoh = rumpfText;<\/p>\n<p>        try {\n            ergebnis.kopf = JSON.parse(kopfText);\n        } catch (e) {\n            ergebnis.fehler = T.fehler_kopf_json;\n            return ergebnis;\n        }\n        try {\n            ergebnis.rumpf = JSON.parse(rumpfText);\n        } catch (e) {\n            ergebnis.fehler = T.fehler_rumpf_json;\n            return ergebnis;\n        }\n        if (!ergebnis.rumpf || typeof ergebnis.rumpf !== 'object') {\n            ergebnis.fehler = T.fehler_rumpf_json;\n            return ergebnis;\n        }<\/p>\n<p>        ergebnis.signatur = teile.length > 2 ? teile[2] : '';\n        ergebnis.ok = true;\n        return ergebnis;\n    }<\/p>\n<p>    function bewerten(zerlegt, jetzt) {\n        const befunde = [];\n        const zeit = Math.floor(Number(jetzt) \/ 1000);\n        const kopf = zerlegt.kopf || {};\n        const rumpf = zerlegt.rumpf || {};<\/p>\n<p>        const alg = String(kopf.alg === undefined ? '' : kopf.alg);\n        if (alg.toLowerCase() === 'none') {\n            befunde.push({ schwer: true, text: T.b_alg_none });\n        }\n        if (alg === '') {\n            befunde.push({ schwer: true, text: T.b_alg_fehlt });\n        }\n        if (zerlegt.signatur === '' && alg.toLowerCase() !== 'none') {\n            befunde.push({ schwer: true, text: T.b_ohne_signatur });\n        }<\/p>\n<p>        if (rumpf.exp === undefined) {\n            befunde.push({ schwer: true, text: T.b_ohne_exp });\n        } else {\n            const rest = Number(rumpf.exp) - zeit;\n            if (rest <= 0) {\n                befunde.push({ schwer: true, text: T.b_abgelaufen.replace('%s', dauerText(rest)) });\n            } else {\n                befunde.push({ schwer: false, text: T.b_laeuft_ab.replace('%s', dauerText(rest)) });\n                if (rest > 60 * 60 * 24 * 30) {\n                    befunde.push({ schwer: true, text: T.b_lang.replace('%s', dauerText(rest)) });\n                }\n            }\n        }\n        if (rumpf.nbf !== undefined && Number(rumpf.nbf) > zeit) {\n            befunde.push({ schwer: true, text: T.b_noch_nicht.replace('%s', dauerText(Number(rumpf.nbf) - zeit)) });\n        }\n        if (rumpf.iat !== undefined) {\n            const alter = zeit - Number(rumpf.iat);\n            if (alter < -300) {\n                befunde.push({ schwer: true, text: T.b_zukunft });\n            }\n        }\n\n        const heikel = [];\n        Object.keys(rumpf).forEach(function (schluessel) {\n            if (HEIKEL.indexOf(String(schluessel).toLowerCase()) !== -1) { heikel.push(schluessel); }\n        });\n        if (heikel.length) {\n            befunde.push({ schwer: false, text: T.b_heikel.replace('%s', heikel.join(', ')) });\n        }\n\n        if (rumpf.aud === undefined) { befunde.push({ schwer: false, text: T.b_ohne_aud }); }\n        if (rumpf.iss === undefined) { befunde.push({ schwer: false, text: T.b_ohne_iss }); }\n\n        return befunde;\n    }\n\n    function ansprueche(rumpf) {\n        const liste = [];\n        Object.keys(rumpf || {}).forEach(function (name) {\n            const wert = rumpf[name];\n            let text;\n            if (ZEITFELDER.indexOf(name) !== -1 &#038;&#038; typeof wert === 'number') {\n                text = datumText(wert) + '  (' + wert + ')';\n            } else if (wert === null) {\n                text = 'null';\n            } else if (typeof wert === 'object') {\n                text = JSON.stringify(wert);\n            } else {\n                text = String(wert);\n            }\n            liste.push({ name: name, wert: text, roh: wert });\n        });\n        return liste;\n    }\n\n    function bereiche(rumpf) {\n        \/\/ scope kommt als Zeichenkette mit Leerzeichen, scp gern als Feld.\n        const raus = [];\n        if (typeof rumpf.scope === 'string') {\n            rumpf.scope.split(\/\\s+\/).forEach(function (s) { if (s) { raus.push(s); } });\n        }\n        if (Array.isArray(rumpf.scp)) {\n            rumpf.scp.forEach(function (s) { raus.push(String(s)); });\n        } else if (typeof rumpf.scp === 'string') {\n            rumpf.scp.split(\/\\s+\/).forEach(function (s) { if (s) { raus.push(s); } });\n        }\n        if (Array.isArray(rumpf.permissions)) {\n            rumpf.permissions.forEach(function (s) { raus.push(String(s)); });\n        }\n        return raus;\n    }\n\n    function untersuchen(text, jetzt) {\n        const zerlegt = feldZerlegen(text);\n        if (!zerlegt.ok) { return zerlegt; }\n        zerlegt.befunde = bewerten(zerlegt, jetzt);\n        zerlegt.ansprueche = ansprueche(zerlegt.rumpf);\n        zerlegt.bereiche = bereiche(zerlegt.rumpf);\n        return zerlegt;\n    }\n\n    \/**\n     * HS256 nachrechnen. Das Geheimnis bleibt im Browser, gerechnet wird mit\n     * der eingebauten Krypto-Schnittstelle.\n     *\/\n    function pruefeHS256(token, geheimnis) {\n        const teile = String(token).replace(\/^bearer\\s+\/i, '').trim().split('.');\n        if (teile.length < 3 || !teile[2]) {\n            return Promise.resolve({ moeglich: false, grund: T.s_keine_signatur });\n        }\n        const zerlegt = feldZerlegen(token);\n        if (!zerlegt.ok) { return Promise.resolve({ moeglich: false, grund: zerlegt.fehler }); }\n        const alg = String((zerlegt.kopf || {}).alg || '').toUpperCase();\n        if (alg !== 'HS256') {\n            return Promise.resolve({ moeglich: false, grund: T.s_nur_hs256.replace('%s', alg || '?') });\n        }\n        if (!geheimnis) {\n            return Promise.resolve({ moeglich: false, grund: T.s_kein_geheimnis });\n        }\n        if (!window.crypto || !window.crypto.subtle) {\n            return Promise.resolve({ moeglich: false, grund: T.s_keine_krypto });\n        }\n\n        const kodierer = new TextEncoder();\n        const daten = kodierer.encode(teile[0] + '.' + teile[1]);\n        return window.crypto.subtle.importKey(\n            'raw', kodierer.encode(geheimnis), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']\n        ).then(function (schluessel) {\n            return window.crypto.subtle.sign('HMAC', schluessel, daten);\n        }).then(function (unterschrift) {\n            const bytes = new Uint8Array(unterschrift);\n            let roh = '';\n            for (let i = 0; i < bytes.length; i++) { roh += String.fromCharCode(bytes[i]); }\n            const meins = btoa(roh).replace(\/\\+\/g, '-').replace(\/\\\/\/g, '_').replace(\/=+$\/, '');\n            return { moeglich: true, gueltig: meins === teile[2], erwartet: meins };\n        }).catch(function (e) {\n            return { moeglich: false, grund: (e &#038;&#038; e.message) ? e.message : T.s_keine_krypto };\n        });\n    }\n\n    if (typeof window !== 'undefined') {\n        window.LW_TEST = window.LW_TEST || {};\n        window.LW_TEST.JWT = {\n            untersuchen: untersuchen,\n            feldZerlegen: feldZerlegen,\n            pruefeHS256: pruefeHS256,\n            vonBase64Url: vonBase64Url,\n            dauerText: dauerText,\n            datumText: datumText,\n            bereiche: bereiche\n        };\n    }\n\n    \/\/ --- Anbindung an das Dokument ---\n\n    const btn = document.getElementById('jwt-btn');\n    const out = document.getElementById('jwt-ergebnis');\n    const feld = document.getElementById('jwt-eingabe');\n    const geheimFeld = document.getElementById('jwt-geheimnis');\n    const beispielBtn = document.getElementById('jwt-beispiel');\n    if (!btn || !out || !feld || !geheimFeld || !beispielBtn) { return; }\n\n    const KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 14px; margin-bottom: 18px;';\n    const UEBERSCHRIFT = 'color: var(--text-primary, #e8e8ee); font-weight: 700; margin-bottom: 8px;';\n\n    function el(tag, css, text) {\n        const knoten = document.createElement(tag);\n        if (css) { knoten.setAttribute('style', css); }\n        if (text !== undefined &#038;&#038; text !== null) { knoten.textContent = text; }\n        return knoten;\n    }\n\n    function meldung(text) {\n        out.textContent = '';\n        out.appendChild(el('div', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left: 3px solid var(--accent, #7ee787); color: var(--text-secondary, #a0a0b0); padding: 14px; border-radius: 6px;', text));\n    }\n\n    function zeigen(erg) {\n        out.textContent = '';\n\n        if (erg.befunde.length) {\n            out.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n            const kasten = el('div', KASTEN);\n            erg.befunde.forEach(function (b) {\n                const z = el('div', 'display: flex; gap: 10px; padding: 5px 0;');\n                z.appendChild(el('span', 'color: ' + (b.schwer ? '#ffb86c' : 'var(--accent, #7ee787)') + '; font-family: monospace;', b.schwer ? '!' : '+'));\n                z.appendChild(el('span', 'color: var(--text-secondary, #a0a0b0); font-size: 0.9rem; line-height: 1.5;', b.text));\n                kasten.appendChild(z);\n            });\n            out.appendChild(kasten);\n        }\n\n        out.appendChild(el('div', UEBERSCHRIFT, T.h_kopf));\n        const kopf = el('pre', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); padding: 16px; border-radius: 6px; overflow-x: auto; font-family: monospace; font-size: 0.85rem; white-space: pre-wrap; word-break: break-all; margin-bottom: 18px;');\n        kopf.textContent = JSON.stringify(erg.kopf, null, 2);\n        out.appendChild(kopf);\n\n        out.appendChild(el('div', UEBERSCHRIFT, T.h_ansprueche));\n        const tabelle = el('div', KASTEN);\n        erg.ansprueche.forEach(function (a) {\n            const z = el('div', 'display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding: 5px 0; border-bottom: 1px solid var(--border, #2a2a35);');\n            z.appendChild(el('span', 'color: var(--text-secondary, #a0a0b0); font-family: monospace;', a.name));\n            z.appendChild(el('span', 'color: var(--text-primary, #e8e8ee); font-family: monospace; text-align: right; word-break: break-all; max-width: 70%;', a.wert));\n            tabelle.appendChild(z);\n        });\n        out.appendChild(tabelle);\n\n        if (erg.bereiche &#038;&#038; erg.bereiche.length) {\n            out.appendChild(el('div', UEBERSCHRIFT, T.h_bereiche));\n            const kasten = el('div', KASTEN);\n            erg.bereiche.forEach(function (b) {\n                kasten.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-family: monospace; font-size: 0.85rem; padding: 3px 0;', b));\n            });\n            out.appendChild(kasten);\n        }\n\n        out.appendChild(el('div', UEBERSCHRIFT, T.h_signatur));\n        const sig = el('div', KASTEN);\n        sig.appendChild(el('div', 'color: var(--text-secondary, #a0a0b0); font-size: 0.9rem; line-height: 1.6;', T.s_erklaerung));\n        const stand = el('div', 'color: var(--text-secondary, #a0a0b0); font-family: monospace; font-size: 0.85rem; padding-top: 8px;', T.s_pruefe);\n        sig.appendChild(stand);\n        out.appendChild(sig);\n\n        pruefeHS256(feld.value, geheimFeld.value).then(function (ergebnis) {\n            if (!ergebnis.moeglich) {\n                stand.textContent = ergebnis.grund;\n                stand.style.color = 'var(--text-secondary, #a0a0b0)';\n                return;\n            }\n            stand.textContent = ergebnis.gueltig ? T.s_gueltig : T.s_ungueltig;\n            stand.style.color = ergebnis.gueltig ? 'var(--accent, #7ee787)' : '#ffb86c';\n        });\n    }\n\n    btn.addEventListener('click', function () {\n        const erg = untersuchen(feld.value, Date.now());\n        if (!erg.ok) { meldung(erg.fehler); return; }\n        zeigen(erg);\n    });\n\n    beispielBtn.addEventListener('click', function () {\n        \/\/ Beispieltoken mit dem Geheimnis \"lukaswojcik\" unterschrieben.\n        feld.value = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImxvZ2luLTIwMjYifQ.eyJpc3MiOiJodHRwczovL3d3dy5sdWthc3dvamNpay5jb20iLCJzdWIiOiIxNDIiLCJhdWQiOiJ3cC1yZXN0IiwiaWF0IjoxNzg1NTc4NDAwLCJuYmYiOjE3ODU1Nzg0MDAsImV4cCI6MTc4NTU4MjAwMCwianRpIjoiYTNmOWMyIiwic2NvcGUiOiJwb3N0czpyZWFkIHBvc3RzOndyaXRlIiwiZW1haWwiOiJyZWRha3Rpb25AZXhhbXBsZS5jb20ifQ.fJnDPZw_ogedOHA5uiKr_0IcnJVZfUa5pygLEx7ykDM';\n        geheimFeld.value = 'lukaswojcik';\n        btn.click();\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Entschl\u00fcsselt ein JSON Web Token im Browser, rechnet die Restlaufzeit aus, listet die Bereiche auf und benennt fehlende Signaturen, endlose Laufzeiten oder personenbezogene Felder im Rumpf.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9283,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92048,92340,92071],"class_list":["post-10239","page","type-page","status-publish","hentry","tag-rest-api-de","tag-server-administration-de","tag-web-security-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Entschl\u00fcsselt ein JSON Web Token im Browser, rechnet die Restlaufzeit aus, listet die Bereiche auf und benennt fehlende Signaturen, endlose Laufzeiten oder personenbezogene Felder im Rumpf.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/jwt-oauth-token-inspector\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/jwt-oauth-token-inspector\\\/\",\"name\":\"JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-08-14T22:22:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/jwt-oauth-token-inspector\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/jwt-oauth-token-inspector\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/jwt-oauth-token-inspector\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-2\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"JWT- und OAuth-Token untersuchen\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/","og_locale":"en_US","og_type":"article","og_title":"JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog","og_description":"Entschl\u00fcsselt ein JSON Web Token im Browser, rechnet die Restlaufzeit aus, listet die Bereiche auf und benennt fehlende Signaturen, endlose Laufzeiten oder personenbezogene Felder im Rumpf.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/","url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/","name":"JWT- und OAuth-Token untersuchen - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-08-14T22:22:33+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/jwt-oauth-token-inspector\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-2\/"},{"@type":"ListItem","position":3,"name":"JWT- und OAuth-Token untersuchen"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=10239"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10239\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9283"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=10239"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=10239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}