# What Is JWT? Structure, Claims, and How It Works

> JWT (JSON Web Token) is a signed token format for API authentication. Learn the header, payload, signature, claims, JWT secret, expiry, and security risks.

**URL:** https://www.ciptadusa.com/blog/jwt-adalah  
**Type:** blog  
**Author:** PT Cipta Dua Saudara  
**Category:** Engineering  
**Published:** 2026-11-02  
**Cover:** https://www.ciptadusa.com/media/uploads/blog/2026-11/1793585800283-jwt-adalah-20261102.webp  

## Article

JWT stands for JSON Web Token, a compact, URL-safe format for carrying claims (pieces of data) between two parties. The claims are written as a JSON object, then digitally signed or protected with a message authentication code (MAC) and/or encrypted, so the receiver can check that nothing was changed ([source](https://www.rfc-editor.org/rfc/rfc7519)). In web applications, a JWT works as a "ticket" the client sends to an API after logging in, for example in the `Authorization: Bearer <token>` header.

This article covers what a JWT is, its three-part structure, the standard claims, the JWT authentication flow, how JWT compares with sessions, what a JWT secret and an expired JWT mean, and the security mistakes to avoid.

## What Is a JWT?

JWT is standardized by the IETF in RFC 7519, published in May 2015. The RFC suggests pronouncing JWT like the English word "jot" ([source](https://www.rfc-editor.org/rfc/rfc7519)). NIST defines a JWT as a data exchange format made of a header, payload, and signature, where the header and payload are JSON objects that are encoded and concatenated, with the result being signed ([source](https://csrc.nist.gov/glossary/term/jwt)).

What a JWT carries are called claims: statements about an entity, such as "this user is named Budi" or "this token is valid until 07:15". Because the content is JSON, any programming language can read it. If you are new to the format, start with [what JSON is](/en/blog/json-adalah).

### What Does JWT Stand For?

JWT stands for JSON Web Token. JSON refers to the format of the claims, Web means the token is designed for web and HTTP environments, and Token means a piece of data that represents a right or an identity.

### Is a JWT Encrypted?

Not necessarily. A JWT comes in two forms. A signed JWT uses JSON Web Signature (JWS, RFC 7515) and guarantees the content has not been changed, but the content is still readable ([source](https://www.rfc-editor.org/rfc/rfc7515)). An encrypted JWT uses JSON Web Encryption (JWE, RFC 7516), which keeps the content confidential ([source](https://www.rfc-editor.org/rfc/rfc7516)). OWASP stresses that a signed JWT provides integrity and authenticity, not confidentiality, because the payload is only base64url encoded, not encrypted ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).

## JWT Structure: Header, Payload, Signature

In its compact form, a JWT has three parts separated by dots: header, payload, and signature, so it looks like `xxxxx.yyyyy.zzzzz` ([source](https://www.jwt.io/introduction)). Here is a token CDS created to illustrate this article, using an example secret. It is not a real token:

```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyIsIm5hbWUiOiJCdWRpIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzkzNTc3NjAwLCJleHAiOjE3OTM1Nzg1MDB9.kuTry3zCk0fPoNGiNn5Ywd-KUNCuARrq3BppgRd2zaY
```

| Part | Contents | Example after decoding |
|---|---|---|
| Header | Token type and signing algorithm | `{"alg":"HS256","typ":"JWT"}` |
| Payload | Claims about the user and the token's validity | `{"sub":"user-123","name":"Budi","role":"admin","iat":1793577600,"exp":1793578500}` |
| Signature | Signature over the header and payload | A base64url string that does not decode to readable text |

### Header

The header holds two pieces of information: the token type (`typ`, set to JWT) and the signing algorithm (`alg`), such as HMAC SHA256 (HS256) or RSA. This JSON is Base64Url encoded to form the first part of the token ([source](https://www.jwt.io/introduction)). Base64url is the URL- and filename-safe variant of Base64 defined in RFC 4648 ([source](https://www.rfc-editor.org/rfc/rfc4648)).

### Payload

The payload holds the claims. In the example above, `sub` is the user ID, `name` and `role` are custom claims defined by the application, and `iat` and `exp` are the issue time and expiration time. This part is also Base64Url encoded. The jwt.io documentation warns that for signed tokens this information is protected against tampering but readable by anyone, so secret information should not go in the payload or header unless it is encrypted ([source](https://www.jwt.io/introduction)).

### Signature

The signature is created from the encoded header and payload, a secret or private key, and the algorithm named in the header ([source](https://www.jwt.io/introduction)). If a single character of the payload changes, for example the `role`, the signature no longer matches and the server must reject the token.

An encrypted token (JWE) looks different: RFC 7516 states that JWEs have five segments separated by four periods ([source](https://www.rfc-editor.org/rfc/rfc7516)).

## Standard JWT Claims

RFC 7519 registers seven standard claims. All of them are optional, but their meaning is agreed, so libraries can check them automatically ([source](https://www.rfc-editor.org/rfc/rfc7519)). The full list of registered claims is maintained by IANA ([source](https://www.iana.org/assignments/jwt/jwt.xhtml)).

| Claim | Full name | Meaning |
|---|---|---|
| `iss` | Issuer | The party that issued the token |
| `sub` | Subject | The subject of the token, such as a user ID |
| `aud` | Audience | The intended recipient, such as a specific API |
| `exp` | Expiration Time | The time on or after which the token must not be accepted |
| `nbf` | Not Before | The time before which the token must not be accepted |
| `iat` | Issued At | The time the token was issued |
| `jti` | JWT ID | A unique token ID, useful for preventing replay |

Time values such as `exp` and `iat` use the NumericDate format, the number of seconds since 1970-01-01T00:00:00Z UTC ([source](https://www.rfc-editor.org/rfc/rfc7519)). In the example token above, `iat` 1793577600 is November 2, 2026 at 00:00 UTC and `exp` 1793578500 is 15 minutes later.

## How JWT Authentication Works

A JWT-based login flow for a web application and an [API](/en/blog/api-adalah) runs like this:

1. The user sends a username and password to the login endpoint.
2. The server checks the credentials. If they are correct, it creates a JWT with claims such as `sub` and `exp`, then signs it.
3. The client stores the token.
4. Each time it accesses a protected resource, the client sends the JWT in the Authorization header using the Bearer scheme ([source](https://www.jwt.io/introduction)).
5. The [backend](/en/blog/backend-adalah) verifies the signature, algorithm, `exp`, `iss`, and `aud`. If everything passes, the request is processed. If not, the server responds with 401.

The Bearer header format comes from RFC 6750 for OAuth 2.0, for example `Authorization: Bearer mF_9.B5f-4.1JqM`. The same RFC makes TLS (HTTPS) mandatory when using bearer tokens ([source](https://www.rfc-editor.org/rfc/rfc6750)). MDN also documents this header ([source](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization)).

Token checks can run in each service or in a single [middleware](/en/blog/middleware-adalah) layer such as an API gateway, which matters in a [microservices](/en/blog/microservices-adalah) architecture with many services.

### Where Are JWTs Used?

OWASP lists several uses of JWTs ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)):

- The ID token in OpenID Connect, which the OpenID Connect Core specification represents as a JWT ([source](https://openid.net/specs/openid-connect-core-1_0.html)).
- OAuth 2.0 access tokens. A profile for JWT-format access tokens is standardized in RFC 9068 (October 2021) ([source](https://www.rfc-editor.org/rfc/rfc9068)).
- "Stateless" user sessions, a use OWASP says is frowned upon.
- DPoP proofs that show possession of a private key, and JWT-SVIDs in SPIFFE for workload authentication.

## JWT vs Session: Which One to Use?

A classic session keeps login data on the server and only gives the browser a session ID in a cookie. A JWT carries its own claims, so the server can verify it without looking up session data. CDS compiled the table below from OWASP and oauth.net documentation:

| Aspect | Cookie-based session | JWT |
|---|---|---|
| Where login data lives | Server (database or cache) | Inside the token the client carries |
| Verification | Look up the session ID in server storage | Check the signature and claims locally |
| Revoking access | Delete the session on the server | Needs a denylist, token status list, or short expiry |
| Good fit for | A web app on one domain | APIs, mobile apps, service-to-service, SSO |

oauth.net recommends JWTs when resource servers need to validate tokens locally without a network call, and opaque tokens plus introspection when access must be revocable immediately ([source](https://oauth.net/2/jwt/)). OWASP warns that if you use JWTs for user sessions, you need a way to invalidate sessions, such as a deny list of revoked tokens. Once you add a deny list, sessions are no longer fully stateless, so a plain session system that follows the OWASP Session Management guidance can be the simpler choice ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html), [session guidance](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)).

## JWT Secret and Expired JWT

### What Is a JWT Secret?

A JWT secret is the secret key for an HMAC algorithm such as HS256. The same server uses it to create and verify signatures. Anyone holding the secret can create a token that looks valid, so the secret must stay on the server, out of the repository, and never be sent to the client. RFC 8725 requires keys to have sufficient entropy and says passwords should only be used for key encryption, not content encryption ([source](https://www.rfc-editor.org/rfc/rfc8725)).

The alternative is a public-key algorithm such as RS256 or ES256: the issuer signs with a private key, and other services only need the public key to verify.

### What Does an Expired JWT Mean?

An expired JWT means the current time is on or after the value of the `exp` claim. RFC 7519 says the token must not be accepted for processing on or after that expiration time ([source](https://www.rfc-editor.org/rfc/rfc7519)). Messages such as "jwt expired" or "token expired" from a library mean the client has to log in again or request a new token through the refresh token mechanism offered by the authorization server. The jwt.io guidance advises not keeping tokens longer than required ([source](https://www.jwt.io/introduction)).

## JWT Security Mistakes to Avoid

RFC 8725 (February 2020, BCP 225) is the official best current practice for JWTs ([source](https://www.rfc-editor.org/rfc/rfc8725)). Together with OWASP, it gives this checklist:

- **Accepting `"alg":"none"`.** OWASP notes that some libraries used to accept unsigned JWTs by default, letting attackers forge tokens. Make sure your parser rejects them ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).
- **Not pinning the algorithm.** RFC 8725 requires libraries to let the caller specify the allowed algorithms and not use any others. OWASP describes "algorithm confusion", where an RS/ES public key is used as an HMAC secret to forge a token.
- **Not checking `iss` and `aud`.** Without these checks, a token issued for one service can be replayed against another. RFC 8725 calls this a substitution attack.
- **Trusting keys named in the token header.** Parameters such as `jwk`, `jku`, and `x5u` are attacker input. Get the verification key from a source you already trust, such as the issuer's `jwks_uri`.
- **Putting sensitive data in the payload.** Anyone holding a signed JWT can read its payload, including through application logs and browser storage. Keep sensitive data on the server, or use JWE when the claims really must travel with the token.
- **Storing tokens in localStorage without thinking it through.** The OWASP HTML5 Security Cheat Sheet advises against storing session identifiers in local storage because the data is always accessible by JavaScript, and a single XSS flaw can steal everything in it. Cookies with the HttpOnly flag can reduce this risk ([source](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html), [RFC 6265](https://www.rfc-editor.org/rfc/rfc6265)).
- **Having no way to revoke tokens.** OWASP names Token Status Lists or a denylist based on `jti` and `iss` as revocation options ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).

For testing, the PortSwigger Web Security Academy offers material and labs on JWT attacks that QA or security teams can use ([source](https://portswigger.net/web-security/jwt)).

## JWT in Software Projects

When building a web app, a mobile app, or a [system integration](/en/blog/integrasi-sistem-adalah), the authentication decision belongs in the design stage: session cookies, JWTs, or an OpenID Connect identity provider, how long tokens stay valid, and how to revoke them. The same applies to [webhooks](/en/blog/webhook-adalah) and other system-to-system integrations that need to verify the sender.

The CDS [custom software development](/en/services/software) team picks the technology stack per project, including the authentication scheme. For systems already running, [IT consulting](/en/services/consulting) covers audits and architecture redesign. As a product example, [Zetta CRM](/en/incubating/zetta-crm), a Go-based MCP server developed by CDS, is accessed through the `POST /mcp` endpoint with an API key.

## JWT FAQ

### What does JWT stand for?

JWT stands for JSON Web Token, the IETF standard RFC 7519 for carrying claims between two parties in a compact, URL-safe format ([source](https://www.rfc-editor.org/rfc/rfc7519)).

### What is a JWT token?

A JWT token is a three-part string (header.payload.signature) that a server issues after a user logs in. The client sends it with each request to prove its identity and access rights.

### Can other people read a JWT?

Yes, for a signed JWT. The header and payload are only base64url encoded, so anyone holding the token can decode them. The signature only prevents changes ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).

### What is the difference between a JWT and an API key?

An API key is a fixed key that identifies the calling application. A JWT carries claims such as the user's identity and expiration time, and can be verified through its signature without a database lookup.

### How long should a JWT be valid?

RFC 7519 sets no number. The lifetime is set per application through the `exp` claim. The jwt.io principle is not to keep tokens longer than required ([source](https://www.jwt.io/introduction)), and to use refresh tokens for longer sessions.

### Does JWT replace sessions?

Not necessarily. JWTs suit APIs and service-to-service calls, while for user sessions in a single web app OWASP notes that JWTs still need a session invalidation mechanism, so a plain session can be simpler ([source](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).

## Need a Secure Login and API?

If your application needs user login, API access from a mobile app, or integration with other systems, the CDS team can design the authentication scheme, token lifetime, and validation from the start. Start with [custom software development](/en/services/software), discuss your existing system through [IT consulting](/en/services/consulting), or see [CDS work](/en/works) first.


---

*Markdown version of https://www.ciptadusa.com/blog/jwt-adalah — generated for AI agents and LLM crawlers.*
