KoderKoder.ai
Bảng giáDoanh nghiệpGiáo dụcDành cho nhà đầu tư
Đăng nhậpBắt đầu

Sản phẩm

Bảng giáDoanh nghiệpDành cho nhà đầu tư

Tài nguyên

Liên hệHỗ trợGiáo dụcBlog

Pháp lý

Chính sách bảo mậtĐiều khoản sử dụngBảo mậtChính sách sử dụng chấp nhận đượcBáo cáo vi phạm

Mạng xã hội

LinkedInTwitter
Koder.ai
Ngôn ngữ

© 2026 Koder.ai. Bảo lưu mọi quyền.

Trang chủ›Blog›JWT là gì? Hướng dẫn rõ ràng về JSON Web Tokens
17 thg 10, 2025·6 phút

JWT là gì? Hướng dẫn rõ ràng về JSON Web Tokens

Tìm hiểu JWT (JSON Web Token) là gì, ba phần của nó hoạt động ra sao, nơi sử dụng và các mẹo bảo mật để tránh sai lầm phổ biến liên quan đến token.

JWT là gì? Hướng dẫn rõ ràng về JSON Web Tokens

JWT in simple terms

A JWT (JSON Web Token) is a compact, URL-safe string that represents a set of information (usually about a user or session) in a way that can be passed between systems. You’ll often see it as a long value starting with something like eyJ..., sent in an HTTP header such as Authorization: Bearer \u003ctoken\u003e.

Why use a token at all?

Traditional logins often rely on server sessions: after you sign in, the server stores session data and gives the browser a session ID cookie. Every request includes that cookie, and the server looks up the session.

With token-based auth, the server can avoid keeping session state for every user request. Instead, the client holds a token (like a JWT) and includes it with API calls. This is popular for APIs because it:

  • works well across multiple services (API gateways, microservices)
  • fits mobile and single-page apps (SPAs) that call APIs directly
  • reduces the need for shared session storage across servers

Important nuance: “stateless” doesn’t mean “no server-side checks ever.” Many real systems still validate tokens against user status, rotating keys, or revocation mechanisms.

Authentication vs authorization (plain English)

  • Authentication answers: Who are you? (You sign in and prove your identity.)
  • Authorization answers: What are you allowed to do? (You can read invoices, edit projects, access admin pages, etc.)

JWTs commonly carry proof of authentication (you’re signed in) and basic authorization hints (roles, permissions, scopes)—but your server should still enforce authorization rules.

Where JWTs show up

You’ll commonly see JWTs used as access tokens in:

  • web APIs
  • SPAs
  • mobile apps
  • systems using OAuth 2.0 or OpenID Connect (OIDC)

JWT structure: header, payload, and signature

A JWT is a compact string made of three parts, each base64url-encoded and separated by dots:

header.payload.signature

Example (redacted):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNzAwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c…

1) Header

The header describes how the token was created—most importantly the signing algorithm (e.g., HS256, RS256/ES256) and the token type.

Common fields:

  • typ: often "JWT" (frequently ignored in practice)
  • alg: the signing algorithm used
  • kid: a key identifier to help the verifier select the right key during rotation

Security note: don’t trust the header blindly. Enforce an allowlist of algorithms you actually use, and do not accept alg: "none".

2) Payload

The payload holds “claims” (fields) about the user and token context: who it’s for, who issued it, and when it expires.

Important: JWTs are not encrypted by default. Base64url encoding makes the token URL-safe; it does not hide the data. Anyone who gets the token can decode the header and payload.

That’s why you should avoid putting secrets (passwords, API keys) or sensitive personal data into a JWT.

3) Signature

The signature is created by signing the header + payload with a key:

  • HS256: a shared secret signs and verifies
  • RS256/ES256: a private key signs; a public key verifies

The signature provides integrity: it lets the server verify the token wasn’t modified and was minted by a trusted signer. It does not provide confidentiality.

Size considerations

Because a JWT includes header and payload on every request where it’s sent, bigger tokens mean more bandwidth and overhead. Keep claims lean and prefer identifiers over bulky data.

Payload and claims: what you can (and shouldn’t) store

Design Claims With Confidence
Plan roles, audiences, issuers, and expiry rules before you generate any code.
Open Planner

Claims generally fall into two buckets: registered (standardized names) and custom (your app’s fields).

Common registered claims

  • iss (issuer): who created the token
  • sub (subject): who the token is about (often a user ID)
  • aud (audience): who the token is meant for (e.g., a specific API)
  • exp (expiration time): when the token must stop being accepted
  • iat (issued at): when the token was created
  • nbf (not before): the token should not be accepted before this time

Custom claims: keep them minimal

Include only what the receiving service truly needs to make an authorization decision.

Good examples:

  • a stable internal user identifier (user_id)
  • a small set of roles/permissions (only if you can keep them current)
  • a tenant/organization ID in multi-tenant apps

Avoid “convenience claims” that duplicate lots of profile data. They bloat the token, go stale quickly, and increase impact if the token leaks.

What you should never put in a JWT payload

Because the payload is readable, don’t store:

  • passwords, API keys, refresh tokens, or any secret value
  • payment details, government IDs, or sensitive personal data
  • anything you wouldn’t want copied from a browser, proxy, or log

If you need sensitive information, store it server-side and put only a reference (like an ID) in the token—or use an encrypted token format (JWE) when appropriate.

How the signature works (and what it guarantees)

Signing is not encryption.

  • Signing is like sealing a letter: people can read it, but they can verify it wasn’t altered.
  • Encryption is like locking the letter in a box: only someone with the key can read it.

When a JWT is issued, the server signs the encoded header + payload. When the token is presented later, the server recomputes the signature and compares it. If someone changes even one character (e.g., "role":"user" to "role":"admin"), verification fails and the token is rejected.

JWT vs OAuth, OpenID Connect, and token types

JWT is a token format. OAuth 2.0 and OpenID Connect (OIDC) are protocols that describe how apps request, issue, and use tokens.

OAuth 2.0 and access/refresh tokens

OAuth 2.0 is mainly about authorization: letting an app access an API on a user’s behalf without sharing the user’s password.

  • Access token: presented to an API to prove permission; may be a JWT or an opaque token
  • Refresh token: longer-lived token used to obtain new access tokens

Access tokens are typically short-lived (minutes). Short lifetimes limit damage if a token leaks.

OpenID Connect (OIDC) and ID tokens

OIDC adds authentication (who the user is) on top of OAuth 2.0 and introduces an ID token, which is usually a JWT.

  • ID token: for the client app to confirm the user’s identity
  • Access token: for the API to authorize requests

A key rule: don’t use an ID token to call an API.

If you want more context on practical flows, see a post about the JWT authentication flow.

Common JWT authentication flow

Scaffold a Go JWT API
Generate a Go API with JWT middleware, claim checks, and clean request handling.
Create Project

A typical flow looks like this:

1) Login

The user signs in (email/password, SSO, etc.). If successful, the server creates a JWT (often an access token) with essential claims like subject and expiration.

2) Token issuance

The server signs the token and returns it to the client (web app, mobile app, or another service).

3) API calls

For protected endpoints, the client includes the JWT in the Authorization header:

Authorization: Bearer \u003cJWT\u003e

4) Verification

Before serving the request, the API typically checks:

  • signature (integrity + trusted issuer)
  • exp (not expired)
  • iss (expected issuer)
  • aud (intended for this API)

If all checks pass, the API treats the user as authenticated and applies authorization rules (e.g., record-level permissions).

5) A quick note on clock skew

Because system clocks drift, many systems allow small clock skew when validating time-based claims like exp (and sometimes nbf). Keep the skew small to avoid extending token validity more than intended.

Where to store JWTs safely

Storage choices change what attackers can steal and how easily they can replay a token.

Browser apps: memory vs localStorage vs cookies

In-memory storage (often recommended for SPAs) keeps the access token in JS state. It clears on refresh and reduces “grab it later” theft, but an XSS bug can still read it while the page runs. Pair it with short-lived access tokens and a refresh flow.

localStorage/sessionStorage are easy but risky: any XSS vulnerability can exfiltrate tokens from web storage. If you use them, treat XSS prevention as non-negotiable (CSP, output escaping, dependency hygiene) and keep tokens short-lived.

Secure cookies (often the safest default for web) store tokens in an HttpOnly cookie so JavaScript can’t read them—reducing the impact of XSS token theft. The trade-off is CSRF risk, since browsers attach cookies automatically.

If you use cookies, set:

  • HttpOnly
  • Secure (HTTPS only)
  • SameSite=Lax or SameSite=Strict (some cross-site flows may need SameSite=None; Secure)

Also consider CSRF tokens for state-changing requests.

Mobile apps: prefer OS secure storage

On iOS/Android, store tokens in platform secure storage (Keychain / Keystore-backed storage). Avoid plain files or preferences. If your threat model includes rooted/jailbroken devices, assume extraction is possible and rely on short-lived tokens and server-side controls.

Least privilege

Limit what a token can do: use minimal scopes/claims, keep access tokens short-lived, and avoid embedding sensitive data.

Common JWT security pitfalls to avoid

JWTs are convenient, but many incidents come from predictable mistakes. Treat a JWT like cash: whoever gets it can often spend it.

1) Overly long expirations

If a token lasts days or weeks, a leak gives an attacker that entire window.

Prefer short-lived access tokens (minutes) and refresh them through a safer mechanism. If you need “remember me,” do it with refresh tokens and server-side controls.

2) Skipping issuer and audience checks

Valid signatures aren’t enough. Verify iss and aud, and validate time-based claims like exp and nbf.

3) Trusting decoded payloads

Decoding is not verification. Always verify the signature on the server and enforce permissions server-side.

4) Algorithm confusion and key mix-ups

  • Don’t accept whatever algorithm a token claims. Allowlist expected algorithms.
  • Don’t mix up symmetric keys (HS256) with public/private keys (RS256/ES256).
  • Minimize blast radius by separating keys per environment and rotating them.

5) Token leakage via URLs, logs, and referrers

Avoid putting JWTs in query params. They can end up in browser history, server logs, analytics tools, and referrer headers.

Use Authorization: Bearer ... instead.

6) No key rotation or revocation plan

Assume keys and tokens can leak. Rotate signing keys, use kid to support smooth rotation, and have a revocation strategy (short expirations + ability to disable accounts/sessions). For storage guidance, see a post about where to store JWTs safely.

When to use JWT (and when not to)

Go From Build to Deploy
Deploy and host your JWT-based app directly, with support for custom domains.
Deploy App

JWTs are useful, but they aren’t automatically the best choice. The real question is whether you benefit from a self-contained token that can be verified without a database lookup on every request.

Good fits for JWT

  • Stateless APIs at scale: local verification (signature + expiry) without per-request session lookups
  • Multiple services / microservices: shared verification rules and public keys
  • SPAs and mobile apps: clients calling APIs directly
  • Short-lived access tokens: reduced impact of theft

When JWT is a poor fit

  • Instant revocation is a must: sessions are simpler if you need “log out everywhere now” without extra infrastructure
  • You need to carry sensitive data: typical JWTs are signed, not encrypted
  • Long-lived tokens: they’re high-value and worth stealing

When simple session cookies are better

For traditional server-rendered web apps where straightforward invalidation matters, server-side sessions with HttpOnly cookies are often the simpler, safer default.

Quick decision checklist

Choose JWT if you need stateless verification across services and can keep tokens short-lived.

Avoid JWT if you need instant revocation, plan to store sensitive data in the token, or can use session cookies without friction.

Practical checklist and FAQs

Verification checklist (what to check every time)

  1. Signature is valid

Verify using the correct key and expected algorithm. Reject invalid signatures—no exceptions.

  1. exp (expiration)

Ensure the token hasn’t expired.

  1. nbf (not before)

If present, ensure the token isn’t being used too early.

  1. aud (audience)

Confirm the token was meant for your API/service.

  1. iss (issuer)

Confirm the token came from the expected issuer.

  1. Sanity checks (recommended)

Validate token format, enforce maximum size, and reject unexpected claim types to reduce edge-case bugs.

Choosing HS256 vs RS256/ES256

  • HS256 (symmetric key): one shared secret signs and verifies.

    • Good for: a single app/API controlled by one team.
    • Watch out for: any verifier that has the secret can also mint tokens.
  • RS256 / ES256 (asymmetric keys): private key signs; public key verifies.

    • Good for: multiple services verifying tokens; distributing public keys without enabling signing.
    • Operational note: rotation is often safer because only the signer holds the private key.

Rule of thumb: if more than one independent system needs to verify tokens (or you don’t fully trust every verifier), prefer RS256/ES256.

Monitoring and logging (without leaking tokens)

  • Don’t log raw tokens (headers, cookies, query strings).
  • If you need correlation, log a token fingerprint (e.g., a hash) or safe metadata (iss, aud, and a user ID only if policy allows).
  • Watch for anomalies: signature failures, spikes in expired tokens, unusual audiences/issuers, and suspicious refresh patterns.

FAQs

Is JWT encrypted?

Not by default. Most JWTs are signed, not encrypted, meaning the contents can be read by anyone who has the token. Use JWE or keep sensitive data out of JWTs.

Can I revoke a JWT?

Not easily if you rely only on self-contained access tokens. Common approaches include short-lived access tokens, deny-lists for high-risk events, or refresh tokens with rotation.

How long should exp be?

As short as your UX and architecture allow. Many APIs use minutes for access tokens, paired with refresh tokens for longer sessions.

Building JWT-protected apps faster with Koder.ai

If you’re implementing JWT auth in a new API or SPA, a lot of the work is repetitive: wiring middleware, validating iss/aud/exp, setting cookie flags, and keeping token handling out of logs.

With Koder.ai, you can vibe-code a web app (React), backend services (Go + PostgreSQL), or a Flutter mobile app through a chat-driven workflow—then iterate in a planning mode, use snapshots and rollback as you refine security, and export the source code when you’re ready. It’s a practical way to accelerate building JWT-based authentication flows while still keeping control over verification logic, key rotation strategy, and deployment/hosting settings (including custom domains).

Câu hỏi thường gặp

What is a JWT, and where do I usually send it?

Một JWT (JSON Web Token) là một chuỗi ngắn, an toàn với URL, mang các claim (các trường dữ liệu) và có thể được server xác minh. Thông thường nó được gửi trong yêu cầu API qua:

  • Authorization: Bearer \u003ctoken\u003e

Ý chính: server có thể xác thực tính toàn vẹn của token (thông qua chữ ký) mà không cần lưu một bản ghi session cho từng người dùng trên mỗi yêu cầu.

How is JWT authentication different from server sessions?

Xác thực bằng session thường lưu trạng thái trên server (một bản ghi session được tham chiếu bằng cookie/session ID). Với xác thực dựa trên JWT, client gửi một token được ký trong mỗi yêu cầu và API sẽ xác thực token đó.

JWT phổ biến cho API và kiến trúc đa dịch vụ vì việc xác thực có thể thực hiện cục bộ, giảm nhu cầu lưu session chia sẻ.

“Không trạng thái” (stateless) vẫn thường bao gồm các kiểm tra phía server như danh sách thu hồi, kiểm tra trạng thái người dùng hoặc xoay khóa.

What are the three parts of a JWT (header, payload, signature)?

Một JWT gồm ba phần mã hóa Base64URL, cách nhau bởi dấu chấm:

  • header.payload.signature

Header mô tả cách token được ký, payload chứa các claim (như sub, exp, aud), và signature cho phép server phát hiện việc thay đổi.

Is a JWT encrypted, and can people read what’s inside?

Không. JWT tiêu chuẩn thường được ký, không phải mã hóa.

  • Việc ký đảm bảo tính toàn vẹn (không bị sửa đổi) và tính xác thực (được phát bởi bên ký đáng tin cậy).
  • Bất kỳ ai có token đều có thể decode Base64URL để đọc header và payload.

Nếu cần bảo mật nội dung, hãy xem xét JWE (token được mã hóa) hoặc giữ thông tin nhạy cảm ở phía server và chỉ để một định danh trong JWT.

What does the JWT signature guarantee—and what doesn’t it guarantee?

Chữ ký cho phép server xác minh token không bị thay đổi và được tạo bởi người có khóa ký.

Nó không:

  • che giấu nội dung payload
  • chứng minh người dùng vẫn đang hoạt động (trừ khi bạn kiểm tra thêm)
  • thu hồi token trước exp một cách tự động

Hãy coi token như một chứng chỉ: nếu bị lộ, nó có thể bị sử dụng lại cho đến khi hết hạn.

What are `alg` and `kid` in the JWT header, and why do they matter?

alg cho biết thuật toán được dùng (ví dụ HS256 vs RS256). kid là bộ nhận diện khóa giúp chọn khóa xác minh đúng khi xoay khóa.

Quy tắc bảo mật cơ bản:

Which JWT claims should I include in the payload?

Bắt đầu với các claim tiêu chuẩn và giữ các claim tùy chỉnh ở mức tối thiểu.

Claim thường dùng:

How do JWT, OAuth 2.0, and OpenID Connect relate (access tokens vs ID tokens)?

JWT là một định dạng token; OAuth 2.0 và OpenID Connect là giao thức.

Phân biệt thông dụng:

  • Access token: dùng để gọi API (có thể là JWT hoặc opaque).
  • ID token (OIDC): dùng bởi client app để xác nhận danh tính (thường là JWT).
  • : dùng để lấy access token mới (thường opaque và rất nhạy cảm).
Where should I store JWTs safely in a browser app?

Với app web, các lựa chọn thường là:

  • Lưu trong bộ nhớ (in-memory): được khuyến nghị cho SPA — nó bị xóa khi refresh và giảm rủi ro bị “lấy sau”, nhưng XSS vẫn có thể đọc token khi trang đang chạy. Kết hợp với token ngắn hạn và flow refresh.
  • localStorage/sessionStorage: dễ dùng nhưng rủi ro nếu có XSS. Nếu dùng, phòng ngừa XSS là bắt buộc (CSP, escape output, quản lý dependency) và giữ token ngắn hạn.
  • Cookie HttpOnly an toàn: thường an toàn hơn vì JS không đọc được cookie — giảm tác hại từ XSS. Đổi lại, có rủi ro CSRF vì trình duyệt tự động gửi cookie.

Nếu dùng cookie, set:

What checks should my API perform when validating a JWT?

Ít nhất, API nên kiểm tra:

  • chữ ký (với khóa đúng và thuật toán được allowlist)
  • exp (chưa hết hạn)
  • iss (issuer đúng)
  • aud (dành cho API của bạn)
  • nbf (nếu có)

Thêm các biện pháp thực tế:

Mục lục
JWT in simple termsWhy use a token at all?Authentication vs authorization (plain English)Where JWTs show upJWT structure: header, payload, and signaturePayload and claims: what you can (and shouldn’t) storeHow the signature works (and what it guarantees)JWT vs OAuth, OpenID Connect, and token typesCommon JWT authentication flowWhere to store JWTs safelyCommon JWT security pitfalls to avoidWhen to use JWT (and when not to)Practical checklist and FAQsBuilding JWT-protected apps faster with Koder.aiCâu hỏi thường gặp
Chia sẻ
Koder.ai
Build your own app with Koder today!

The best way to understand the power of Koder is to see it for yourself.

Start FreeBook a Demo
  • Dùng danh sách cho phép (allowlist) các thuật toán mong đợi; đừng chấp nhận mọi giá trị alg.
  • Không bao giờ chấp nhận alg: "none".
  • Đừng để giá trị kid không đáng tin khiến quá trình tra cứu khóa trở nên không an toàn.
  • iss (issuer)
  • sub (subject / định danh người dùng)
  • aud (audience / API đích)
  • exp (expiration)
  • iat (issued at)
  • nbf (not before)
  • Tránh đặt bí mật hoặc dữ liệu cá nhân nhạy cảm trong payload vì nó có thể bị đọc nếu token bị lộ.

    Refresh token

    Quan trọng: đừng dùng ID token để gọi API chỉ vì nó trông giống access token JWT.

    • HttpOnly
    • Secure (chỉ HTTPS)
    • SameSite=Lax hoặc SameSite=Strict (một số luồng cross-site cần SameSite=None; Secure)

    Cân nhắc token CSRF cho các request thay đổi trạng thái.

    • giới hạn kích thước token tối đa
    • từ chối các kiểu claim bất thường
    • cho phép một khoảng sai số nhỏ về đồng hồ để tránh vấn đề lệch giờ