JWT is widely used in APIs, single-page applications, mobile apps, and even microservices due to its compact, secure, and stateless nature.
Table of Contents
Basic Authentication
- In Basic Authentication, the client must send a username and password with every request.
- These credentials are usually stored on the client side (like in cookies or headers).
Problems with Basic Authentication:
- Security Risk – If the cookie or storage is compromised, credentials can be stolen.
- Database Lookups – Server must validate the credentials on each request, hitting the database every time.
- Not Scalable – This repeated DB access slows down performance and increases server load.
- No Statelessness – Server needs to “remember” users or constantly check credentials.
Token-based Authentication (JWT)
To solve the limitations of Basic Authentication, we use JWT – the most common token-based solution.
JWT (JSON Web Token) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed using a secret (with HMAC) or a public/private key pair (with RSA or ECDSA).
Structure of a JWT
A JWT consists of three parts, separated by dots (.):
xxxxx.yyyyy.zzzzz
PythonThese parts are:
- Header
- Payload
- Signature
Header
Typically consists of two parts:
{
"alg": "HS256",
"typ": "JWT"
}
Python- alg: Signing algorithm (e.g., HS256, RS256)
- typ: Token type
Encoded using Base64Url.
Payload
Contains the claims — statements about the user and additional metadata:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1712470400
}
PythonCommon claim types:
- iss – Issuer
- sub – Subject
- exp – Expiration time
- iat – Issued at
- nbf – Not before
Signature
Used to verify the token hasn’t been altered:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
PythonHow JWT Works
Let’s say you’re logging into a web or mobile app. Here’s what happens behind the scenes:

Step 1: User Logs In
The user sends a login request to the server with their username and password.
POST /login
{
"username": "john",
"password": "mypassword"
}
PythonStep 2: Server Verifies Credentials
The server checks the username and password (e.g., from a database).
If valid:
- The server creates a JWT, which includes:
- User ID or username
- Roles/permissions
- Expiration time
- The server signs the token using a secret key.
Example payload:
{
"sub": "john",
"role": "admin",
"exp": 1712500000
}
PythonStep 3: Server Returns the JWT
The signed JWT is sent back to the client (browser/mobile app).
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
PythonStep 4: Client Stores the JWT
The client stores the token, usually in:
- localStorage or sessionStorage (browser)
- AsyncStorage (React Native)
- Or a secure cookie (best for web security)
Step 5: Client Makes Authenticated Requests
For future API requests, the client includes the token in the Authorization header like this:
GET /user-profile
Authorization: Bearer <your-jwt-token>
PythonStep 6: Server Verifies the JWT
For every protected route:
- The server extracts the token from the header
- It verifies the signature using the secret key
- If valid and not expired → user is authenticated
- If invalid → the request is rejected (401 Unauthorized)
Step 7: Access Granted
Once verified, the server allows access to the requested resource — and can even read roles/permissions from the token payload.
How JWT Verification Works?
When a client sends a JWT with a request (usually in the Authorization header), the server performs token validation to ensure the request is authentic and safe.
Signing the JWT (At Login Time)
When the user logs in successfully, the server:
- Creates a payload (e.g., user_id, role, exp, etc.)
- Signs it using a secret key (if using HS256) or a private key (if using RS256)
- Sends this JWT to the client
Verifying the JWT (On Every Request)
When the client sends the JWT back in a request:
- The server extracts the token from the Authorization header:
Authorization: Bearer <JWT>
Python- The server decodes and verifies the token using the same secret key (for HS256) or the public key (for RS256)
- If the token is:
- Untampered (signature is valid)
- Not expired (exp time hasn’t passed)
- Properly formatted → Then the token is trusted and the request proceeds.
- If anything fails (signature mismatch, token modified, expired):
- The server rejects the request (usually with a 401 Unauthorized error).
Why This Works?
- The signature is generated using the header, payload, and the secret key.
- Any change in the payload (e.g., changing role from “user” to “admin”) will change the signature.
- Since the server knows the original secret, it can detect tampering.
Why Use JWT?
JWT is popular for stateless authentication in modern web applications. Here’s why:
- Compact – Small enough to be sent via URL, POST params, or HTTP headers.
- Self-contained – Holds all user information needed.
- Stateless – No need to store session info on the server.
- Secure – Can be signed and optionally encrypted.
Use Cases
- Authentication – After login, server returns a JWT. Client stores and includes it in future requests (usually in the Authorization header).
- Authorization – Determine user access to resources.
- Information Exchange – Securely transmit data between parties.
- Microservices – Used for inter-service communication.
Security Considerations
- Always use HTTPS to transmit JWTs.
- Set short expiration (exp) times.
- Use strong secrets or RSA keys.
- Store JWTs securely (preferably in memory or HTTP-only cookies).
- Revoke JWTs through blacklisting or token versioning (for logout, etc.).
Authentication with JWT
Authentication is about verifying who the user is.
- After login, the server issues a JWT containing user identity (like user_id, username, etc.).
- The client sends this token in subsequent requests.
- The server checks the token’s signature and payload to confirm the user is authenticated.
Authorization with JWT
Authorization is about determining what the authenticated user is allowed to do.
- The JWT payload can include user roles or permissions, like:
{
"sub": "john",
"role": "admin"
}
PythonWhen the user tries to access a protected resource, the server reads the token:
- Is this user an admin?
- Do they have access to this endpoint?
Conclusion
JWT is a powerful tool that enables secure, stateless communication between parties. It’s particularly effective for APIs, microservices, and modern web/mobile apps. While it simplifies authentication and session management, it’s essential to handle it with care to avoid security pitfalls.
Whether you’re building a small app or a complex distributed system, understanding JWT will be a key asset in your developer toolkit.