Back to guides

GUIDE / security

How to Test JWT Authentication

Learn how to test JWT authentication: claims, expiry, signatures, refresh tokens, algorithm attacks, and a practical JWT security test checklist.

By The Testing AcademyPublished July 9, 2026Updated July 9, 202617 min read

A login that returns a token is only the start of auth risk on modern APIs and SPAs. How to test JWT authentication means proving the server rejects bad tokens, enforces claims, rotates refresh credentials safely, and blocks privilege escalation through payload edits.

This guide shows how to test JWT authentication with practical cases for signatures, expiry, audience, roles, refresh flows, revocation, and common anti-patterns. You will get checklists, tables, safe staging methods, common mistakes, and defect examples you can reuse.

For broader auth coverage, read API authentication testing and authentication and authorization testing. For endpoint-level security packing, use the API security testing checklist.

Ethics and Scope

  • Test only systems you are authorized to test.
  • Prefer staging with synthetic users.
  • Do not attack production identity providers without explicit permission.
  • Do not brute force secrets.
  • Treat stolen or leaked real user tokens as incidents, not fixtures.

JWT Basics for Testers

A JWT often looks like three base64url sections:

header.payload.signature

Example structure (illustrative):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJ1c2VyIiwiZXhwIjoxNzAwMDAwMDAwfQ.
SIGNATURE
  • Header: algorithm and type metadata.
  • Payload: claims such as subject, roles, expiry.
  • Signature: integrity protection created with a secret or private key.

Critical tester insight: readable payload is not trusted data. If the server does not verify the signature and claims, an attacker can edit the payload.

What "Good" JWT Authentication Looks Like

From a QA perspective, a solid implementation usually:

  1. Issues tokens only after successful authentication.
  2. Signs tokens with a strong algorithm and managed keys.
  3. Validates signature on every protected request.
  4. Enforces exp, and nbf when used.
  5. Validates iss and aud when those claims are part of design.
  6. Treats roles and tenants as server-enforced authorization inputs, still checked against policy.
  7. Uses short-lived access tokens plus carefully handled refresh tokens.
  8. Rejects malformed tokens consistently.
  9. Provides a revocation or rotation story for logout, password change, and compromise.
  10. Avoids putting sensitive secrets in the payload.

Your tests should try to falsify each of those properties.

Tools You Need

  • API client: Postman, Insomnia, Bruno, or curl.
  • JWT decoder for inspection (devtools, jwt.io style tools offline, or CLI). Prefer offline decoding for sensitive staging tokens.
  • Proxy: Burp or ZAP for intercepting client traffic.
  • Two or more test users and at least two roles.
  • Clock control awareness (waiting for expiry, or staging config with short TTLs).

You do not need to implement cryptography. You need disciplined request variants.

Step by Step: How to Test JWT Authentication

Step 1: Capture a valid token the legitimate way

  1. Call the real login or OAuth token endpoint.
  2. Store access token and refresh token separately.
  3. Call a protected endpoint and confirm success.
  4. Record response times and status codes as baseline.

Document:

  • Token endpoint
  • Grant type
  • Client IDs if any
  • Where the client stores tokens
  • Access token TTL
  • Refresh token TTL

Step 2: Decode and inventory claims

Decode payload and list claims:

ClaimExampleWhat to test
subuser_123Token acts only for that subject
expunix timestampExpired token rejected
nbfunix timestampEarly token rejected if enforced
iatissued atSanity and lifecycle
isshttps://auth.example.comWrong issuer rejected
audapi.example.comWrong audience rejected
role / rolesuserClient edits do not elevate
tenant_idorg_9Cross-tenant use denied
jtiunique idRevocation/replay support if used

Write down which claims your product documentation says are enforced.

Step 3: Missing and malformed token tests

Against a protected route:

CaseRequest changeExpected
No Authorization headeromit header401
Empty bearerAuthorization: Bearer401
Random stringBearer not-a-jwt401
Only two segmentsremove signature part401
Truncated tokencut last characters401
Wrong prefixToken abc instead of Bearer if Bearer required401

Consistency matters. Alternating 401 and 500 can leak implementation fragility.

Step 4: Signature tampering tests

  1. Decode payload.
  2. Change a claim, for example "role": "admin".
  3. Re-encode payload without a valid resign (or keep old signature).
  4. Send to API.

Expected: reject. If accepted, you likely found a critical failure: server trusting unsigned or poorly verified tokens.

Also try:

  • Flip one character in the signature.
  • Replace signature with signature from another token.
  • Mix header from token A with payload from token B.

Step 5: Algorithm confusion and alg=none style probes

Historical classes of bugs include accepting alg values the server should not trust.

QA-friendly probes (authorized staging only):

  1. Create a token header with "alg":"none" and a payload that elevates privileges, with empty signature segment as applicable to your tooling.
  2. Send to API.
  3. Confirm rejection.

If your stack uses asymmetric algorithms, security teams may also test key confusion cases. QA should at least confirm algorithm is not client-controlled in a way that disables verification. If unsure, file a question to security engineering rather than inventing exotic crypto attacks.

Step 6: Expiry and not-before enforcement

Practical methods:

  • Prefer staging config with short-lived access tokens (for example 60-120 seconds) for testability.
  • Obtain token, wait for expiry, retry protected call.
  • Confirm 401 after expiry.
  • Confirm refresh flow can mint a new access token when refresh is still valid.
  • If nbf is present in future, confirm early use fails when enforced.

Avoid relying on local laptop clock tricks as your only method. Server time is the authority.

Step 7: Issuer and audience enforcement

If tokens include iss and aud:

  1. Capture a token intended for another environment or API if your org has multiple (dev vs staging) and testing is allowed across them carefully.
  2. Replay a token from service A against service B.
  3. Expect rejection when audiences differ.

In microservices, a token meant for the public API should not automatically authorize internal admin services unless designed that way.

Step 8: Authorization claims are not the whole story

Even a valid JWT with "role":"user" must still pass object-level checks.

Tests:

  • Valid user token cannot call admin route.
  • Valid user token cannot modify another user's resource.
  • Editing the JWT role claim to admin fails signature checks and is rejected.
  • Server does not "only" trust the token role when a database role is the source of truth, depending on architecture.

JWT authn proves identity (or session of identity). Authz still needs policy. Connect this with authentication and authorization testing.

Step 9: Refresh token lifecycle

Refresh tokens are often more valuable than access tokens because they last longer.

Checklist:

[ ] Valid refresh returns new access token
[ ] Refresh with access token rejected if wrong token type
[ ] Refresh for user A cannot be used to obtain tokens for user B
[ ] Expired refresh rejected
[ ] Revoked refresh rejected after logout
[ ] Password change invalidates refresh tokens if policy says so
[ ] Refresh rotation: old refresh rejected after use when rotation enabled
[ ] Concurrent refresh behavior understood (race may issue multiple, or reuse detection)
[ ] Refresh endpoint rate limited

Worked flow:

  1. Login -> access1, refresh1.
  2. Use refresh1 -> access2, refresh2 (if rotating).
  3. Replay refresh1 -> should fail if one-time rotation is required.
  4. Logout or revoke -> refresh2 fails.

Step 10: Logout, revocation, and password change

Designs differ:

  • Stateless JWT until expiry, with short TTL.
  • Denylist for jti until exp.
  • Versioned password stamp embedded in token.
  • Server-side session store behind the JWT.

QA must test the stated design, not an imaginary ideal.

Cases:

  • After logout, access token fails immediately if promised.
  • If access token remains valid until exp by design, confirm TTL is short and refresh is revoked.
  • After password reset, old tokens cannot continue indefinitely if policy requires kill sessions.

Document actual behavior in the bug or test notes so product and security can accept or reject residual risk.

Step 11: Transport and storage observations

While testing clients:

  • Confirm tokens are not placed in URL query strings.
  • Confirm browser storage choices match architecture and that CSRF controls exist if cookies are used.
  • Confirm logs and error reporters do not print full tokens.
  • Confirm HTTPS is required in deployed environments.

Step 12: Cross-service and partner tokens

If partners use JWTs:

  • Validate partner tokens cannot call end-user routes beyond scope.
  • Validate scope claims (scope, permissions) are enforced.
  • Validate client credentials tokens are not overly privileged.

JWT Test Case Catalog

IDTitleStepsExpectedPriority
JWT-01Valid access token succeedsLogin, call protected GET200 and correct dataHigh
JWT-02Missing token failsCall without Authorization401High
JWT-03Tampered payload failsEdit claim keep old sig401Critical
JWT-04Expired token failsWait/use expired token401High
JWT-05Wrong audience failsUse token for other API401High
JWT-06User cannot call adminValid user token on admin route403High
JWT-07Refresh issues new accessPOST refresh with valid refreshNew access token worksHigh
JWT-08Reused rotated refresh failsRefresh twice with same token when rotation onSecond failsHigh
JWT-09Logout revokes refreshLogout then refreshFailHigh
JWT-10alg none rejectedSend none-alg forged token401Critical
JWT-11Token in query rejected or avoidedAttempt access via ?token=Not accepted or not used by clientsMedium
JWT-12Disabled user token failsDisable user, reuse tokenFail per policyHigh

Example curl Patterns

Valid call:

curl -s -o /dev/null -w "%{http_code}\n" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  https://api.staging.example.com/v1/me

Missing token:

curl -s -o /dev/null -w "%{http_code}\n" \
  https://api.staging.example.com/v1/me

Refresh:

curl -s -X POST https://api.staging.example.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type":"refresh_token","refresh_token":"'"$REFRESH_TOKEN"'"}'

Use environment variables so tokens are not pasted into shared chat logs.

Comparing Access Tokens and Refresh Tokens

AspectAccess tokenRefresh token
PurposeAuthorize API callsObtain new access tokens
LifetimeShortLonger
Exposure riskHigh volume useHigher value if stolen
Typical storageMemory/cookie depending on designMore protected handling
QA focusSignature, claims, expiry, authzRotation, revocation, binding, rate limits

Common JWT Implementation Pitfalls QA Can Catch

  1. Trusting payload without verifying signature.
  2. Long-lived access tokens with no revocation story.
  3. Putting passwords or secrets in claims.
  4. Using the same token for all audiences.
  5. Role elevation via client-side claim edits accepted.
  6. Refresh tokens never rotated or never revoked on password change.
  7. Detailed error messages that help attackers (invalid signature vs user disabled inconsistencies may be OK, but stack traces are not).
  8. Tokens logged in APM tools and support dashboards.

How to File a JWT Security Defect

Title: API accepts access tokens with tampered role claim
Environment: staging API v1
Baseline: valid user token returns role user on /v1/me
Steps:
1. Capture access token for user qa_jwt_1.
2. Modify payload role from user to admin without valid re-signing (old signature retained).
3. Call GET /v1/admin/users with modified token.
Actual: 200 and admin user list returned.
Expected: 401 due to invalid signature, or at minimum 403 with no admin data and no trust of client-edited claims.
Impact: Anyone who can obtain any valid token format knowledge may forge admin privileges if signature checks are bypassed; critical auth failure.
Evidence: sanitized tokens redacted to first/last 6 chars, response bodies, timestamps.

Never paste full production tokens into tickets that broad audiences can read.

Common Mistakes When Teams Test JWT Auth

Mistake 1: Only testing login success

A 200 on login proves little about protected route enforcement.

Mistake 2: Decoding tokens and stopping

Readable claims are not validation.

Mistake 3: One role, one user

You will miss vertical privilege problems and subject mismatches.

Mistake 4: Ignoring refresh endpoints

Attackers love refresh grants because they extend sessions.

Mistake 5: No short TTL environment

If access tokens last 24 hours, expiry tests become painful and get skipped. Ask for test-friendly TTLs in staging.

Mistake 6: Treating 403 and 401 as interchangeable without documenting design

They mean different things. Test for the intended contract and keep it consistent.

Mistake 7: Forgetting mobile and old app clients

Old clients may send legacy token headers. Include them in regression if still supported.

Mistake 8: No automation for the boring denials

Missing, expired, and tampered token cases are perfect candidates for CI.

JWT Security Testing Checklist

[ ] Valid token works on intended routes
[ ] Missing/malformed tokens rejected
[ ] Tampered payload rejected
[ ] Tampered signature rejected
[ ] Expired token rejected
[ ] nbf enforced if used
[ ] iss/aud enforced if used
[ ] alg none / unexpected alg rejected
[ ] Role and tenant claims cannot be self-elevated
[ ] Object-level authz still enforced with valid token
[ ] Refresh succeeds when valid
[ ] Refresh fails when expired/revoked/reused (per design)
[ ] Logout/password change behavior matches policy
[ ] Tokens not sent in URLs by official clients
[ ] Tokens not logged in app errors
[ ] Rate limits on login and refresh
[ ] Cross-env token reuse rejected
[ ] Partner scopes enforced

How JWT Testing Fits the Wider Security Program

JWT tests are one slice of API auth. Still test:

  • CSRF if cookies store tokens.
  • XSS impact on token theft for browser storage models.
  • Account recovery flows that issue new tokens.
  • Broken access control on IDs after authentication succeeds.

See security testing for QA for the broader map, and the API security testing checklist for endpoint packing.

Practice Plan for a Team Workshop

One half-day workshop:

  1. Map token issuance in your staging app.
  2. Build the twelve core cases from the catalog.
  3. Automate the five fastest denials in CI.
  4. Review one real defect report format.
  5. Decide staging TTLs with backend engineers.

For ongoing skill building in competitive QA scenarios, register at QABattle sign-up and use API-focused practice in battles.

End-to-End Scenario: Login to Privileged Action

Walk a full lifecycle in staging:

  1. Login as standard user; store access and refresh tokens.
  2. Call /v1/me successfully.
  3. Call /v1/admin/metrics and expect denial.
  4. Tamper with role claim; expect rejection.
  5. Wait for access expiry; expect /v1/me denial.
  6. Refresh; expect new access token success on /v1/me.
  7. Change password as the user.
  8. Confirm old refresh fails if policy requires session kill.
  9. Login again; confirm new tokens work.
  10. Logout; confirm refresh fails.

This single scenario often surfaces more design truths than ten isolated payload edits.

Service Accounts and Machine Tokens

Not all JWTs belong to humans.

Machine token checks:

[ ] Client credentials token cannot perform end-user-only actions
[ ] Scopes are minimized for each service
[ ] Token TTL is appropriate for machine use
[ ] Audience restricted to intended services
[ ] Compromised client secret rotation process exists and is testable in staging

A service token with scope=* is a future incident report.

Mobile App Specific JWT Checks

Mobile clients introduce storage and refresh edge cases.

Check:

  • Tokens are not logged by debug builds shipped to testers accidentally.
  • App uses official refresh flow, not home-grown insecure storage of passwords.
  • Certificate pinning discussions are handled by mobile security owners; QA still verifies traffic against staging with approved tools.
  • App handles 401 by refresh-then-retry without dropping users into endless loops.
  • After logout, tokens are cleared from local storage/keychain equivalents.

Microservices Validation Consistency

In multi-service systems, one gateway may validate JWT while an internal service trusts headers blindly.

Risk pattern:

  1. Gateway checks signature.
  2. Gateway forwards X-User-Id to internal services.
  3. Internal services are also reachable through another path that does not validate.

QA and AppSec should confirm trust boundaries:

  • Can internal endpoints be called directly from places they should not?
  • Do services re-validate tokens when required by architecture?
  • Are user identity headers signed or otherwise protected from spoofing inside the mesh?

This is advanced for pure black-box QA, but asking the question during design reviews prevents ugly production findings.

Negative Claim Matrix

Build a matrix of claim manipulations:

Claim changedNew valueExpected
exppast timereject
expfar future without valid resignreject
subother user id without resignreject
roleadmin without resignreject
audwrong APIreject
issattacker issuer URLreject
tenant_idother tenant without resignreject

Every row assumes signature validation still must fail closed when the token is not resignable by the client.

JWT Header Puzzles Worth a Look

Besides alg, inspect:

  • kid values: does the server fetch keys unsafely based on attacker-controlled kid?
  • Unexpected typ values.
  • Extremely large headers that may stress parsers.

If you observe strange key loading behavior, stop and involve security specialists. Some kid issues become SSRF-class problems.

Performance and Availability Side Notes

Security testing can accidentally become load testing.

Be careful with:

  • Tight loops on login endpoints
  • Massive concurrent refresh storms
  • Huge malformed tokens that stress parsers

Stay inside agreed rates. Security quality includes being a good steward of shared staging.

Documentation QA Should Demand

Ask engineering for a short auth contract:

Access token TTL:
Refresh token TTL:
Rotation policy:
Revocation policy on logout:
Revocation policy on password change:
Required claims:
Accepted algorithms:
Clock skew tolerance:
Where public keys are published:

Without this, testers guess and severity debates drag on.

Mapping Findings to Fix Owners

Finding typeLikely owner
Signature not verifiedAuth service / API platform
Missing exp checkAuth library configuration
Role claim trusted without DB/policy checkApp authorization layer
Refresh not revokedIdentity service
Token logged in errorsObservability + app handlers
Token in query stringClient teams

Good routing shortens mean time to remediate.

Practice Script for New QA Hires

Day one JWT lab:

  1. Decode a staging token offline.
  2. Call a protected route with and without it.
  3. Flip one payload character and observe failure.
  4. Capture refresh flow.
  5. Write one defect-style note even if everything passes, describing residual risk and what was evidenced.

This builds confidence without requiring crypto expertise.

When you know how to test JWT authentication, you stop treating bearer tokens as magic strings and start treating them as verifiable trust objects with a lifecycle.

Conclusion

Learning how to test JWT authentication means proving that tokens are hard to forge, short-lived enough to manage risk, validated on every protected call, and paired with real authorization checks. Decode claims to understand them, then attack your own staging tokens with missing values, expiry, tampering, refresh reuse, and role edits.

When those tests are part of ordinary API regression, login is no longer a green checkbox. It becomes a verified trust boundary. That is what modern API quality requires.

FAQ

Questions testers ask

How do you test JWT authentication as a QA?

Obtain valid tokens from the real login or token endpoint, decode claims without trusting them blindly, then replay API calls with missing, expired, malformed, unsigned, and tampered tokens. Verify protected routes reject bad tokens, accept good ones, and honor role and subject claims server-side.

What claims should QA validate in a JWT?

Common claims include iss, aud, exp, nbf, iat, sub, and app-specific roles or tenant IDs. Testing means confirming the server enforces them, not only that they appear in a decoded payload. Expired tokens and wrong audience values should fail.

What is the JWT alg=none test?

It checks whether the API accepts a token that declares no signature algorithm and carries an empty or absent signature. Secure systems reject this. Acceptance can allow attackers to forge tokens with arbitrary claims.

How should refresh tokens be tested?

Verify refresh issues new access tokens, rejects reused revoked refresh tokens if rotation is required, binds to the right user, expires correctly, and does not expose refresh tokens to insecure storage patterns in clients you control. Test logout and password change revocation paths.

Is decoding a JWT enough to test security?

No. Anyone can decode a base64 payload. Security comes from server-side signature verification and claim enforcement. QA must send modified tokens to the API and observe accept or reject behavior.

Where should JWTs be stored in web apps?

Storage is an architecture choice with trade-offs. HttpOnly secure cookies reduce XSS token theft but need CSRF defenses. localStorage is easy for SPAs but readable by XSS. QA should test the chosen design's failure modes rather than arguing absolutes without context.