Categorie: Story

  • JWT-parser gids: JSON Web Tokens veilig decoderen, valideren en inspecteren

    JWT-parser gids: JSON Web Tokens veilig decoderen, valideren en inspecteren

    Je authenticatie is zojuist in productie stukgegaan. Gebruikers krijgen “Invalid Token”-fouten en je moet snel uitzoeken waarom. Je maakt de JWT open en het lijkt op onzin: drie blokken willekeurige tekens gescheiden door punten. De gegevens zitten erin, maar zonder een parser kun je ze niet lezen.

    Een JWT-parser is een gespecialiseerde tool die de drie delen van een JSON Web Token — Header, Payload en Signature — opsplitst volgens de RFC 7519-standaard. Vanaf april 2026 decoderen deze parsers Base64URL-gecodeerde gegevens en verifiëren ze handtekeningen met secrets of public keys om ervoor te zorgen dat het token niet is gemanipuleerd, waarmee ze bedreigingen zoals de “alg: none”-aanval blokkeren.

    Wat een JWT-parser echt doet

    Beschouw een JWT-parser als een vertaler. Het neemt een lange, ondoorzichtige tekenreeks en zet deze terug om naar leesbare JSON-objecten. Dit is fundamenteel voor het beheren van gebruikersidentiteiten en het beveiligen van gegevensuitwisseling in moderne applicaties.

    Intern zoekt de parser de twee punten (.) op die het token in drie secties verdelen:

    Sectie Doel Gecodeerd? Leesbaar zonder key?
    Header Metadata: ondertekeningsalgoritme (HS256, RS256) Base64URL Ja
    Payload Claims: gebruikersgegevens, vervaldatum, rollen Base64URL Ja
    Signature Digitale verzegeling die authenticiteit bewijst HMAC/RSA Nee — vereist key

    Vereenvoudigde structuur van een JWT-token in drie delen

    Stapsgewijs decoderen: wat er vanbinnen gebeurt

    Laten we een echt token doorlopen. Neem deze voorbeeld-JWT:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE3MDAwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

    Stap 1: Splitsen op punten

    [0] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    [1] eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE3MDAwMDAwMDB9
    [2] SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

    Stap 2: Base64URL-decode sectie [0] (Header)

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    

    Stap 3: Base64URL-decode sectie [1] (Payload)

    {
      "sub": "1234567890",
      "name": "John",
      "iat": 1700000000
    }
    

    Stap 4: Verifieer sectie [2] (Signature) — vereist de secret key

    De parser neemt de Base64URL-gecodeerde header + “.” + payload en berekent vervolgens een HMAC-SHA256 met de secret. Als het resultaat overeenkomt met sectie [2], is het token authentiek.

    Belangrijke beveiligingsopmerking: Base64URL is geen versleuteling

    Een veelvoorkomende valkuil voor nieuwe ontwikkelaars is de aanname dat de gecodeerde header en payload zijn versleuteld. Dat zijn ze niet. Zoals JustUse.me aangeeft, maakt Base64URL-codering JSON gewoon veilig om via URL’s en headers te verzenden. Iedereen die het token heeft, kan de payload decoderen zonder wachtwoord of key.

    Bewaar nooit gevoelige gegevens (wachtwoorden, BSN’s, API-sleutels) in een JWT-payload. Ze zijn zichtbaar voor iedereen die het token onderschept.

    Handtekeningverificatie: de beveiligingspoort

    Hoewel iedereen de gegevens van een token kan lezen, is handtekeningverificatie wat je systeem daadwerkelijk veilig houdt. Een JWT-parser leest niet alleen informatie — hij bewijst waar deze vandaan komt.

    De parser berekent de handtekening opnieuw met behulp van de header, payload en een key, en controleert vervolgens of het resultaat overeenkomt met de handtekening op het token. Als ze niet overeenkomen, is het token gemanipuleerd.

    Twee algoritmefamilies

    Algoritme Key-type Hoe het werkt Veelvoorkomend gebruik
    HS256 (HMAC) Symmetrisch — dezelfde secret key voor ondertekenen en verifiëren Beide partijen delen één secret Authenticatie voor één service, microservices binnen één team
    RS256 (RSA) Asymmetrisch — private key ondertekent, public key verifieert Afzender houdt private key; iedereen met public key kan verifiëren OAuth2-providers, third-party API-integraties
    ES256 (ECDSA) Asymmetrisch —zelfde model als RSA maar met elliptische krommen Kleinere keys, snellere verificatie Mobiele apps, prestatiegevoelige services

    De verificatielogica van een JWT-parser in 3 stappen

    De “alg: none”-aanval

    Dit is een van de gevaarlijkste JWT-kwetsbaarheden. Een aanvaller past de header aan om "alg": "none" te claimen en verwijdert de handtekening. Een slecht geïmplementeerde parser zou dit kunnen accepteren en het token als geldig behandelen zonder enige verificatie.

    Verdediging: Je parser moet elk token waarvan het algoritme “none” is of niet overeenkomt met je verwachte algoritme expliciet afwijzen. Stas Persiianenko, die de Apify JWT-tool ontwikkelde, benadrukt dat hoewel tokens transparant zijn qua ontwerp, hun beveiliging afhangt van de parser die niet-ondertekende of gemanipuleerde tokens strikt afwijst.

    decoded = jwt.decode(token, key, algorithms=None)  # NEVER do this
    
    decoded = jwt.decode(token, key, algorithms=["HS256"])
    

    Standaard JWT-claims: wat elk veld betekent

    Een JWT-parser haalt “claims” uit de payload. Deze volgen het JOSE (JSON Object Signing and Encryption)-raamwerk voor compatibiliteit tussen systemen.

    Claim Volledige naam Doel Voorbeeldwaarde
    iss Issuer Wie het token heeft uitgegeven "auth.example.com"
    sub Subject De gebruiker of entiteit die het token vertegenwoordigt "user:12345"
    aud Audience Bedoelde ontvanger van het token "api.example.com"
    exp Expiration Time Wanneer het token ongeldig wordt 1700000000 (Unix-timestamp)
    iat Issued At Wanneer het token is aangemaakt 1699999999
    nbf Not Before Token is niet geldig vóór dit tijdstip 1699999999
    jti JWT ID Unieke identificatie voor het token "a1b2c3d4"

    Bij gebruik van asymmetrische handtekeningen verwijzen parsers vaak naar een JWK (JSON Web Key) — een JSON-structuur die een public key vertegenwoordigt. De parser haalt automatisch de juiste JWK op van de metadata-endpoint van de uitgever om het token te verifiëren.

    Implementatie: echte code voor productie

    PHP met lcobucci/jwt

    De standaard in het PHP-ecosysteem is lcobucci/jwt. Gegevens van Packagist tonen meer dan 322 miljoen installaties vanaf april 2026, wat het de standaardkeuze maakt voor Laravel- en Symfony-projecten.

    use Lcobucci\JWT\Configuration;
    use Lcobucci\JWT\Signer\Hmac\Sha256;
    use Lcobucci\JWT\Signer\Key\InMemory;
    
    $config = Configuration::forSymmetricSigner(
        new Sha256(),
        InMemory::plainText('your-secret-key')
    );
    
    // Parsing and validating a token
    $token = $config->parser()->parse($jwtString);
    
    // Verify constraints: expiration, issuer, etc.
    $constraints = [
        new \Lcobucci\JWT\Validation\Constraint\IssuedBy('auth.example.com'),
        new \Lcobucci\JWT\Validation\Constraint\PermittedFor('api.example.com'),
        new \Lcobucci\JWT\Validation\Constraint\SignedWith(
            $config->signer(),
            $config->signingKey()
        ),
    ];
    
    $isValid = $config->validator()->validate($token, ...$constraints);
    

    Hono (Edge/Serverless) met Web Crypto

    Voor lichtgewicht edge-applicaties biedt de Hono JWT Helper een minimale decode()-functie, perfect voor serverless platforms waar je snelle cold starts en minimale afhankelijkheden wilt.

    import { jwt } from 'hono/jwt'
    
    // Middleware to verify JWT on every request
    app.use('/api/*', jwt({ secret: 'your-secret' }))
    
    // Access decoded claims in your handler
    app.get('/api/profile', (c) => {
      const payload = c.get('jwtPayload')
      return c.json({ user: payload.sub })
    })
    

    AI-gedreven JWT-analyse met MCP

    Tegen 2026 stelt het Model Context Protocol (MCP) AI-assistenten zoals Claude Code of Cursor in staat rechtstreeks met JWT-tools te communiceren. Stel een MCP-server in en een ontwikkelaar kan een AI vragen om “Controleer alle JWT’s in deze logs op verval-fouten” — de agent handelt het parsen af via de command line.

    Volgens Apify kost bulkverwerking ongeveer $11.50 per 10.000 tokens vanaf 2026. Deze automatisering stelt AI-agents in staat verlopen tokens te vinden en direct suggesties te doen voor codefixes voor de beveiligingsinstellingen van de app.

    Conclusie

    Een JWT-parser is meer dan een gemak bij het debuggen — het is een essentiële beveiligingscontrole. Het zorgt ervoor dat tokens authentiek zijn via handtekeningcontroles en geldig via claimverificatie. Onthoud de twee regels die het meest van belang zijn: Base64URL is geen versleuteling, dus bewaar nooit secrets in de payload. En specificeer altijd expliciet toegestane algoritmes om “alg: none”-aanvallen te voorkomen.

    Gebruik voor productie-apps bewezen bibliotheken zoals lcobucci/jwt of de JWT-helper van Hono in plaats van je eigen parser te bouwen. Voor debugging en bulkanalyse zijn AI-gedreven MCP-tools de moderne aanpak om beveiligingsaudits geautomatiseerd en grondig te houden.

    FAQ

    Is het legaal om een JWT-token te decoderen dat ik in mijn browser heb gevonden?

    Ja, het is volledig legaal. JWT’s zijn ontworpen om transparant te zijn — de header en payload zijn gecodeerd voor transport, niet versleuteld voor geheimhouding. Het bezitten van het token impliceert dat je toegang hebt tot de gegevens in de claims. Houd echter altijd rekening met lokale privacywetgeving zoals de AVG/GDPR wanneer tokens persoonlijke informatie bevatten.

    Waarom toont mijn JWT-parser isExpired: true voor een token dat ik zojuist heb gegenereerd?

    Dit wordt meestal veroorzaakt door klokafwijking (clock drift) tussen de server die het token genereerde en het systeem dat het parseert. Als de klokken van de twee systemen niet gesynchroniseerd zijn (via UTC/NTP), kunnen de exp– of nbf-claims ongeldig lijken. Los dit op door ervoor te zorgen dat beide systemen NTP gebruiken voor tijdsynchronisatie, of voeg een kleine “leeway” toe (meestal 60 seconds) in je parse-bibliotheek om kleine afwijkingen op te vangen.

    Kan ik een JWT decoderen zonder de secret of public key te hebben?

    Ja, je kunt altijd de Header en Payload decoderen en lezen zonder key, omdat ze simpelweg Base64URL-gecodeerde JSON zijn. Je kunt echter de Signature niet verifiëren of erop vertrouwen dat de gegevens authentiek zijn zonder de bijbehorende secret (voor HS256) of public key (voor RS256). Zonder verificatie moet je de gegevens beschouwen als ongeverifieerd en mogelijk gemanipuleerd.

    Wat is de “alg: none”-aanval en hoe voorkom ik deze?

    De “alg: none”-aanval maakt gebruik van parsers die het in de token-header gespecificeerde algoritme accepteren zonder validatie. Een aanvaller verandert de header in "alg": "none" en verwijdert de handtekening, waardoor een kwetsbare parser wordt misleid het token als geldig te accepteren. Voorkom dit door in je verificatiecode altijd expliciet toegestane algoritmes op te geven — accepteer nooit “none” en laat het token nooit bepalen welk algoritme wordt gebruikt.