Skip to content

Rewrite JSON Web Token Cheat Sheet: language-agnostic, drop Java code#2083

Open
Copilot wants to merge 5 commits intomasterfrom
copilot/add-jwt-section-to-authentication-cheat-sheet
Open

Rewrite JSON Web Token Cheat Sheet: language-agnostic, drop Java code#2083
Copilot wants to merge 5 commits intomasterfrom
copilot/add-jwt-section-to-authentication-cheat-sheet

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

Replaces the Java-specific JWT cheat sheet (629 lines) with a concise, language-agnostic security guide (164 lines) covering all known JWT attack classes.

Changes

  • Removed all Java code examples and references to the Java POC project
  • Restructured around 8 numbered vulnerability categories, each with a concise Risk + Mitigations format:
    1. Algorithm confusion (alg: none, RS256 → HS256 key confusion)
    2. Weak signing secrets (offline HMAC brute-force)
    3. Missing/insufficient claims validation (exp, nbf, iat, iss, aud, sub)
    4. Sensitive data in unencrypted payload (JWE/AES-GCM guidance)
    5. Insecure client-side token storage (localStorage vs memory/closures vs hardened cookies)
    6. Token sidejacking (fingerprint cookie + SHA-256 hash in JWT claim)
    7. Lack of token revocation (jti denylist, refresh token rotation)
    8. Header injection (kid, jku, x5u — SQL injection, path traversal, SSRF vectors)
  • Added Best Practices Summary (8 rules) and a References section (RFC 7519/7515/7516/8725, PortSwigger, jwt.io, Auth0 CVE post, JWT Attack Playbook)

Checklist

  • All the markdown files do not raise any validation policy violation, see the policy.
  • All the markdown files follow these format rules.
  • In case of a new Cheat Sheet, you have used the Cheat Sheet template.
  • All your assets are stored in the assets folder.
  • All the images used are in the PNG format.
  • Any references to websites have been formatted as [TEXT](URL)
  • You verified/tested the effectiveness of your contribution (e.g., the defensive code proposed is really an effective remediation? Please verify it works!).
  • The CI build of your PR pass, see the build status here.

AI Tool Usage Disclosure (required for all PRs)

  • I have used AI tools to generate the contents of this PR. I have verified
    the contents and I affirm the results. The LLM used is claude-sonnet-4-5
    and the prompt used is: Rewrite JSON_Web_Token_Cheat_Sheet as a concise, language-agnostic security cheat sheet covering all known JWT security flaws with good references. Drop Java code.

⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.

…at Sheet

- Add 'JSON Web Tokens (JWT)' section to Authentication Cheat Sheet with
  common implementation mistakes (storage, expiration, alg:none, claim
  validation, payload data, weak secrets, revocation)
- Rename JSON_Web_Token_for_Java_Cheat_Sheet.md to JSON_Web_Token_Cheat_Sheet.md
  and update Objective section to note Java examples are language-neutral
- Update all cross-references across Index.md, IndexASVS.md, IndexASVS4.md,
  IndexMASVS.md, IndexProactiveControls.md, IndexTopTen.md,
  Forgot_Password_Cheat_Sheet.md, REST_Security_Cheat_Sheet.md

Closes #1973
Closes #1176

Co-authored-by: mackowski <[email protected]>
Agent-Logs-Url: https://github.com/OWASP/CheatSheetSeries/sessions/a9a54bd6-cdc5-4d96-86db-c4c2583cfe89
Copilot AI changed the title [WIP] Add JWT mistakes section to Authentication Cheat Sheet Add JWT section to Authentication Cheat Sheet; generalize JWT Cheat Sheet (drop "for Java") Mar 26, 2026
Copilot AI requested a review from mackowski March 26, 2026 15:00
@mackowski
Copy link
Copy Markdown
Collaborator

This is WIP, I am still working on this ;-)

…alone JWT Cheat Sheet

- Expand Authentication_Cheat_Sheet.md JWT section to cover all topics
  from the removed JWT CS: token structure overview, session management
  reference, token sidejacking (fingerprinting), expanded revocation
  options (denylist + fingerprinting+sessionStorage), JWE reference
  (RFC 7516), and Further Reading (RFC 8725, JWT Attack Playbook)
- Delete JSON_Web_Token_Cheat_Sheet.md completely (no content duplication)
- Update Forgot_Password_Cheat_Sheet.md link → Auth CS JWT section
- Update REST_Security_Cheat_Sheet.md link → Auth CS JWT section
- Update IndexASVS, IndexASVS4, IndexMASVS, IndexProactiveControls,
  IndexTopTen to replace JWT CS link with Auth CS JWT section link
- Regenerate Index.md via script (count: 112 → 111, JWT CS entry removed)

Closes #1973
Closes #1176

Agent-Logs-Url: https://github.com/OWASP/CheatSheetSeries/sessions/c2eb6d41-32a8-46f5-bdbf-e0abc98044ad

Co-authored-by: mackowski <[email protected]>
Copilot AI changed the title Add JWT section to Authentication Cheat Sheet; generalize JWT Cheat Sheet (drop "for Java") Consolidate JWT guidance into Authentication Cheat Sheet; remove standalone JWT Cheat Sheet Mar 26, 2026
@mackowski mackowski marked this pull request as ready for review March 26, 2026 15:49
@mackowski
Copy link
Copy Markdown
Collaborator

@jmanico @szh this PR fixes issue #1973 and #1176. We already had some PRs for this issues, I hope here we will iterate and have a content we are happy about and we will be able to close this 2 issues.

@jmanico
Copy link
Copy Markdown
Member

jmanico commented Mar 26, 2026

@mackowski my concern is that this is the wrong direction. I would much rather move all the JWT content into a JWT cheatsheet and link the AuthN cheatsheet to it. My goal is to avoid building large guides and keep these to small cheatsheets.

So I politely think this is the wrong direction, but I also do not want to derail you. If you want this in, go ahead and force-merge it and we can address splitting out the JWT work in a different issue.

@mackowski
Copy link
Copy Markdown
Collaborator

Good idea @jmanico I will move this to separate cheatsheet and reference in AuthN cheatsheet. For now I will keep it short and concise.
I will do this over the weekend ;-)

…T section

Per reviewer feedback ("move all the JWT content into a JWT cheatsheet and
link the AuthN cheatsheet to it; keep these to small cheatsheets"):

- Restore cheatsheets/JSON_Web_Token_Cheat_Sheet.md as standalone
  comprehensive cheatsheet (token structure, sidejacking, revocation,
  info disclosure, storage, weak secrets, implementation examples)
- Fix self-reference anchor in JWT CS (JSON_Web_Token_Cheat_Sheet.md
  #token-sidejacking → #token-sidejacking)
- Trim Authentication_Cheat_Sheet.md JWT section to a 2-sentence
  paragraph with links to JWT CS and Session Management CS
- Update Forgot_Password_Cheat_Sheet.md → JSON_Web_Token_Cheat_Sheet.md
- Update REST_Security_Cheat_Sheet.md → JWT CS #no-built-in-token-revocation
- Restore IndexASVS, IndexASVS4, IndexMASVS, IndexProactiveControls,
  IndexTopTen to link to JWT CS (not Auth CS anchor)
- Regenerate Index.md (count: 111 → 112)

Agent-Logs-Url: https://github.com/OWASP/CheatSheetSeries/sessions/1caf9112-f7dd-4b0a-b47c-c0da156cbadd

Co-authored-by: mackowski <[email protected]>
Copilot AI changed the title Consolidate JWT guidance into Authentication Cheat Sheet; remove standalone JWT Cheat Sheet Restore dedicated JWT Cheat Sheet; trim Authentication Cheat Sheet JWT section Mar 26, 2026
Copilot stopped work on behalf of mackowski due to an error March 26, 2026 20:23
…rity guide

- Remove all Java code examples (629 lines → 164 lines)
- Restructure around 8 security vulnerability categories with risk/mitigation format
- Cover: alg:none, RS256→HS256 confusion, weak secrets, missing claims validation,
  sensitive data in payload, insecure storage, token sidejacking, lack of revocation,
  header injection (kid/jku/x5u)
- Add Best Practices Summary and References sections
- All markdownlint checks pass

Agent-Logs-Url: https://github.com/OWASP/CheatSheetSeries/sessions/a7188aba-1cb6-4b4f-a4c4-cf5fb6cc048a

Co-authored-by: mackowski <[email protected]>
Copilot AI changed the title Restore dedicated JWT Cheat Sheet; trim Authentication Cheat Sheet JWT section Rewrite JSON Web Token Cheat Sheet: language-agnostic, drop Java code Mar 26, 2026
@randomstuff
Copy link
Copy Markdown

FWIW is have a very WIP branch about JWT in here:

https://github.com/randomstuff/CheatSheetSeries/tree/jwt_cheatsheet

It was originally based on a branch by @chalbersma

@jmanico
Copy link
Copy Markdown
Member

jmanico commented Mar 26, 2026

Here is a copy of that WIP cheatsheet.

JWT Cheat Sheet

Introduction

JSON Web Token (JWT) is a standard format (RFC 7519)
for cryptographically secured tokens. It can be used for many a wide range of usages such as:

  • transporting information about the end-user identity and attributes in OpenID Connect (ID token);
  • representing authorizations for accessing a an API in an access token (eg. RFC 9068);
  • proving possesion of a private key (eg. RFC 9449);
  • authenticating a workload (eg. JWT-SVID).

JWT can provide authenticity (JWS) and/or confidentiality (JWE) to the token content:

  • An authenticated JWT (JWS) is protected against tampering (authenticity).
    It includes some proof of authenticity which can be used by the
    recipient to verify that it has not been tampered with
    and has not been forged altogether.
    In most applications, you want the token to be authenticated.
  • The content of an encrypted JWS (JWE) is protected such that only its recipient
    should be able to inspect its content (confidentiality).
    This is desirable if the token is passed to a third party
    which should not be able to inspect the token content.

In addition, the JWT specification allows the usage of unsecure JWTs ("alg":"none").
These JWTs do not provide ANY form of authenticity protection
and should usually not be used.
They are not discussed here.

JWT is a profile of the more general
JOSE format (RFC 7515, RFC 7516).
While this cheat sheet is focused on JWTs,
a large part of what is discussed here is more generally applicable to JOSE messages in general.
Conversely, CWT, and more generally COSE, have a very similar design
and many of the things discussed might be applicable to CWT and COSE as well.

Concepts

Actors

Issuer: the issuer of the JWT is the party which created the token.
The issuer is generally communicated in the issuer claim (iss):
this claim can be used by the audience to find the relevant keys to process the token
and apply the correct policy.

Audience: the audience of the JWT is the actor which is supposed to verify its authenticity,
decrypt it (if necessary) and validate its content. In order to prevent against audience confusion attacks,
where a JWT intended for one audience is sent by a malicious actor to an unintended audience,
the audience is generally communicated in the audience claim (aud)
and MUST be validated by the audience.

Presenter/Holder:
the presenter (resp. holder) of the token is the actor which presents the token to the audience the token (resp. holds the token).
In some cases, the presenter of the token is the issuer
but in many cases, the issuer gives the JWT to another presenter.
Depending on the application, this third-party may for example be identified by the authorized party (azp) of client identifier (client_id) claims.

TODO, add some examples?

Type of tokens

Bearer token: TODO

Proof-of-posession token: TODO

Authenticity (JWS)

An authenticated JWT (JWS) is protected against tampering (authenticity).
It includes some proof of authenticity which can be used by the
recipient to verify that it has not been tampered with
and has not been forged altogether.
This can be done either using:

  • a digital signature (public-key cryptography, using a public/private key pair);
  • a MAC (using a shared secret).

In most applications, you want the token to be authenticated
and the consumer of the token MUST vaidate the authenticity of the token.

Structure of a signed JWT

The following elements are present in signed JWTs:

  • Protected Header: the JWT header contains some information about the token such as the type of token (IANA media type)
    and the cryptographic algorithms used to protect the token.
  • Claims: the content JWT is a list of claims (usually about the subject). See the JWT IANA Registry for a list of standard claims.
  • Signature, a signature in JWT is either a public-key digital signature (using a public/private key pair) or a MAC (using a shared secret). The signatures protects both the protected headers and the claims.

An authenticated JWT has the following format:

{base64url(json(header))}.{base64url(json(claims))}.{base64ur(signature)}

The following example is taken from RFC 7519
(with line breaks added for presentation purpose):

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

The decoded protected header is:

{
  "typ": "JWT",
  "alg": "HS256"
}

The decoded claims are:

{
  "iss": "joe",
  "exp": 1300819380,
  "http://example.com/is_root": true
}

Signature vs. MAC

Recommendation: use a digital signature scheme when possible?

A JWE can be authenticated using either a digital signature or a MAC:

  • When using a digital signature, the issuer of the token uses a private key to generate a signature.
    The audience of the token can use the associated public key to verify the authenticity of the token.
    Whereas the private key must only be known by the issuer, the public key can be public.
  • When using a MAC, a shared secret is shared between the issuer and the audience.
    The same shared secret is used by the issuer to generate the token and by the audience
    to verify the authenticity of the token.
    The issuer MUST not use the same secret for different audiences
    and, more generally, the same secret MUST only be shared between these two participants.

Using a MAC may be interesting in the following cases:

  • The issuer of the token is the sole audience of the token.

Public-key signature

Benefits of using a digital signature:

  • The issuer can reuse the same public key for many different audiences.
  • The consumer (audience) of the token only need public information to validate the token authenticity
    which reduces the risk of secret leakage by the consumer.
  • Because the public key does not need to be secret, it can easily be distributed (eg. by publishing it at a public HTTPS URI).
  • This makes key rotation simpler as well.

Recommended signature algorithms in order of preference:

  1. EdDSA (Ed25519, Ed448);
  2. ECDSA (ES256, ES384, ES512);
  3. RSASSA-PSS (PS256, PS384, PS512).

The following algorithms are NOT recommended:

  • RSASSA-PKCS1-v1_5 (RS256, RS384, RS512).

TODO, ES256K?

Notes:

  • Support for EdDSA in JWT implementations may be currently somewhat limited.
  • Generating ECDSA signatures may be dangerous on embedded systems where the quality of the randomness may be problematic. In this case, you must only use ECDSA signature if you make sure than the signature implementation uses deterministic signatures as defined in RFC 6979.

TODO, Post-quantum signatures. ML-DSA (ML-DSA-44, ML-DSA-65, ML-DSA-87)? very large signature, probably not great justified at the moment for short-lived signatures. ML-DSA is designed to be resistant against quantum computers. However its support in JWT implementation is currently very limited. The size of if the signatures in ML-DSA is much larger than in ECDSA and EdDSA, resulting into very large JWTs.

MAC

The following MAC algorithms are recommended:

  • HMAC with SHA-2 (HS256, HS384, HS512)

Secret management:

  • Do not reuse the same secret for another purpose (eg. for encryption).
    • Using the same key for authenticating different types of JWTs or JOSE is fine as long as this does not introduce a risk of token type confusion.
  • Do not reuse the same secret with another audience.
  • Do not reuse the same secret with another issuer.
  • Do not use a password as MAC secret.
  • The secret must be generated using a local, cryptographically secure secret generator.
  • The secret must have at least the same size as the output (eg. 256, 384 and 512 bits respectively for HS256, HS384 and HS512).
  • Do not publish your secret key!

Valid HMAC secret generation example:

import secrets
secret_for_hs256 = secrets.token_bytes(256//8)

Invalid HMAC secret generation:

import random

# Using a password/passphrase is not OK.:
bad_secret1_for_hs256 = "MyProject2025!"

# Not a secure randomness source:
bad_secret2_for_hs256 = random.randbytes(256//8)

# Not enough entropy:
bad_secret3_for_hs256 = random.randbytes(128//8)

# Not enough entropy for HS512:
bad_secret_for_hs512 = random.randbytes(256//8)

Protected headers

TODO

Token Media Type

The typ header field may be used to indicate the media type of the token. The application/jwt type is a generic type for JWTs. However, specific applications of JWTs define more specific media types of the form application/*+jwt such as:

  • application/at+jwt for access tokens;
  • application/dpop+jwt for DPoP proofs (proof-of-possession of a private key);
  • etc.

It is recommended to use a specific media type for specific applications instead of using the generic application/jwt type. This makes it possible to

Using a specific media type in your tokens and validating this specific media type can be used to prevent cross-application JWT

Notes:

  • you can and should omit the application/ prefix in the typ header (eg. "typ:"at+jwt");
  • media types are case insensitive.

An an issuer,

  • you SHOULD include a specific token type in the generated tokens;
  • use a standard one if applicable (see the Media Types IANA registry);
  • use a private one otherwise (eg. application/myorganisation-myapplication+jwt) and document its usage.

As a consumer,

  • you SHOULD validate that the token type included in the JWT is the one expected in the current context if such a type has been defined;
  • in some cases, you may need to accept application/jwt for retrocompatibility with older issuers which did not include a specific toke type;
  • you SHOULD reject other unexpected token types.

Claims

See the JWT IANA Registry for a list of standard claims.
Some importants claims are discussed in this section.

Validity

TODO, iat and nbf

Audience

TODO, aud

A JWT can include more than one audience:

{"aud": ["audience1","audience2"]}

If these token represent unrelated entities, this might present unrelated (and possibly distrusting entitied). When receiving the JWT from its presente r"audience1" could forward the token to "audience2" and impersonate the subject and/or presented on "audience2". Even if the different audiences trust each other one audience could be compromised. If the JWT has multiple audiences representing different entities (as opposed to different endpoint of the same entity), the token should be a proof-of-possession token (not a bearer token).

TODO, audience ambiguity/etc. eg. when the audience is chosen by another party.

Issuer

TODO, iss

Presenter

TODO, client_id, azp

Metadata

TODO, jti and iat

Subject

TODO, sub

TODO, act, may_act

Authorizations

TODO, scope

Confidentiality (JWE)

Usually, you want a token which provides authenticity (JWS). In some cases, you might want to have confidentiality as well. This might be important if the claims contain some sensitive information (such as PII) that should not be exposed to the presenter (for example). This is achieved by using a Nested JWT: this is usually done by first signing the claims and then encrypting the resulting token.

You usualy don't want to have a JWT which provides confidentiality only: when using an encrypted JWT, you usually want to provide authenticity as well.

The correct handling of encryption introduces additional requirements such as:

  • lack of forward secrecy (in general);
  • susceptible to Harvest now, decrypt later (HNDL), especially when using non-post-quantum public key encryption.

For these reasons, these considerations are currently not addessed in this Cheat Sheet but will be addressed in a upcoming version.

Key publishing

TODO

Recognizing a public key from a private key in JWK format:

Key types kty Public key fields Private key fields
ML-DSA AKP alg, pub priv
EC (eg. ECDSA) EC crv, x, y
RSA RSA n, e d, p, q, dp, dq, qi
EdDSA, X25519, X448 OKP crv, x d

TODO, add missing alg

TODO, other algorithms

TODO, JSON Web Key Use use and JSON Web Key Operations key_ops

Attacks on JWT

For more details, see RFC 8725.

TODO, align with RFC 8725

Accepting Unsecured JWT

Some JWT libraries, used to accept unsecured JWTs by default ("alg":"none"). In this case, an attacker would be able forge his own JWTs: depending on the application, he might be able to impersonate arbitrary users, obtains arbitrary authorizations, etc.

This issue should now be fixed in JWT libraries.

Cross-JWT Confusion

TODO

Recommendations

For more details, see RFC 8725.

General

  • Do not log JWTs if theyr are intended to be secret. You can log specific claims however (if their are not considered sensible). The jti claim, associated with the iss claim, can be used to identify a specific token.

Key Management

TODO

Key generation:

  • Do not reuse the same key pair for another purpose (eg. for public-key encryption, for TLS authentication, for WebAuthn/Passkey, etc.). Using the same key for authenticating different types of JWTs or JOSE is fine as long as this does not introduce a risk of token type confusion or token audience confusion.
  • The issuer should generate its own private keys. Don't use a private key generated by another agent (such as the consumer): your private key would not be private; this would increase the number of actors having access to your private key.
  • If possible, store the private keys on dedicated hardware (such as a smart card, a TPM) or a dedicated service.

Key distribution:

  • The issuer can publish its public keys.
  • This is typically done using the JWKS format over HTTPS.
  • Make sure you do not publish the private keys by mistake! This is especialy important when publishing in JWK format as a private key in JWK format may be interpreted as a public key.

Issuer

  • Verify the issued token are not vulnerable to token type confusion.
  • Include a specific token type claim (typ) depending on intended usage of the token in order to protect against token type confusion.
  • TODO

Verifier

  • Rely on a trusted library for JWT verification.
  • Validate important claims
  • TODO

Alternatives to JWT and JOSE

Depending on the application, some alternatives to JWT and JOSE might be:

Critique of JWT and JOSE:

Further Reading

Main JWT and JOSE specifications:

IANA registries:

Attacks on JWT and JOSE:

Other useful links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants