Een JSON Web Token (JWT) decoderen

decodeert een JSON Web Token en toont de header en payload in een leesbare, gestructureerde vorm

Wat is een JWT (JSON Web Token)?

Een JSON Web Token, afgekort tot JWT (uitgesproken als "jot"), is een compact formaat gedefinieerd door RFC 7519 dat het mogelijk maakt om een reeks claims (claims) tussen twee partijen te transporteren. De JWT, of JWT-token, is vandaag het dominante formaat om een geauthenticeerde identiteit te dragen in een HTTP-API. Een JWT presenteert zich als een ASCII-tekenreeks bestaande uit drie segmenten gescheiden door punten:

header.payload.signature

Elk segment is gecodeerd in Base64URL, een Base64-variant zonder padding = en die + vervangt door - en / door _ zodat het in een URL of een HTTP-header kan circuleren zonder extra escaping.

Belangrijk: een JWT is NIET versleuteld. Het standaard JWT-formaat (JWS) is gewoon ondertekend: de handtekening garandeert de integriteit van de inhoud, maar biedt geen vertrouwelijkheid. Iedereen kan de payload van een JWT decoderen met een eenvoudige omgekeerde Base64URL, zoals deze online jwt decode-tool doet.

Anatomie van een JWT

Een json web token bestaat uit drie duidelijk onderscheiden delen, elk met een precieze rol in het authenticatiemechanisme:

1. Header

De header is een JSON-object dat beschrijft hoe het token is ondertekend. Het bevat minimaal:

  • alg (algorithm): het gebruikte handtekeningsalgoritme. Typische waarden: HS256, RS256, ES256, EdDSA.
  • typ (type): het type van het token, bijna altijd "JWT".
  • kid (key ID): optioneel, identificeert welke sleutel moet worden gebruikt om de handtekening te verifiëren. Praktisch bij een park van roterende sleutels (JWKS).

2. Payload

De payload bevat de claims, dat wil zeggen de beweringen die de uitgever maakt over de gebruiker of de sessie. RFC 7519 definieert zeven standaardclaims (registered claims):

  • iss (issuer): wie het token heeft uitgegeven, bijvoorbeeld "https://accounts.google.com".
  • sub (subject): aan wie het token toebehoort, in de praktijk de gebruikersidentifier.
  • aud (audience): aan wie het token is gericht. Vermijdt dat een token uitgegeven voor API A wordt geaccepteerd door API B.
  • exp (expiration time): Unix-tijdstempel waarna het token niet meer geldig is.
  • nbf (not before): tijdstempel vóór welke het token nog niet actief is.
  • iat (issued at): tijdstempel van uitgifte van het token.
  • jti (JWT ID): unieke identifier van het token, gebruikt voor herroeping en preventie van replay.

Naast deze standaardclaims komen over het algemeen custom claims die eigen zijn aan de applicatie (roles, scope, tenant_id, email, permissions...).

3. Handtekening

De handtekening is een cryptografisch hash berekend op base64url(header) + "." + base64url(payload) met behulp van een sleutel. Zij bewijst dat niemand de header of de payload heeft gewijzigd sinds de uitgifte. De meest gangbare algoritmen:

  • HS256 / HS384 / HS512: symmetrische HMAC-SHA-handtekening. Een gedeelde geheime sleutel tussen uitgever en verificateur. Eenvoudig, maar ongeschikt zodra er meer dan één consument is.
  • RS256 / RS384 / RS512: asymmetrische RSA-handtekening. De uitgever ondertekent met zijn privésleutel, elke consument verifieert met de overeenkomstige publieke sleutel. Feitelijke standaard voor OAuth2 en OpenID Connect.
  • ES256 / ES384 / ES512: asymmetrische ECDSA-handtekening. Dezelfde eigenschappen als RS256 maar met veel kortere sleutels en handtekeningen.
  • EdDSA (Ed25519): moderne asymmetrische handtekening, snel en compact.

Nogmaals: de handtekening beschermt de integriteit, niet de vertrouwelijkheid. De payload blijft leesbaar voor iedereen die het token heeft.

Waarom een JWT decoderen?

De jwt token decode-bewerking beantwoordt verschillende concrete behoeften voor een ontwikkelaar of een security engineer:

  • Authenticatie-debug: uw API geeft een 401 of een 403 terug, u wilt zien wat er werkelijk in de payload zit (sub, scope, roles, exp) in plaats van te gokken.
  • Claims verifiëren: bevestigen dat een token de verwachte claim bevat (bijvoorbeeld tenant_id of permissions) voordat u ergens anders zoekt in de autorisatieketen.
  • De vervaldatum lezen: het exp-tijdstempel converteren naar een menselijke datum om te bevestigen dat een token inderdaad verlopen is, of integendeel dat het nog steeds geldig zou moeten zijn.
  • Beveiligingsaudit: zorgen dat een service van derden geen gevoelige informatie lekt in de payload (e-mails, interne identifiers, persoonsgegevens).
  • Training en begrip: concreet zien hoe een jsonwebtoken van een OAuth-provider (Google, Auth0, Keycloak, AWS Cognito) eruitziet om de mechaniek te begrijpen zonder in de documentatie te duiken.
  • Verkenning van publieke tokens: een JWT inspecteren die is gevonden in logs, in een cookie of in een onderschepbare OAuth-uitwisseling.

Decoder vs Verifier: het kritieke onderscheid

Beide bewerkingen lijken naburig, maar ze hebben niets te maken in termen van beveiligingsgaranties:

  • Een JWT decoderen bestaat uit het splitsen van de tekenreeks op de . en een omgekeerde Base64URL toepassen op de eerste twee segmenten. Het is een eenvoudige lezing, binnen het bereik van elk script van drie regels. Er wordt geen handtekeningverificatie uitgevoerd.
  • Een JWT verifiëren bestaat uit het herberekenen van de handtekening vanuit de header, de payload en een sleutel, en vervolgens het resultaat te vergelijken met de handtekening die in het token aanwezig is. Het is wat garandeert dat het token niet is vervalst.

Praktische conclusie: decoderen is niet vertrouwen. Zolang de handtekening niet met de juiste sleutel is geverifieerd, kan de inhoud van de payload totaal nep zijn. Voor de vertrouwensfase, gebruik onze JWT Verifier.

Hoe u het gebruikt

  1. Haal de te inspecteren JWT op, bijvoorbeeld uit een Authorization: Bearer <jwt>-header, uit een sessiecookie, uit de localStorage van de browser, of uit een applicatielog.
  2. Plak de volledige tekenreeks in het invoerveld. De drie segmenten moeten gescheiden blijven door punten.
  3. De tool toont onmiddellijk de header gedecodeerd in opgemaakte JSON, met het algoritme en het type.
  4. De payload wordt vervolgens gedecodeerd en weergegeven. U ziet daar alle standaard- en custom-claims.
  5. De tool geeft ook de handtekeninginformatie aan (gedeclareerd algoritme, lengte), zonder deze te verifiëren.
  6. Om te bevestigen dat het token niet is vervalst, schakel naar onze JWT Verifier met de verwachte publieke sleutel of geheim.

Alle decodering wordt uitgevoerd in uw browser in JavaScript: uw token wordt nooit verzonden naar onze servers.

JWT en beveiliging: valkuilen om te vermijden

Sla NOOIT gevoelige gegevens op in de payload van een ondertekende JWT.

Wachtwoorden, creditcardnummers, medische gegevens, API-geheimen, kritieke interne identifiers: alles wat in de payload staat is leesbaar voor iedereen die het token heeft, inclusief de gebruiker zelf via de ontwikkelaarstools van zijn browser. De handtekening verbergt niets, hij bewijst alleen dat de uitgever inderdaad is wie hij beweert te zijn.

Enkele gouden regels om JWT's goed te gebruiken in productie:

  • Verifieer altijd de handtekening aan de serverkant voor het toekennen van enig recht. Onze JWT Verifier illustreert precies deze bewerking.
  • Verkies RS256 of ES256 boven HS256 voor publieke API's. Asymmetrische handtekening vermijdt het delen van een geheim tussen de uitgever en elke consument.
  • Respecteer altijd de exp-claim. Een JWT zonder vervaldatum of met een te verre vervaldatum is een tijdbom in geval van een lek.
  • Valideer iss en aud aan de serverkant, om te voorkomen dat een legitiem token uitgegeven voor een andere service per ongeluk wordt geaccepteerd.
  • Weiger alg: "none" aan de verificatiekant. Het is een klassieke kwetsbaarheid die een aanvaller in staat stelt om elke payload te smeden.
  • Houd de levensduren kort (15 minuten bijvoorbeeld) en koppel met een langere maar herroepbare refresh token aan de serverkant.

Voorbeeld van een gedecodeerd JWT-token

Hier is een typische JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiSm9obiIsImlhdCI6MTUxNjIzOTAyMn0.jrU9j8LZcRK2_BZjqXjU7lEpJbkqmXfTQIu9vT45j-I

Eenmaal gedecodeerd, hier is de inhoud:

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

// Payload
{
  "sub": "123",
  "name": "John",
  "iat": 1516239022
}

// Signature (binaire, encodé en Base64URL)
HMACSHA256(
  base64url(header) + "." + base64url(payload),
  secret
)

Waar vind ik een JWT om te kopiëren?

In de praktijk komt een te ontsleutelen JWT (in de zin van decoderen) meestal uit een van deze locaties:

  • HTTP-cookie: open de ontwikkelaarstools (F12), tabblad Application of Storage, vervolgens Cookies. Vind een cookie genaamd access_token, jwt, session of vergelijkbaar.
  • localStorage / sessionStorage: hetzelfde paneel, sectie Local Storage. Veel SPA's slaan daar hun token op onder een sleutel token of auth.
  • Authorization-header: tabblad Network, selecteer een API-aanvraag, lees de Authorization: Bearer <jwt>-header. Kopieer alleen het deel na Bearer .
  • Serverlogs: een JWT verschijnt soms in de logs van een gateway of een reverse proxy (te vermijden in productie, maar nuttig in debug).

Veelgestelde vragen

Is de JWT versleuteld of in cleartext?

Een ondertekende JWT (JWS-formaat) is alleen gecodeerd in Base64URL, niet versleuteld. Iedereen die een token onderschept, kan de payload in enkele seconden lezen. Als u werkelijk vertrouwelijke gegevens in het token moet vervoeren, moet u het JWE-formaat (JSON Web Encryption) gebruiken, dat een versleutelingslaag toevoegt bovenop de handtekening. In de praktijk blijft JWE zeldzaam: men geeft er de voorkeur aan geen gevoelige gegevens in een token te plaatsen en de kritieke informatie aan de serverkant in de database te houden.

Hoe herroep ik een JWT voor zijn vervaldatum?

Het is een van de zwakke punten van JWT: door constructie hoeft de server de status van het token niet op te slaan, dus hij weet ook niet hoe hij het als herroepen moet markeren. Drie benaderingen bestaan. Herroepingslijst: aan de serverkant de lijst van ongeldige jti's onderhouden, en deze bij elke aanvraag raadplegen. Korte levensduren: access tokens uitgeven die 5 tot 15 minuten geldig zijn, en een aan de serverkant herroepbare refresh token gebruiken om er nieuwe te genereren. Rotatie van de handtekeningsleutel: een hele generatie tokens ongeldig maken door de sleutel te veranderen. De tweede benadering is verreweg de meest verspreid.

Wat is het verschil tussen een JWT en een klassieke sessie?

Een klassieke sessie slaat een ondoorzichtige identifier op aan de clientkant (meestal in een cookie) en bewaart alle bijbehorende gegevens (gebruiker, rechten, vervaldatum) in geheugen of in een database aan de serverkant. Een JWT daarentegen vervoert deze gegevens rechtstreeks in het ondertekende token. Voordeel van JWT: de server hoeft geen sessie op te slaan, wat horizontale scaling en microservices-architectuur vereenvoudigt. Nadelen: herroeping is complexer, het token is omvangrijker bij elke aanvraag, en het minste lek stelt de payload bloot.

Verschil tussen JWT, JWS en JWE?

JWT (RFC 7519) is een generiek tokenformaat. Het kan op twee concrete manieren worden geïmplementeerd: JWS (RFC 7515, JSON Web Signature) dat zich beperkt tot het ondertekenen van de payload, en JWE (RFC 7516, JSON Web Encryption) dat deze versleutelt. In de praktijk, wanneer men spreekt over "JWT" zonder precisering, spreekt men bijna altijd over een JWS: een ondertekend maar voor iedereen leesbaar token. JWE wordt gebruikt in contexten waar vertrouwelijkheid van de payload onmisbaar is, bijvoorbeeld in bepaalde geavanceerde OpenID Connect-scenario's.

Mijn JWT wordt niet geaccepteerd door de API, waarom?

De klassieke oorzaken zijn, in volgorde van frequentie: verlopen token (controleer de exp-claim), ongeldige handtekening (geheime sleutel of publieke sleutel komt niet overeen met die welke door de uitgever wordt gebruikt), verkeerde aud (het token is uitgegeven voor een andere service), verkeerde iss (de gedeclareerde uitgever is niet de verwachte), geweigerd algoritme (de API vereist bijvoorbeeld RS256 en ontvangt een HS256), gedesynchroniseerde klokken tussen de uitgever en de verificateur (heeft effect op exp en nbf). Het token decoderen met deze tool maakt het al mogelijk om de helft van de hypothesen te elimineren door direct de claims te lezen.

Hoe genereer ik een JWT?

De meeste talen beschikken over een speciale bibliotheek: jsonwebtoken in Node.js, PyJWT in Python, lcobucci/jwt of firebase/php-jwt in PHP, jjwt in Java, golang-jwt/jwt in Go. Allemaal nemen een payload-object, een sleutel en een algoritme als invoer, en geven de tekenreeks header.payload.signature terug klaar om verzonden te worden. Het wordt sterk afgeraden om de generatie met de hand te implementeren: cryptografie bevat te veel valkuilen (niet-constante vergelijkingen, verkeerde behandeling van alg: none, enz.).

Accepteert de decoder een verlopen JWT?

Ja. De decoder beperkt zich tot het tonen van de inhoud van het token zonder een oordeel te vellen over zijn temporele geldigheid. Hij evalueert noch exp, noch nbf, noch de handtekening. Het is nuttig om te begrijpen waarom een token is geweigerd door een API: men kan de waarde van exp vergelijken met het huidige uur om te bevestigen dat het inderdaad verlopen is.

Is mijn JWT geldig als de decoder hem correct weergeeft?

Nee. De weergave bewijst alleen dat de tekenreeks wel gevormd is (drie segmenten gescheiden door punten, correcte Base64URL-codering, geldige JSON in de header en de payload). Dat zegt niets over de authenticiteit van het token. Een volledig vervalste JWT kan zonder fout in een decoder worden weergegeven, het is precies daarom dat we hem moeten doorgeven aan een verifier.

Voorbeeldverzoek

curl -X POST https://cdrn.fr/api/v1/tools/jwt-decoder/execute \
  -H "Content-Type: application/json" \
  -d '{"token":"..."}'

Invoerschema

Veld Type Vereist Standaard
token text

Endpoints

  • GET https://cdrn.fr/api/v1/tools - toont alle beschikbare tools
  • GET https://cdrn.fr/api/v1/tools/jwt-decoder - geeft het schema van deze tool terug
  • POST https://cdrn.fr/api/v1/tools/jwt-decoder/execute - voert deze tool uit met een JSON-payload