Open-source project
dwyl/learn-json-web-tokens avatar
dwyl/learn-json-web-tokens

dwyl/learn-json-web-tokens: A Node.js JWT Tutorial You Can Run and Test

:closed_lock_with_key: Learn how to use JSON Web Token (JWT) to secure your next Web App! (Tutorial/Example with Tests!!)

4,173 stars242 forksJavaScriptMIT

At a glance

What is it?
A small teaching repository that signs and verifies JWTs with jsonwebtoken and level, ships a four-endpoint server and a test suite, and stops short of refresh tokens and key rotation.
Who is it for?
Adopt it as a reading and running exercise if you are learning how a JWT moves from a login form to a protected route, and as a reference for the claims the jsonwebtoken library exposes. Do not adopt it as a production auth layer: there is no refresh token, no key rotation and no documented revocation beyond the in-memory store in the example.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 47 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap dwyl/learn-json-web-tokens fills

Most JWT material on the web is either a specification summary or a framework-specific recipe. This repository sits in between. It is a tutorial with a working Node.js server, a test suite, and a Chinese translation in README-zh_CN.md, aimed at developers who already write JavaScript and want to see the token lifecycle end to end rather than read about it. The README states the goal plainly: learn how to use JSON Web Token (JWT) to secure your next Web App. The framing is authentication, not authorization policy, and the example code reflects that narrow target. If you want a library reference, the jsonwebtoken package is the thing to read. This repository is for the wiring around it: where the token is generated, where it is read back, and what happens when verification fails.

What a JWT actually is, according to the README

The README quotes the IETF definition: a compact, URL-safe means of representing claims transferred between two parties, encoded as a JSON object and digitally signed using JSON Web Signature. It then splits a token into three dot-separated parts shown on separate lines for readability: a header describing the token and the hashing algorithm, a payload carrying the claims, and a signature generated from the first two parts and used to verify validity. The claim keys listed are iss, exp, iat, nbf, jti, sub and aud, with the note that exp must be in seconds as defined in the spec. Two practical remarks stand out. Payload length grows with the data you put in it, so the README's rule of thumb is to store the bare minimum. And the token is signed, not encrypted: anyone holding it can read the payload. That distinction is the one people get wrong most often, and the README does not soften it.

The four endpoints and the two helper functions

The example server is built on the core node.js http module rather than Express, and exposes four routes: /home for the login form, /auth for authentication, /private for restricted content, and /logout to invalidate the token. The README says the choice of a bare http server was deliberate, for readability, maintainability and testability, with helpers and handlers tested separately. The interesting logic lives in example/lib/helpers.js. generateToken signs an object containing an auth value of 'magic', the request's user-agent header, and an exp computed as Math.floor(new Date().getTime()/1000) + 7*24*60*60, so a seven-day lifetime in seconds. The secret comes from the JWT_SECRET environment variable. validate() reads req.headers.authorization, calls jwt.verify inside a try block, and falls through to authFail on a thrown error, on a falsy decode, or when decoded.auth is not 'magic'. Both functions are synchronous, and the README defends that: neither performs I/O or network requests, so synchronous computation is safe here. That reasoning holds for HMAC verification and breaks the moment you switch to an asymmetric algorithm with remote key lookup, which the tutorial does not cover.

Installing it and running the example server

The repository is a Node package, so the path in is npm. package.json declares dependencies on jsonwebtoken ^8.5.1 and level ^5.0.1, and an engines field of node >= 6. The start script runs node ./example/server.js. The README also points at a hosted instance at jwt.herokuapp.com and offers a Gitpod button for opening example/lib/helpers.js in a browser workspace with GitHub OAuth, which is the fastest route if you do not want a local Node install. Locally, the sequence is:

bash
npm install
JWT_SECRET=your-secret npm start

The server then listens and serves the login form at /home. Authenticating there produces a token that the private route requires. To see the test side, the package defines three separate scripts, and they are not interchangeable:

bash
npm test
npm run spec
npm run coverage

npm test runs istanbul over ./example/test/functional.js. npm run spec runs tape over ./example/test/integration.js and pipes the result through tap-spec. npm run coverage runs the same functional file and then enforces istanbul check-coverage at 100 percent for statements, functions, lines and branches. That last script is the one to watch: it will fail the build on any uncovered branch, so it doubles as a specification of how much of the example is exercised. A pre-commit hook runs jshint and coverage before each commit.

Where the tutorial stops short

The /logout route is described as invalidating the token, but the README does not document the mechanism or whether the token store survives a process restart. That matters because a signed JWT is stateless by construction: verifying a signature tells you the token was issued by someone holding the secret and has not expired, not that the user is still logged in. Any revocation therefore needs server-side state, and the README is silent on how durable that state is. Two other gaps are worth naming. There is no refresh token flow, so the only lever on session length is the hardcoded seven-day exp in generateToken. And there is no key rotation story: the secret is a single environment variable, and changing it invalidates every outstanding token at once. The dependency list is also dated. jsonwebtoken ^8.5.1 and level ^5.0.1 are the pinned ranges in package.json, and the README does not discuss verification algorithm pinning, which is the standard defense against algorithm confusion attacks. A tutorial that shows jwt.verify(token, secret) without an algorithms option teaches a habit you will want to unlearn.

How it compares with a framework auth library

The obvious alternative is not another tutorial but a framework-integrated auth package, such as Passport with its JWT strategy. The difference is one of scope and control. Passport hands you a strategy object, a middleware chain and session handling conventions, and you configure it rather than write it. This repository does the opposite: it writes the http server, the routes and the two helper functions by hand so that every step is visible in example/server.js and example/lib/helpers.js. That is better for learning and worse for shipping. A Passport strategy will handle extraction from headers and query parameters, and it will fail closed in ways that are already tested by a wider community. The dwyl example fails closed too, via authFail, but the failure paths are exactly as wide as the example's test file. If your goal is to understand JWT mechanics before you pick a library, read this first. If your goal is to authenticate users this week, start with the library and come back here for the concepts.

Licence, maintenance and upgrade cost

The repository is MIT licensed, while package.json declares "license": "ISC". That mismatch is worth resolving with your own legal review before you vendor the code, because the two licences differ in how they handle warranty and liability language even though both are permissive. On maintenance: the last push was on 2026-08-15, and the repository is not archived, so it is current as of that date. There are no retrieved releases, which is consistent with a tutorial repository that versions through package.json (currently 1.0.6) rather than publishing. The upgrade cost is low but not zero. The runtime surface is two dependencies, and the example is a few hundred lines, so porting it to a newer jsonwebtoken major version is a matter of checking the verify options and the sign payload shape. The bigger cost is the test harness: istanbul is deprecated in favour of nyc, and the 100 percent coverage gate will need to be re-established against whatever runner you move to. Budget an afternoon, not a sprint.

Editorial conclusion

Adopt it as a reading and running exercise if you are learning how a JWT moves from a login form to a protected route, and as a reference for the claims the jsonwebtoken library exposes. Do not adopt it as a production auth layer: there is no refresh token, no key rotation and no documented revocation beyond the in-memory store in the example. Before you copy anything, run npm test and confirm that the 100 percent coverage thresholds in the coverage script still pass on the Node version you target, since package.json only requires engines node >= 6.

Frequently asked questions

How do I get a JSON Web Token with dwyl/learn-json-web-tokens?

Start the example server and authenticate through the login form at /home. The generateToken helper in example/lib/helpers.js signs a payload with an auth value of 'magic', the request user-agent and a seven-day exp, using the secret from the JWT_SECRET environment variable.

What are JSON Web Tokens used for in this tutorial?

The README frames them as a way to send read-only signed claims between services, and the example uses them for authentication: a token issued at /auth is required to reach the restricted /private route.

How do I decode a JSON Web Token in this example?

The validate helper calls jwt.verify(token, secret) on the value in req.headers.authorization, which returns the decoded payload or throws. The README does not document a separate decode-only step in the example code.

What are the 3 components of a JWT token?

The README lists a header describing the token and hashing algorithm, a payload holding the claims, and a signature generated from the first two parts that is used to verify validity. The three are separated by periods in a single string.

Official sources

  1. dwyl/learn-json-web-tokens on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dwyl-learn-json-web-tokens.svg)](https://hysenlabs.com/projects/dwyl-learn-json-web-tokens)