Resource library

Cyber QA

JWT security testing: A QA Guide (2026)

Learn JWT security testing safely with threat-based cases for signatures, claims, JWKS rotation, authorization, token transport, and runnable PyJWT tests.

25 min read | 3,458 words

TL;DR

JWT security testing proves that an API accepts only correctly signed tokens from the expected issuer for the expected audience and time window, then applies authorization independently. Test algorithm restrictions, signature tampering, required claims, JWKS rotation, tenant and scope boundaries, token transport, revocation policy, and safe failure behavior.

Key Takeaways

  • Treat JWT acceptance as a sequence of parsing, algorithm, signature, issuer, audience, time, subject, and authorization decisions.
  • Configure allowed algorithms on the verifier instead of trusting the token's `alg` header.
  • Test valid signatures with wrong issuer, audience, tenant, scope, and resource ownership because authentication is not authorization.
  • Exercise JWKS cache refresh, key rotation, unknown `kid`, duplicate identifiers, and provider outages without weakening verification.
  • Verify tokens are protected in headers, cookies, browser storage, URLs, logs, traces, reports, and error messages.
  • Use real signed fixtures and controlled keys for integration tests, then keep malformed-token cases small and threat-driven.
  • Assert safe 401 and 403 behavior plus the absence of data and side effects, not just an error message.

JWT security testing is the disciplined verification that a service accepts only authentic, correctly targeted, currently valid tokens and still enforces authorization after authentication. A JWT that parses successfully is not necessarily trustworthy. The verifier must restrict algorithms, validate the signature with the correct key, enforce issuer and audience, apply time rules, require identity claims, and translate claims into permissions without trusting attacker-controlled values.

The best QA approach is threat-based rather than payload-random. Model each trust decision, create one controlled mutation at a time, and assert both the rejection response and the protected postcondition. This guide covers signed access tokens, JWKS rotation, API and browser risks, runnable PyJWT tests, and interview-ready reasoning for 2026 systems.

TL;DR

Control Positive case High-value negative case Expected evidence
Algorithm policy Allowed asymmetric algorithm none or unapproved algorithm Rejected before claims are trusted
Signature Trusted active key Changed payload or signature 401, no protected data
Issuer Exact configured issuer Valid signature, foreign issuer 401 and stable error class
Audience Intended API audience Token issued for another API 401, no cross-service acceptance
Time Current token within policy Expired or not-yet-valid token Rejection with tested clock policy
Key selection Known active kid Unknown, duplicate, or retired kid Safe failure and controlled refresh
Authorization Required scope and ownership Valid token, wrong tenant or owner 403 or concealment policy, no side effect
Transport Protected header or secure cookie URL, logs, unsafe browser storage Token never leaked to unintended sinks

Do not decode a JWT and call the test complete. Acceptance is a chain, and every link needs an oracle.

1. Build a JWT Security Testing Trust Model

A compact JWT has three base64url-encoded segments: protected header, payload, and signature. The header may name the algorithm and a key identifier. The payload contains claims. Neither header nor payload is confidential merely because it is encoded. Anyone holding the token can usually read them. The signature provides integrity and issuer authentication when verification is configured correctly. Encryption is a separate mechanism.

Map the actors before creating cases: authorization server or identity provider, signing-key store, JWKS endpoint, API gateway, resource server, browser or mobile client, logs, caches, and downstream services. Record which component verifies the token and which one makes authorization decisions. If the gateway verifies but the service trusts forwarded identity headers, test whether callers can reach the service directly or spoof those headers.

Define protected assets and security boundaries. Examples include tenant data, admin actions, payment details, password changes, exports, and service-to-service operations. Then identify attacker capabilities: alter a captured token, obtain a token for a different audience, use an expired token, select an unexpected key, replay a token, manipulate browser transport, or present a valid low-privilege identity against another user's resource.

Create a verification sequence in the specification. A typical order is bounded parsing, allowed algorithm selection from server configuration, key selection, signature verification, issuer and audience checks, time validation, required-claim validation, subject and tenant resolution, then endpoint authorization. Tests should prove that untrusted claims are not used for database lookup, logging decisions, or routing before cryptographic verification.

For a broader API threat inventory, pair this model with API security testing with OWASP.

2. Understand JWT, JWS, JWE, and Opaque Tokens

JWT describes a claims format. A signed JWT is commonly represented using JSON Web Signature. An encrypted token uses JSON Web Encryption. Many OAuth access tokens are signed JWTs, but OAuth does not require that format. An opaque access token may require introspection. An OpenID Connect ID token is meant for the client and should not automatically be sent as an API access token. Test plans must identify the actual token type and intended consumer.

Token form What the consumer validates Confidential by default? Typical QA focus
Signed JWT access token Signature, claims, authorization No algorithm, issuer, audience, time, scope
Encrypted JWT Decryption plus inner integrity and claims Yes, if correctly configured key use, nested validation, safe failure
Opaque access token Introspection response or gateway result Not readable locally active state, cache, outage, audience, scope
ID token Client authentication context No nonce, issuer, client audience, time
Session cookie Server-side session mapping Value-dependent cookie flags, fixation, rotation, CSRF

This distinction prevents common invalid tests. Sending an ID token to an API may be rejected because its audience is the client, not the resource server. Attempting to decode an opaque token locally proves nothing. Expecting a signed JWT to hide personal data is also wrong. Its payload may be visible in browser tools, proxy logs, and telemetry.

Document whether access tokens are bearer tokens. A bearer token can be used by whoever possesses it, so transport and storage controls matter as much as signature correctness. Sender-constrained schemes can reduce replay, but they add proof and key-binding checks that need their own cases. Stay aligned with the identity provider and API contract rather than assuming every token ecosystem uses the same claims.

3. Test Algorithm and Signature Validation

The verifier must choose allowed algorithms from trusted configuration. It must not accept whatever the untrusted alg header requests. Test a valid token using the configured algorithm, a token marked none, a token using another supported-by-library but unapproved algorithm, a token with an empty signature, a valid token with one changed payload byte, a truncated token, extra segments, invalid base64url, and an oversized input.

Algorithm confusion tests should be safe and specific to the actual key model. In an asymmetric deployment, the private key signs and the public key verifies. A verifier that mistakenly treats public-key material as a symmetric HMAC secret can be vulnerable if configuration permits algorithm substitution. Modern libraries include defenses, but QA should verify application configuration instead of relying on a library name. Never create offensive tokens against systems you do not own or have authorization to test.

For signature tampering, take a valid test token, change a harmless claim in the payload segment without resigning, and expect rejection. Do not only corrupt the last signature character because some base64 encodings can produce ambiguous test mutations if padding bits are involved. Rebuild the payload segment with a changed value and preserve the original signature.

Check error handling. External responses should not reveal key paths, library stack traces, raw token values, signing material, or detailed distinctions that help an attacker enumerate keys. Internally, logs should retain a safe reason category and correlation ID. A missing token and invalid token normally map to 401, while a valid authenticated principal that lacks permission normally maps to 403 or the API's documented resource-concealment behavior. API error handling and negative testing gives a reusable oracle for those failures.

4. Validate Registered and Private Claims

A correct signature says that the signer protected the bytes. It does not say the token was issued by the expected authority, intended for this API, current, complete, or authorized for the action. Test claims independently with tokens signed by controlled trusted keys so a signature error does not mask the claim rule.

iss should match the configured issuer comparison rule. aud may be a string or an array in JWT representations, and the library should determine whether the expected audience is present. Test missing audience, wrong API, a related environment such as staging versus production, and multiple audiences according to policy. exp controls expiry, nbf controls earliest acceptance, and iat can support age or anomaly policies. Use an injected clock at the application boundary where possible and test just inside, at, and just outside any documented skew.

Require the claims your authorization model needs. A missing sub, tenant ID, client ID, token type, or scope should not become an anonymous default or broad access. Validate types too. An array where a string is expected, a numeric subject, deeply nested custom data, or a scope string parsed with the wrong delimiter can trigger unsafe coercion.

Private claims need namespace and trust review. A client should not be able to copy role: admin into a self-issued or incorrectly targeted token and gain access. Map claims from specific issuers and token types. If permissions are loaded from a database rather than embedded, test stale and disabled accounts. If embedded roles remain valid until expiry, document the revocation window and create tests around it rather than pretending changes are instant.

5. Exercise Expiry, Clock Skew, Replay, and Revocation

Time tests become flaky when they rely on wall-clock sleeps. Prefer a token factory and a verifier with an injectable clock. If the library reads system time directly, generate tokens with generous offsets for ordinary tests and reserve narrow boundary checks for an isolated component where the clock can be controlled. Record all timestamps in UTC and use numeric-date semantics consistently.

Test an active token, exactly expired token according to library semantics, clearly expired token, not-yet-valid token, future-issued token if the application constrains iat, token older than a maximum age, and values just within and outside configured leeway. Leeway is a bounded allowance for clock differences, not a way to extend normal lifetime. Verify the configured value, because a large skew can turn a short token into a long-lived credential.

JWT validation alone does not necessarily prevent replay. If a bearer token is captured, it can normally be reused until expiry unless the system adds sender binding, a jti denylist, session state, or a risk control. Test the actual policy. For one-time action tokens, repeat the same jti and assert the action occurs once. For access tokens designed for reuse, do not write a false test expecting second use to fail. Instead, test token theft mitigations, lifetime, rotation, and monitoring.

Revocation is architectural. A self-contained token may remain valid until expiry. Systems that need faster response can consult session state, token version, introspection, or a denylist. Test disabled users, password reset, logout, key compromise, and role removal according to documented propagation time. Include cache behavior and fail-safe decisions when the revocation store is unavailable.

6. Test Issuer, Audience, Tenant, Scope, and Ownership

Authorization is where many JWT implementations fail despite excellent cryptography. Build a matrix across subject, client, tenant, audience, scopes or roles, endpoint, HTTP method, resource owner, resource state, and sensitive fields. A valid token for tenant A must not read, update, delete, search, export, or infer tenant B data. A read scope must not authorize write methods. An admin role in one organization must not become global administration unless explicitly designed.

Test vertical privilege escalation with low-role tokens against admin operations. Test horizontal access with two ordinary users and swapped resource identifiers. Include collection endpoints, filters, batch actions, nested routes, file downloads, GraphQL fields, and indirect references. A secure direct GET /users/{id} does not compensate for an export endpoint that ignores tenant scope.

Audience and scope solve different problems. Audience answers which resource server should accept the token. Scope or role contributes to what the principal may do there. A token for API B with an admin string should still be rejected by API A. A token for API A with a valid signature but missing the required scope should authenticate and then fail authorization. Keeping these outcomes distinct helps clients and monitoring.

Postconditions are mandatory for denied mutations. After 403 or concealed 404, read the resource through an authorized control account and verify version, protected fields, and related records did not change. Inspect events and notifications if the code could emit them before authorization. The test is stronger when it proves the authorization guard runs before expensive work and side effects.

For schema-level token and security declarations around endpoints, see OpenAPI schema testing, then add runtime cases because documentation alone cannot prove enforcement.

7. Test JWKS Fetching, Caching, and Key Rotation

Resource servers often obtain public verification keys from a JSON Web Key Set. Key selection frequently uses kid, but that identifier is not proof of trust. The JWKS must come from configured issuer metadata or a pinned trusted location. Do not let an untrusted header redirect the verifier to an arbitrary URL. Test that any header-based key URL fields are ignored or rejected unless the architecture deliberately and safely supports them.

Build a controllable JWKS server with key A and key B. Start with A active and cached. Rotate by publishing both A and B, issue a token with B, then retire A after the overlap window. Verify known cached keys do not require a fetch per request, a new legitimate kid triggers a bounded refresh, and tokens signed by retired keys fail after policy says they should. Test rollbacks and overlapping deployments.

Unknown kid traffic can cause a fetch storm. Send many tokens with different unknown identifiers and assert rate limiting, negative caching, request coalescing, and bounded outbound calls. The verifier must not fail open if the JWKS endpoint is slow or unavailable. Existing cached keys may remain usable within cache policy, while a completely unknown key should not be trusted. Capture whether stale-cache behavior is intentional.

Test duplicate key identifiers, keys with an unexpected use or algorithm, malformed JSON, oversized sets, missing modulus or curve values, TLS failure, redirects, cache headers, and provider 5xx. The goal is robust failure without accepting a token under the wrong key. Avoid assertions tied to internal cache implementation unless that behavior is part of an operational requirement. Public outcomes, fetch counts, latency bounds, and security events make stronger oracles.

8. Run JWT Signature and Claims Tests with PyJWT

The following pytest module generates an RSA key pair at test time, signs controlled tokens, and verifies an explicit algorithm, issuer, audience, and required claims. It uses public PyJWT and cryptography APIs. Save it as test_jwt_security.py, install pytest, PyJWT, and cryptography, then run pytest -q.

import base64
import json
from datetime import datetime, timedelta, timezone

import jwt
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

ISSUER = "https://identity.test.example"
AUDIENCE = "orders-api"

@pytest.fixture(scope="module")
def keys():
    private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
    private_pem = private_key.private_bytes(
        serialization.Encoding.PEM,
        serialization.PrivateFormat.PKCS8,
        serialization.NoEncryption(),
    )
    public_pem = private_key.public_key().public_bytes(
        serialization.Encoding.PEM,
        serialization.PublicFormat.SubjectPublicKeyInfo,
    )
    return private_pem, public_pem

def claims(**overrides):
    now = datetime.now(timezone.utc)
    value = {
        "iss": ISSUER,
        "aud": AUDIENCE,
        "sub": "user-42",
        "iat": now,
        "exp": now + timedelta(minutes=10),
        "scope": "orders:read",
    }
    value.update(overrides)
    return value

def verify(token, public_key):
    return jwt.decode(
        token,
        public_key,
        algorithms=["RS256"],
        issuer=ISSUER,
        audience=AUDIENCE,
        options={"require": ["exp", "iat", "sub", "iss", "aud"]},
    )

def b64url(data):
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")

def test_accepts_valid_token(keys):
    private_key, public_key = keys
    token = jwt.encode(claims(), private_key, algorithm="RS256", headers={"kid": "key-a"})
    decoded = verify(token, public_key)
    assert decoded["sub"] == "user-42"
    assert decoded["scope"] == "orders:read"

def test_rejects_none_algorithm(keys):
    _, public_key = keys
    header = b64url(json.dumps({"alg": "none", "typ": "JWT"}).encode())
    payload = b64url(json.dumps(claims(sub="admin"), default=str).encode())
    unsigned = f"{header}.{payload}."
    with pytest.raises(jwt.InvalidAlgorithmError):
        verify(unsigned, public_key)

def test_rejects_tampered_payload(keys):
    private_key, public_key = keys
    token = jwt.encode(claims(), private_key, algorithm="RS256")
    header, _, signature = token.split(".")
    changed_payload = b64url(json.dumps({"sub": "admin"}).encode())
    tampered = f"{header}.{changed_payload}.{signature}"
    with pytest.raises(jwt.InvalidSignatureError):
        verify(tampered, public_key)

def test_rejects_wrong_audience(keys):
    private_key, public_key = keys
    token = jwt.encode(claims(aud="billing-api"), private_key, algorithm="RS256")
    with pytest.raises(jwt.InvalidAudienceError):
        verify(token, public_key)

def test_rejects_expired_token(keys):
    private_key, public_key = keys
    now = datetime.now(timezone.utc)
    token = jwt.encode(
        claims(iat=now - timedelta(minutes=20), exp=now - timedelta(minutes=10)),
        private_key,
        algorithm="RS256",
    )
    with pytest.raises(jwt.ExpiredSignatureError):
        verify(token, public_key)

def test_requires_subject(keys):
    private_key, public_key = keys
    payload = claims()
    del payload["sub"]
    token = jwt.encode(payload, private_key, algorithm="RS256")
    with pytest.raises(jwt.MissingRequiredClaimError):
        verify(token, public_key)

The altered payload test intentionally replaces all claims, so signature verification fails before claim validation. Claim-specific cases use a legitimate test signer and isolate the intended rule. In API integration tests, obtain tokens through a controlled identity fixture when you are verifying the real authorization server contract. Never commit production signing keys.

9. Secure Token Transport, Storage, Logs, and Errors

For APIs, send bearer access tokens in the Authorization header over TLS. Do not place tokens in query strings because URLs reach browser history, reverse-proxy logs, analytics, referrer data, screenshots, and support tools. If a browser uses cookies, test Secure, HttpOnly, and an appropriate SameSite policy, plus CSRF protection where cross-site requests are possible. Cookie and header architectures have different threat models, so avoid one-size-fits-all assertions.

Review browser storage. Tokens in localStorage are accessible to JavaScript running in the origin, which increases impact from cross-site scripting. An in-memory token reduces persistence but does not solve script execution. A hardened cookie can block JavaScript reads but requires CSRF and session design. QA should trace the actual application flow: login response, redirects, refresh, tab sharing, logout, expiry, and error recovery.

Seed a recognizable fake token into a test and search approved logs, traces, reports, captured network attachments, exception messages, analytics calls, and crash output. Assert redaction at capture time. Do not print tokens to console just to make automation easier. If a report must correlate attempts, store a nonreversible short fingerprint under a documented security policy.

Test CORS and caching around authenticated responses. A protected response should not become shared across users through an intermediary cache. Error bodies should not echo the raw token or decode its claims. Rate limits should prevent token parsing abuse from becoming a denial-of-service path. Also bound header and token sizes before expensive key operations. These tests connect application security with operational resilience.

10. Operationalize JWT Security Testing in CI

Create a small deterministic commit suite: valid token, missing token, malformed token, unapproved algorithm, changed payload, wrong issuer, wrong audience, expired token, missing required claim, insufficient scope, and cross-tenant resource access. Run it against every service that validates tokens. Keep token factories centralized enough to enforce safe defaults, but let tests override one claim at a time.

Add component cases for JWKS cache, rotation, outage, unknown kid, and concurrent refresh. Run multi-service audience tests in an integration environment. Browser flows should cover storage, refresh, logout, cookie flags, and leakage sinks. Schedule heavier malformed-input and load cases in isolated environments with explicit authorization and traffic limits.

Maintain independent positive controls. If every negative test fails because the signing fixture broke, the suite provides little evidence. A known valid token should pass the authentication layer, and an authorized control request should reach the resource. Then each mutation should fail for the intended reason, which you can confirm through safe internal telemetry without making public errors overly detailed.

Review identity configuration changes like code. Issuer URLs, audiences, algorithms, JWKS endpoints, skew, cache TTL, role mappings, and proxy trust boundaries deserve version control, peer review, and regression tests. Track dependencies and security advisories, but do not assume upgrading a JWT library corrects unsafe application choices. JWT authentication testing can complement this security-focused guide with broader functional authentication flows.

Interview Questions and Answers

Q: What is the first rule of JWT validation?

Treat the token as untrusted until cryptographic verification and required claim checks succeed. Configure allowed algorithms and trusted issuers outside the token. Do not use header or payload values to make privileged decisions before verification.

Q: Is decoding a JWT the same as verifying it?

No. Decoding only turns encoded bytes into readable JSON. Verification checks integrity with a trusted key and then enforces issuer, audience, time, and required-claim rules. Authorization still follows.

Q: How would you test algorithm confusion?

I confirm the verifier has an explicit algorithm allowlist, then present tokens using none and an unapproved algorithm. In an asymmetric deployment, I also verify the application never treats public-key material as an HMAC secret. All testing stays within an authorized environment.

Q: Why must audience be tested when the signature is valid?

One identity provider may issue tokens for several services. A valid signature proves the issuer, not that this API is the intended recipient. Wrong-audience acceptance enables cross-service token misuse.

Q: How do you test JWKS rotation?

I operate a controllable JWKS endpoint, publish overlapping old and new keys, issue tokens for both, then retire the old key according to policy. I verify cache refresh, unknown-key behavior, bounded outbound requests, and safe failure during provider outage.

Q: What is the difference between 401 and 403 in JWT tests?

A missing, invalid, expired, or wrongly targeted token normally fails authentication with 401. A valid authenticated principal that lacks permission normally receives 403, unless the API deliberately conceals resource existence. In both cases I assert no protected data or side effect.

Q: Can logout instantly invalidate a JWT?

Not automatically. A self-contained token may remain valid until expiry unless the architecture checks revocation, session state, token version, or introspection. I test the documented invalidation window rather than assuming instant revocation.

Concise versions of these answers are available in interviewQnA for focused preparation.

Common Mistakes

  • Decoding the payload and treating successful JSON parsing as authentication.
  • Trusting the token's alg, key URL, role, or tenant value before verification.
  • Testing only broken signatures and missing validly signed tokens with wrong issuer or audience.
  • Accepting an ID token where an access token for the API is required.
  • Using a broad leeway that silently extends short token lifetimes.
  • Equating authentication with authorization and skipping ownership, tenant, field, and method checks.
  • Fetching JWKS for every unknown kid without negative caching or request coalescing.
  • Failing open when JWKS, introspection, or revocation dependencies are unavailable.
  • Storing bearer tokens in URLs or emitting them into logs, traces, screenshots, and test reports.
  • Committing private keys or durable real tokens as test fixtures.
  • Using wall-clock sleeps for boundary cases and accepting flaky expiry tests.
  • Expecting logout or role removal to be instant without an architecture that supports it.

Conclusion

JWT security testing should prove a complete trust chain: approved algorithm, valid signature under a trusted key, correct issuer and audience, acceptable time window, required claims, and independent authorization for the requested resource. It should also prove that key rotation and token transport fail safely under real operational pressure.

Begin with one valid signed control token, then mutate one trust decision per case. Add cross-tenant and cross-audience scenarios before exotic malformed inputs, because correctly signed but misused tokens often expose the most consequential application defects. Finish by testing JWKS lifecycle and token leakage so cryptographic strength is not undone by deployment behavior.

Interview Questions and Answers

What steps should a JWT verifier perform?

It should parse within limits, restrict algorithms from trusted configuration, select a trusted key, verify the signature, and validate issuer, audience, time, and required claims. Only then should it resolve identity and perform endpoint authorization. Untrusted claims must not make privileged decisions earlier.

What is the difference between decoding and verifying a JWT?

Decoding exposes the JSON header and payload but provides no trust. Verification checks the signature with an approved algorithm and trusted key, then validates claims. A verified identity still needs authorization checks.

How do you test JWT signature security?

I start with a real signed control token, then test an unapproved algorithm, `none`, an empty signature, a changed payload, changed signature, malformed segments, and oversized input. I assert a safe 401 response, no protected result, and a useful redacted internal reason.

Why are issuer and audience both important?

Issuer limits which authority may vouch for the claims. Audience limits which resource server may consume the token. A token can have a valid signature from a trusted platform and still be intended for a different API.

How would you verify JWT key rotation?

I use a controlled JWKS server and rotate from key A to an overlap of A and B, then to B only. I test cached keys, refresh on a legitimate new `kid`, retirement, outages, malformed sets, and bounded fetch behavior for unknown identifiers.

How do you distinguish authentication and authorization failures?

Invalid or absent credentials normally produce 401. A valid identity without permission normally produces 403 or a documented concealment response. I also verify denied requests leave protected state and side effects unchanged.

What token leakage checks would you automate?

I seed a recognizable fake token and inspect approved logs, traces, analytics, exception output, URLs, screenshots, and test reports for leakage. I verify header or cookie protections and redaction at capture time. I never use production credentials for this test.

Frequently Asked Questions

What is JWT security testing?

JWT security testing verifies algorithm restrictions, signature integrity, trusted issuer and audience, time and required claims, key rotation, authorization, and safe token handling. It also proves rejected requests expose no protected data or side effects.

Is it safe to read the claims in a JWT?

Reading claims is not the same as trusting them. Signed JWT payloads are usually visible to the holder, and claims must not drive privileged behavior until signature and claim validation succeeds. Sensitive data generally should not be placed in a readable token.

Which JWT claims should an API validate?

At minimum, validate the claims required by the contract, commonly issuer, audience, expiry, subject, and any not-before rule. Tenant, token type, client, scope, and custom claims may also be required for authorization.

How do you test an expired JWT without flaky sleeps?

Generate a token that is clearly expired and use a controlled clock for narrow boundary cases. Test just inside and outside documented leeway rather than waiting in real time.

What is a JWKS rotation test?

It verifies that a verifier can accept a newly published trusted key, continue using allowed overlapping keys, and reject retired or unknown keys. It should also cover cache refresh, concurrent fetches, malformed sets, and endpoint outages.

Should JWTs be stored in localStorage?

There is no universal browser storage choice. JavaScript-readable storage increases the impact of cross-site scripting, while secure cookies require CSRF-aware design. QA should test the selected architecture, refresh flow, logout, leakage, and cookie controls.

Does a valid JWT signature prove the user is authorized?

No. It proves integrity under a trusted key after correct verification. The API must still enforce audience, tenant, scope or role, resource ownership, method, state, and field-level rules.

Related Guides