{"id":13565369,"url":"https://github.com/jwtk/jjwt","last_synced_at":"2025-05-12T18:15:31.285Z","repository":{"id":20698571,"uuid":"23982180","full_name":"jwtk/jjwt","owner":"jwtk","description":"Java JWT: JSON Web Token for Java and Android","archived":false,"fork":false,"pushed_at":"2025-04-23T20:08:21.000Z","size":3142,"stargazers_count":10650,"open_issues_count":42,"forks_count":1355,"subscribers_count":278,"default_branch":"master","last_synced_at":"2025-05-12T18:15:18.579Z","etag":null,"topics":["hacktoberfest","jackson","java","java-jwt","jjwt","json","jwe","jwk","jwk-thumbprint","jwk-thumbprint-uri","jwkset","jws","jwt","jwt-auth","jwt-authentication","jwt-bearer-tokens","jwt-claims","jwt-server","jwt-token","jwt-tokens"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jwtk.png","metadata":{"files":{"readme":"README.adoc","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-09-13T01:06:24.000Z","updated_at":"2025-05-11T09:54:13.000Z","dependencies_parsed_at":"2023-10-04T03:54:20.073Z","dependency_job_id":"69e748a4-3567-4253-96f2-dbedae94ff76","html_url":"https://github.com/jwtk/jjwt","commit_stats":{"total_commits":491,"total_committers":68,"mean_commits":7.220588235294118,"dds":0.6924643584521385,"last_synced_commit":"2ad964a3f1d77ffa1a915640d94e9238216a52d6"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwtk%2Fjjwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwtk%2Fjjwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwtk%2Fjjwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwtk%2Fjjwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwtk","download_url":"https://codeload.github.com/jwtk/jjwt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253795161,"owners_count":21965487,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","jackson","java","java-jwt","jjwt","json","jwe","jwk","jwk-thumbprint","jwk-thumbprint-uri","jwkset","jws","jwt","jwt-auth","jwt-authentication","jwt-bearer-tokens","jwt-claims","jwt-server","jwt-token","jwt-tokens"],"created_at":"2024-08-01T13:01:45.534Z","updated_at":"2025-05-12T18:15:31.257Z","avatar_url":"https://github.com/jwtk.png","language":"Java","readme":":doctype: book\n= Java JWT: JSON Web Token for Java and Android\n:project-version: 0.12.6\n:toc:\n:toc-title:\n:toc-placement!:\n:toclevels: 4\n\nifdef::env-github[]\n:tip-caption: ✏️TIP\n:note-caption: ℹ️ NOTE\n:important-caption: ‼️IMPORTANT\n:caution-caption: ⛔️CAUTION\n:warning-caption: ⚠️WARNING\nendif::[]\n\n// Macros\n:fn-require-java8-plus: Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.\n:fn-require-java11-plus: Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.\n:fn-require-java15-plus: Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.\n\nimage:https://github.com/jwtk/jjwt/actions/workflows/ci.yml/badge.svg?branch=master[Build Status,link=https://github.com/jwtk/jjwt/actions/workflows/ci.yml?query=branch%3Amaster]\nimage:https://coveralls.io/repos/github/jwtk/jjwt/badge.svg?branch=master[Coverage Status,link=https://coveralls.io/github/jwtk/jjwt?branch=master]\nimage:https://snyk-widget.herokuapp.com/badge/mvn/io.jsonwebtoken/jjwt-root/badge.svg[Vuln score,link=https://snyk-widget.herokuapp.com/badge/mvn/io.jsonwebtoken/jjwt-root/badge.svg]\nimage:https://snyk.io/test/github/jwtk/jjwt/badge.svg[Known Vulns,link=https://snyk.io/test/github/jwtk/jjwt/badge.svg]\n\nJJWT aims to be the easiest to use and understand library for creating and verifying JSON Web Tokens (JWTs) and\nJSON Web Keys (JWKs) on the JVM and Android.\n\nJJWT is a pure Java implementation based exclusively on the\nhttps://datatracker.ietf.org/wg/jose/documents/[JOSE Working Group] RFC specifications:\n\n* https://tools.ietf.org/html/rfc7519[RFC 7519: JSON Web Token (JWT)]\n* https://tools.ietf.org/html/rfc7515[RFC 7515: JSON Web Signature (JWS)]\n* https://tools.ietf.org/html/rfc7516[RFC 7516: JSON Web Encryption (JWE)]\n* https://tools.ietf.org/html/rfc7517[RFC 7517: JSON Web Key (JWK)]\n* https://tools.ietf.org/html/rfc7518[RFC 7518: JSON Web Algorithms (JWA)]\n* https://www.rfc-editor.org/rfc/rfc7638.html[RFC 7638: JSON Web Key Thumbprint]\n* https://www.rfc-editor.org/rfc/rfc9278.html[RFC 9278: JSON Web Key Thumbprint URI]\n* https://www.rfc-editor.org/rfc/rfc7797.html[RFC 7797: JWS Unencoded Payload Option]\n* https://www.rfc-editor.org/rfc/rfc8037[RFC 8037: Edwards Curve algorithms and JWKs]\n\nIt was created by https://github.com/lhazlewood[Les Hazlewood]\nand is supported and maintained by a https://github.com/jwtk/jjwt/graphs/contributors[community] of contributors.\n\nJJWT is open source under the terms of the http://www.apache.org/licenses/LICENSE-2.0[Apache 2.0 License].\n\n====\n[discrete]\n== Table of Contents\n---\ntoc::[]\n====\n\n+++\u003ca name=\"features\"\u003e++++++\u003c/a\u003e+++\n\n== Features\n\n* Fully functional on all Java 7+ JDKs and Android\n* Automatic security best practices and assertions\n* Easy to learn and read API\n* Convenient and readable http://en.wikipedia.org/wiki/Fluent_interface[fluent] interfaces, great for IDE\nauto-completion to write code quickly\n* Fully RFC specification compliant on all implemented functionality, tested against RFC-specified test vectors\n* Stable implementation with almost 1,700 tests and enforced 100% test code coverage.  Every single method, statement\nand conditional branch variant in the entire codebase is tested and required to pass on every build.\n* Creating, parsing and verifying digitally signed compact JWTs (aka JWSs) with all standard JWS algorithms:\n+\n|===\n| Identifier | Signature Algorithm\n\n| `HS256`\n| HMAC using SHA-256\n\n| `HS384`\n| HMAC using SHA-384\n\n| `HS512`\n| HMAC using SHA-512\n\n| `ES256`\n| ECDSA using P-256 and SHA-256\n\n| `ES384`\n| ECDSA using P-384 and SHA-384\n\n| `ES512`\n| ECDSA using P-521 and SHA-512\n\n| `RS256`\n| RSASSA-PKCS-v1_5 using SHA-256\n\n| `RS384`\n| RSASSA-PKCS-v1_5 using SHA-384\n\n| `RS512`\n| RSASSA-PKCS-v1_5 using SHA-512\n\n| `PS256`\n| RSASSA-PSS using SHA-256 and MGF1 with SHA-256^*1*^\n\n| `PS384`\n| RSASSA-PSS using SHA-384 and MGF1 with SHA-384^*1*^\n\n| `PS512`\n| RSASSA-PSS using SHA-512 and MGF1 with SHA-512^*1*^\n\n| `EdDSA`\n| Edwards-curve Digital Signature Algorithm^*2*^\n|===\n+\n^*1.*{sp}{fn-require-java11-plus}^\n+\n^*2*.{sp}{fn-require-java15-plus}^\n\n* Creating, parsing and decrypting encrypted compact JWTs (aka JWEs) with all standard JWE encryption algorithms:\n+\n|===\n| Identifier | Encryption Algorithm\n\n| `A128CBC‑HS256`\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.3[AES_128_CBC_HMAC_SHA_256] authenticated encryption algorithm\n\n| `A192CBC-HS384`\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.4[AES_192_CBC_HMAC_SHA_384] authenticated encryption algorithm\n\n| `A256CBC-HS512`\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.5[AES_256_CBC_HMAC_SHA_512] authenticated encryption algorithm\n\n| `A128GCM`\n| AES GCM using 128-bit key^*1*^\n\n| `A192GCM`\n| AES GCM using 192-bit key^*1*^\n\n| `A256GCM`\n| AES GCM using 256-bit key^*1*^\n|===\n+\n^*1*.{sp}{fn-require-java8-plus}^\n\n* All Key Management Algorithms for obtaining JWE encryption and decryption keys:\n+\n|===\n| Identifier | Key Management Algorithm\n\n| `RSA1_5`\n| RSAES-PKCS1-v1_5\n\n| `RSA-OAEP`\n| RSAES OAEP using default parameters\n\n| `RSA-OAEP-256`\n| RSAES OAEP using SHA-256 and MGF1 with SHA-256\n\n| `A128KW`\n| AES Key Wrap with default initial value using 128-bit key\n\n| `A192KW`\n| AES Key Wrap with default initial value using 192-bit key\n\n| `A256KW`\n| AES Key Wrap with default initial value using 256-bit key\n\n| `dir`\n| Direct use of a shared symmetric key as the CEK\n\n| `ECDH-ES`\n| Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDF\n\n| `ECDH-ES+A128KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A128KW\"\n\n| `ECDH-ES+A192KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A192KW\"\n\n| `ECDH-ES+A256KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A256KW\"\n\n| `A128GCMKW`\n| Key wrapping with AES GCM using 128-bit key^*1*^\n\n| `A192GCMKW`\n| Key wrapping with AES GCM using 192-bit key^*1*^\n\n| `A256GCMKW`\n| Key wrapping with AES GCM using 256-bit key^*1*^\n\n| `PBES2-HS256+A128KW`\n| PBES2 with HMAC SHA-256 and \"A128KW\" wrapping^*1*^\n\n| `PBES2-HS384+A192KW`\n| PBES2 with HMAC SHA-384 and \"A192KW\" wrapping^*1*^\n\n| `PBES2‑HS512+A256KW`\n| PBES2 with HMAC SHA-512 and \"A256KW\" wrapping^*1*^\n|===\n+\n^*1*.{sp}{fn-require-java8-plus}^\n\n* Creating, parsing and verifying JSON Web Keys (JWKs) in all standard JWA key formats using native Java `Key` types:\n+\n|===\n| JWK Key Format | Java `Key` Type | JJWT `Jwk` Type\n\n| Symmetric Key\n| `SecretKey`\n| `SecretJwk`\n\n| Elliptic Curve Public Key\n| `ECPublicKey`\n| `EcPublicJwk`\n\n| Elliptic Curve Private Key\n| `ECPrivateKey`\n| `EcPrivateJwk`\n\n| RSA Public Key\n| `RSAPublicKey`\n| `RsaPublicJwk`\n\n| RSA Private Key\n| `RSAPrivateKey`\n| `RsaPrivateJwk`\n\n| XDH Private Key\n| `XECPublicKey`^*1*^\n| `OctetPublicJwk`\n\n| XDH Private Key\n| `XECPrivateKey`^*1*^\n| `OctetPrivateJwk`\n\n| EdDSA Public Key\n| `EdECPublicKey`^*2*^\n| `OctetPublicJwk`\n\n| EdDSA Private Key\n| `EdECPublicKey`^*2*^\n| `OctetPrivateJwk`\n|===\n+\n^*1*.{sp}{fn-require-java15-plus}^\n+\n^*2*.{sp}{fn-require-java15-plus}^\n\n* Convenience enhancements beyond the specification such as\n ** Payload compression for any large JWT, not just JWEs\n ** Claims assertions (requiring specific values)\n ** Claim POJO marshaling and unmarshalling when using a compatible JSON parser (e.g. Jackson)\n ** Secure Key generation based on desired JWA algorithms\n ** and more...\n\n+++\u003ca name=\"features-unsupported\"\u003e++++++\u003c/a\u003e+++\n\n=== Currently Unsupported Features\n\n* https://tools.ietf.org/html/rfc7515#section-7.2[Non-compact] serialization and parsing.\n\nThis feature may be implemented in a future release.  Community contributions are welcome!\n\n+++\u003ca name=\"community\"\u003e++++++\u003c/a\u003e+++\n\n== Community\n\n+++\u003ca name=\"help\"\u003e++++++\u003c/a\u003e+++\n\n=== Getting Help\n\nIf you have trouble using JJWT, please first read the documentation on this page before asking questions.  We try\nvery hard to ensure JJWT's documentation is robust, categorized with a table of contents, and up to date for each\nrelease.\n\n+++\u003ca name=\"help-questions\"\u003e++++++\u003c/a\u003e+++\n\n==== Questions\n\nIf the documentation or the API JavaDoc isn't sufficient, and you either have usability questions or are confused\nabout something, please https://github.com/jwtk/jjwt/discussions/new?category=q-a[ask your question here]. However:\n\n*Please do not create a GitHub issue to ask a question.*\n\nWe use GitHub Issues to track actionable work that requires changes to JJWT's design and/or codebase.  If you have a\nusability question, instead please\nhttps://github.com/jwtk/jjwt/discussions/new?category=q-a[ask your question here], and we can convert that to an\nissue if necessary.\n\n*If a GitHub Issue is created that does not represent actionable work for JJWT's codebase, it will be promptly\nclosed.*\n\n+++\u003ca name=\"help-issues\"\u003e++++++\u003c/a\u003e+++\n\n==== Bugs, Feature Requests, Ideas and General Discussions\n\nIf you do not have a usability question and believe you have a legitimate bug or feature request,\nplease https://github.com/jwtk/jjwt/discussions[discuss it here] *_FIRST_*. Please do a quick search first to\nsee if an existing discussion related to yours exist already and join that existing discussion if necesary.\n\nIf you feel like you'd like to help fix a bug or implement the new feature yourself, please read the Contributing\nsection next before starting any work.\n\n+++\u003ca name=\"contributing\"\u003e++++++\u003c/a\u003e+++\n\n=== Contributing\n\n+++\u003ca name=\"contributing-pull-requests\"\u003e++++++\u003c/a\u003e+++\n\n==== Pull Requests\n\nSimple Pull Requests that fix anything other than JJWT core code (documentation, JavaDoc, typos, test cases, etc) are\nalways appreciated and have a high likelihood of being merged quickly. Please send them!\n\nHowever, if you want or feel the need to change JJWT's functionality or core code, please do not issue a pull request\nwithout https://github.com/jwtk/jjwt/discussions[starting a new JJWT discussion] and discussing your desired\nchanges *first*, _before you start working on it_.\n\nIt would be a shame to reject your earnest and genuinely-appreciated pull request if it might not align with the\nproject's goals, design expectations or planned functionality.  We've sadly had to reject large PRs in the past because\nthey were out of sync with project or design expectations - all because the PR author didn't first check in with\nthe team first before working on a solution.\n\nSo, please https://github.com/jwtk/jjwt/discussions[create a new JJWT discussion] first to discuss, and then we\ncan see easily convert the discussion to an issue and then see if (or how) a PR is warranted.  Thank you!\n\n+++\u003ca name=\"contributing-help-wanted\"\u003e++++++\u003c/a\u003e+++\n\n==== Help Wanted\n\nIf you would like to help, but don't know where to start, please visit the\nhttps://github.com/jwtk/jjwt/labels/help%20wanted[Help Wanted Issues] page and pick any of the\nones there, and we'll be happy to discuss and answer questions in the issue comments.\n\nIf any of those don't appeal to you, no worries! Any help you would like to offer would be\nappreciated based on the above caveats concerning \u003c\u003ccontributing-pull-requests,contributing pull requests\u003e\u003e. Feel free\nto https://github.com/jwtk/jjwt/discussions[discuss or ask questions first] if you're not sure. :)\n\n+++\u003ca name=\"overview\"\u003e++++++\u003c/a\u003e+++\n\n== What is a JSON Web Token?\n\nJSON Web Token (JWT) is a _general-purpose_ text-based messaging format for transmitting information in a\ncompact and secure way.  Contrary to popular belief, JWT is not just useful for sending and receiving identity tokens\non the web - even if that is the most common use case.  JWTs can be used as messages for _any_ type of data.\n\nA JWT in its simplest form contains two parts:\n\n. The primary data within the JWT, called the `payload`, and\n. A JSON `Object` with name/value pairs that represent metadata about the `payload` and the\nmessage itself, called the `header`.\n\nA JWT `payload` can be absolutely anything at all - anything that can be represented as a byte array, such as Strings,\nimages, documents, etc.\n\nBut because a JWT `header` is a JSON `Object`, it would make sense that a JWT `payload` could also be a JSON\n`Object` as well. In many cases, developers like the `payload` to be JSON that\nrepresents data about a user or computer or similar identity concept. When used this way, the `payload` is called a\nJSON `Claims` object, and each name/value pair within that object is called a `claim` - each piece of information\nwithin 'claims' something about an identity.\n\nAnd while it is useful to 'claim' something about an identity, really anyone can do that. What's important is that you\n_trust_ the claims by verifying they come from a person or computer you trust.\n\nA nice feature of JWTs is that they can be secured in various ways. A JWT can be cryptographically signed (making it\nwhat we call a https://tools.ietf.org/html/rfc7515[JWS]) or encrypted (making it a\nhttps://tools.ietf.org/html/rfc7516[JWE]).  This adds a powerful layer of verifiability to the JWT - a\nJWS or JWE recipient can have a high degree of confidence it comes from someone they trust\nby verifying a signature or decrypting it. It is this feature of verifiability that makes JWT a good choice\nfor sending and receiving secure information, like identity claims.\n\nFinally, JSON with whitespace for human readability is nice, but it doesn't make for a very efficient message\nformat.  Therefore, JWTs can be _compacted_ (and even compressed) to a minimal representation - basically\nBase64URL-encoded strings - so they can be transmitted around the web more efficiently, such as in HTTP headers or URLs.\n\n+++\u003ca name=\"overview-example-jwt\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Example\n\nOnce you have a `payload` and `header`, how are they compacted for web transmission, and what does the final JWT\nactually look like? Let's walk through a simplified version of the process with some pseudocode:\n\n. Assume we have a JWT with a JSON `header` and a simple text message payload:\n+\n*header*\n+\n----\n{\n  \"alg\": \"none\"\n}\n----\n+\n*payload*\n+\n----\nThe true sign of intelligence is not knowledge but imagination.\n----\n\n. Remove all unnecessary whitespace in the JSON:\n+\n[,groovy]\n----\nString header = '{\"alg\":\"none\"}'\nString payload = 'The true sign of intelligence is not knowledge but imagination.'\n----\n\n. Get the UTF-8 bytes and Base64URL-encode each:\n+\n[,groovy]\n----\nString encodedHeader = base64URLEncode( header.getBytes(\"UTF-8\") )\nString encodedPayload = base64URLEncode( payload.getBytes(\"UTF-8\") )\n----\n\n. Join the encoded header and claims with period ('.') characters:\n+\n[,groovy]\n----\nString compact = encodedHeader + '.' + encodedPayload + '.'\n----\n\nThe final concatenated `compact` JWT String looks like this:\n\n----\neyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.\n----\n\nThis is called an 'unprotected' JWT because no security was involved - no digital signatures or encryption to\n'protect' the JWT to ensure it cannot be changed by 3rd parties.\n\nIf we wanted to digitally sign the compact form so that we could at least guarantee that no-one changes the data\nwithout us detecting it, we'd have to perform a few more steps, shown next.\n\n+++\u003ca name=\"overview-example-jws\"\u003e++++++\u003c/a\u003e+++\n\n=== JWS Example\n\nInstead of a plain text payload, the next example will use probably the most common type of payload - a JSON claims\n`Object` containing information about a particular identity.  We'll also digitally sign the JWT to ensure it\ncannot be changed by a 3rd party without us knowing.\n\n. Assume we have a JSON `header` and a claims `payload`:\n+\n*header*\n+\n[,json]\n----\n{\n  \"alg\": \"HS256\"\n}\n----\n+\n*payload*\n+\n[,json]\n----\n{\n  \"sub\": \"Joe\"\n}\n----\n+\nIn this case, the `header` indicates that the `HS256` (HMAC using SHA-256) algorithm will be used to cryptographically sign\nthe JWT. Also, the `payload` JSON object has a single claim, `sub` with value `Joe`.\n+\nThere are a number of standard claims, called https://tools.ietf.org/html/rfc7519#section-4.1[Registered Claims],\nin the specification and `sub` (for 'Subject') is one of them.\n\n. Remove all unnecessary whitespace in both JSON objects:\n+\n[,groovy]\n----\nString header = '{\"alg\":\"HS256\"}'\nString claims = '{\"sub\":\"Joe\"}'\n----\n\n. Get their UTF-8 bytes and Base64URL-encode each:\n+\n[,groovy]\n----\nString encodedHeader = base64URLEncode( header.getBytes(\"UTF-8\") )\nString encodedClaims = base64URLEncode( claims.getBytes(\"UTF-8\") )\n----\n\n. Concatenate the encoded header and claims with a period character '.' delimiter:\n+\n[,groovy]\n----\nString concatenated = encodedHeader + '.' + encodedClaims\n----\n\n. Use a sufficiently-strong cryptographic secret or private key, along with a signing algorithm of your choice\n (we'll use HMAC-SHA-256 here), and sign the concatenated string:\n+\n[,groovy]\n----\n SecretKey key = getMySecretKey()\n byte[] signature = hmacSha256( concatenated, key )\n----\n\n. Because signatures are always byte arrays, Base64URL-encode the signature and join it to the `concatenated` string\nwith a period character '.' delimiter:\n+\n[,groovy]\n----\nString compact = concatenated + '.' + base64URLEncode( signature )\n----\n\nAnd there you have it, the final `compact` String looks like this:\n\n----\neyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4\n----\n\nThis is called a 'JWS' - short for _signed_ JWT.\n\nOf course, no one would want to do this manually in code, and worse, if you get anything wrong, you could introduce\nserious security problems and weaknesses.  As a result, JJWT was created to handle all of this for you: JJWT completely\nautomates both the creation of JWSs and the parsing and verification of JWSs for you.\n\n+++\u003ca name=\"overview-example-jwe\"\u003e++++++\u003c/a\u003e+++\n\n=== JWE Example\n\nSo far we have seen an unprotected JWT and a cryptographically signed JWT (called a 'JWS').  One of the things\nthat is inherent to both of these two is that all the information within them can be seen by anyone - all the data in\nboth the header and the payload is publicly visible.  JWS just ensures the data hasn't been changed by anyone -\nit doesn't prevent anyone from seeing it.  Many times, this is just fine because the data within them is not\nsensitive information.\n\nBut what if you needed to represent information in a JWT that _is_ considered sensitive information - maybe someone's\npostal address or social security number or bank account number?\n\nIn these cases, we'd want a fully-encrypted JWT, called a 'JWE' for short.  A JWE uses cryptography to ensure that the\npayload remains fully encrypted _and_ authenticated so unauthorized parties cannot see data within, nor change the data\nwithout being detected.  Specifically, the JWE specification requires that\nhttps://en.wikipedia.org/wiki/Authenticated_encryption#Authenticated_encryption_with_associated_data_(AEAD)[Authenticated Encryption with Associated Data]\nalgorithms are used to fully encrypt and protect data.\n\nA full overview of AEAD algorithms are out of scope for this documentation, but here's an example of a final compact\nJWE that utilizes these algorithms (line breaks are for readability only):\n\n----\neyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.\n6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.\nAxY8DCtDaGlsbGljb3RoZQ.\nKDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.\nU0m_YmjN04DJvceFICbCVQ\n----\n\nNext we'll cover how to install JJWT in your project, and then we'll see how to use JJWT's nice fluent API instead\nof risky string manipulation to quickly and safely build JWTs, JWSs, and JWEs.\n\n+++\u003ca name=\"install\"\u003e++++++\u003c/a\u003e+++\n\n== Installation\n\nUse your favorite Maven-compatible build tool to pull the dependencies from Maven Central.\n\nThe dependencies could differ slightly if you are working with a \u003c\u003cinstall-jdk,JDK project\u003e\u003e or an\n\u003c\u003cinstall-android,Android project\u003e\u003e.\n\n+++\u003ca name=\"install-jdk\"\u003e++++++\u003c/a\u003e+++\n\n=== JDK Projects\n\nIf you're building a (non-Android) JDK project, you will want to define the following dependencies:\n\n+++\u003ca name=\"install-jdk-maven\"\u003e++++++\u003c/a\u003e+++\n\n==== Maven\n\n[,xml,subs=\"+attributes\"]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.jsonwebtoken\u003c/groupId\u003e\n    \u003cartifactId\u003ejjwt-api\u003c/artifactId\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.jsonwebtoken\u003c/groupId\u003e\n    \u003cartifactId\u003ejjwt-impl\u003c/artifactId\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n    \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.jsonwebtoken\u003c/groupId\u003e\n    \u003cartifactId\u003ejjwt-jackson\u003c/artifactId\u003e \u003c!-- or jjwt-gson if Gson is preferred --\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n    \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n\u003c!-- Uncomment this next dependency if you are using:\n     - JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.\n     - JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.\n     - JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.\n     It is unnecessary for these algorithms on JDK 15 or later.\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.bouncycastle\u003c/groupId\u003e\n    \u003cartifactId\u003ebcprov-jdk18on\u003c/artifactId\u003e or bcprov-jdk15to18 on JDK 7\n    \u003cversion\u003e1.76\u003c/version\u003e\n    \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n--\u003e\n----\n\n+++\u003ca name=\"install-jdk-gradle\"\u003e++++++\u003c/a\u003e+++\n\n==== Gradle\n\n[,groovy,subs=\"+attributes\"]\n----\ndependencies {\n    implementation 'io.jsonwebtoken:jjwt-api:{project-version}'\n    runtimeOnly 'io.jsonwebtoken:jjwt-impl:{project-version}'\n    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:{project-version}' // or 'io.jsonwebtoken:jjwt-gson:{project-version}' for gson\n    /*\n      Uncomment this next dependency if you are using:\n       - JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.\n       - JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.\n       - JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.\n      It is unnecessary for these algorithms on JDK 15 or later.\n    */\n    // runtimeOnly 'org.bouncycastle:bcprov-jdk18on:1.76' // or bcprov-jdk15to18 on JDK 7\n}\n----\n\n+++\u003ca name=\"install-android\"\u003e++++++\u003c/a\u003e+++\n\n=== Android Projects\n\nAndroid projects will want to define the following dependencies and Proguard exclusions, and optional\nBouncyCastle `Provider`:\n\n+++\u003ca name=\"install-android-dependencies\"\u003e++++++\u003c/a\u003e+++\n\n==== Dependencies\n\nAdd the dependencies to your project:\n\n[,groovy,subs=\"+attributes\"]\n----\ndependencies {\n    api('io.jsonwebtoken:jjwt-api:{project-version}')\n    runtimeOnly('io.jsonwebtoken:jjwt-impl:{project-version}')\n    runtimeOnly('io.jsonwebtoken:jjwt-orgjson:{project-version}') {\n        exclude(group: 'org.json', module: 'json') //provided by Android natively\n    }\n    /*\n      Uncomment this next dependency if you want to use:\n       - RSASSA-PSS (PS256, PS384, PS512) signature algorithms.\n       - EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.\n       - EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.\n      ** AND ALSO ensure you enable the BouncyCastle provider as shown below **\n    */\n    //implementation('org.bouncycastle:bcprov-jdk18on:1.76') // or bcprov-jdk15to18 for JDK 7\n}\n----\n\n+++\u003ca name=\"install-android-proguard\"\u003e++++++\u003c/a\u003e+++\n\n==== Proguard\n\nYou can use the following https://developer.android.com/studio/build/shrink-code[Android Proguard] exclusion rules:\n\n----\n-keepattributes InnerClasses\n\n-keep class io.jsonwebtoken.** { *; }\n-keepnames class io.jsonwebtoken.* { *; }\n-keepnames interface io.jsonwebtoken.* { *; }\n\n-keep class org.bouncycastle.** { *; }\n-keepnames class org.bouncycastle.** { *; }\n-dontwarn org.bouncycastle.**\n----\n\n+++\u003ca name=\"install-android-bc\"\u003e++++++\u003c/a\u003e+++\n\n==== Bouncy Castle\n\nIf you want to use JWT RSASSA-PSS algorithms (i.e. `PS256`, `PS384`, and `PS512`), EdECDH (`X25512` or `X448`)\nElliptic Curve Diffie-Hellman encryption, EdDSA (`Ed25519` or `Ed448`) signature algorithms, or you just want to\nensure your Android application is running an updated version of BouncyCastle, you will need to:\n\n. Uncomment the BouncyCastle dependency as commented above in the \u003c\u003cinstall-android-dependencies,dependencies\u003e\u003e section.\n. Replace the legacy Android custom `BC` provider with the updated one.\n\nProvider registration needs to be done _early_ in the application's lifecycle, preferably in your application's\nmain `Activity` class as a static initialization block.  For example:\n\n[,kotlin]\n----\nclass MainActivity : AppCompatActivity() {\n\n    companion object {\n        init {\n            Security.removeProvider(\"BC\") //remove old/legacy Android-provided BC provider\n            Security.addProvider(BouncyCastleProvider()) // add 'real'/correct BC provider\n        }\n    }\n\n    // ... etc ...\n}\n----\n\n+++\u003ca name=\"install-understandingdependencies\"\u003e++++++\u003c/a\u003e+++\n\n=== Understanding JJWT Dependencies\n\nNotice the above JJWT dependency declarations all have only one compile-time dependency and the rest are declared as\n_runtime_ dependencies.\n\nThis is because JJWT is designed so you only depend on the APIs that are explicitly designed for you to use in\nyour applications and all other internal implementation details - that can change without warning - are relegated to\nruntime-only dependencies.  This is an extremely important point if you want to ensure stable JJWT usage and\nupgrades over time:\n\n[WARNING]\n====\nJJWT guarantees semantic versioning compatibility for all of its artifacts _except_ the `jjwt-impl` .jar.  No such\nguarantee is made for the `jjwt-impl` .jar and internal changes in that .jar can happen at any time.  Never add the\n`jjwt-impl` .jar to your project with `compile` scope - always declare it with `runtime` scope.\n====\n\nThis is done to benefit you: great care goes into curating the `jjwt-api` .jar and ensuring it contains what you need\nand remains backwards compatible as much as is possible so you can depend on that safely with compile scope.  The\nruntime `jjwt-impl` .jar strategy affords the JJWT developers the flexibility to change the internal packages and\nimplementations whenever and however necessary.  This helps us implement features, fix bugs, and ship new releases to\nyou more quickly and efficiently.\n\n+++\u003ca name=\"quickstart\"\u003e++++++\u003c/a\u003e+++\n\n== Quickstart\n\nMost complexity is hidden behind a convenient and readable builder-based\nhttp://en.wikipedia.org/wiki/Fluent_interface[fluent interface], great for relying on IDE auto-completion to write\ncode quickly.  Here's an example:\n\n[,java]\n----\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.security.Keys;\nimport java.security.Key;\n\n// We need a signing key, so we'll create one just for this example. Usually\n// the key would be read from your application configuration instead.\nSecretKey key = Jwts.SIG.HS256.key().build();\n\nString jws = Jwts.builder().subject(\"Joe\").signWith(key).compact();\n----\n\nHow easy was that!?\n\nIn this case, we are:\n\n. _building_ a JWT that will have the\nhttps://tools.ietf.org/html/rfc7519#section-4.1[registered claim] `sub` (Subject) set to `Joe`. We are then\n. _signing_ the JWT using a key suitable for the HMAC-SHA-256 algorithm.  Finally, we are\n. _compacting_ it into its final `String` form.  A signed JWT is called a 'JWS'.\n\nThe resultant `jws` String looks like this:\n\n----\neyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4\n----\n\nNow let's verify the JWT (you should always discard JWTs that don't match an expected signature):\n\n[,java]\n----\nassert Jwts.parser().verifyWith(key).build().parseSignedClaims(jws).getPayload().getSubject().equals(\"Joe\");\n----\n\nThere are two things going on here. The `key` from before is being used to verify the signature of the JWT. If it\nfails to verify the JWT, a `SignatureException` (which extends `JwtException`) is thrown. Assuming the JWT is\nverified, we parse the claims and assert that that subject is set to `Joe`.  You have to love code one-liners\nthat pack a punch!\n\n[NOTE]\n====\n*Type-safe JWTs:* To get a type-safe `Claims` JWT result, call the `parseSignedClaims` method (since there are many\nsimilar methods available). You will get an `UnsupportedJwtException` if you parse your JWT with wrong method.\n====\n\nBut what if parsing or signature validation failed?  You can catch `JwtException` and react accordingly:\n\n[,java]\n----\ntry {\n\n    Jwts.parser().verifyWith(key).build().parseSignedClaims(compactJws);\n\n    //OK, we can trust this JWT\n\n} catch (JwtException e) {\n\n    //don't trust the JWT!\n}\n----\n\nNow that we've had a quickstart 'taste' of how to create and parse JWTs, let's cover JJWT's API in-depth.\n\n+++\u003ca name=\"jwt-create\"\u003e++++++\u003c/a\u003e+++\n\n== Creating a JWT\n\nYou create a JWT as follows:\n\n. Use the `Jwts.builder()` method to create a `JwtBuilder` instance.\n. Optionally set any \u003c\u003cjwt-header,`header` parameters\u003e\u003e as desired.\n. Call builder methods to set the payload \u003c\u003cjwt-content,content\u003e\u003e or \u003c\u003cjwt-claims,claims\u003e\u003e.\n. Optionally call `signWith` or `encryptWith` methods if you want to digitally sign or encrypt the JWT.\n. Call the `compact()` method to produce the resulting compact JWT string.\n\nFor example:\n\n[,java]\n----\nString jwt = Jwts.builder()                     // (1)\n\n    .header()                                   // (2) optional\n        .keyId(\"aKeyId\")\n        .and()\n\n    .subject(\"Bob\")                             // (3) JSON Claims, or\n    //.content(aByteArray, \"text/plain\")        //     any byte[] content, with media type\n\n    .signWith(signingKey)                       // (4) if signing, or\n    //.encryptWith(key, keyAlg, encryptionAlg)  //     if encrypting\n\n    .compact();                                 // (5)\n----\n\n* The JWT `payload` may be either `byte[]` content (via `content`) _or_ JSON Claims\n(such as `subject`, `claims`, etc), but not both.\n* Either digital signatures (`signWith`) or encryption (`encryptWith`) may be used, but not both.\n\n[WARNING]\n====\n*Unprotected JWTs*: If you do not use the `signWith` or `encryptWith` builder methods, *an Unprotected JWT will be\ncreated, which offers no security protection at all*.  If you need security protection, consider either\n\u003c\u003cjws,digitally signing\u003e\u003e or \u003c\u003cjwe,encrypting\u003e\u003e the JWT before calling the `compact()` builder method.\n====\n\n+++\u003ca name=\"jwt-header\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-header\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n=== JWT Header\n\nA JWT header is a JSON `Object` that provides metadata about the contents, format, and any cryptographic operations\nrelevant to the JWT `payload`.  JJWT provides a number of ways of setting the entire header and/or multiple individual\nheader parameters (name/value pairs).\n\n+++\u003ca name=\"jwt-header-builder\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-header-instance\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n==== JwtBuilder Header\n\nThe easiest and recommended way to set one or more JWT header parameters (name/value pairs) is to use the\n``JwtBuilder``'s `header()` builder as desired, and then call its `and()` method to return back\nto the `JwtBuilder` for further configuration. For example:\n\n[,java]\n----\nString jwt = Jwts.builder()\n\n    .header()                        // \u003c----\n        .keyId(\"aKeyId\")\n        .x509Url(aUri)\n        .add(\"someName\", anyValue)\n        .add(mapValues)\n        // ... etc ...\n        .and()                      // go back to the JwtBuilder\n\n    .subject(\"Joe\")                 // resume JwtBuilder calls...\n    // ... etc ...\n    .compact();\n----\n\nThe `JwtBuilder` `header()` builder also supports automatically calculating X.509 thumbprints and other builder-style benefits that\na simple property getter/setter object would not do.\n\n[NOTE]\n====\n*Automatic Headers*: You do not need to set the `alg`, `enc` or `zip` headers - JJWT will always set them\nautomatically as needed.\n====\n\n+++\u003ca name=\"jwt-header-params\"\u003e++++++\u003c/a\u003e+++\n\n===== Custom Header Parameters\n\nIn addition to type-safe builder methods for standard header parameters, `JwtBuilder.header()` can also support\narbitrary name/value pairs via the `add` method:\n\n[,java]\n----\nJwts.builder()\n\n    .header()\n        .add(\"aHeaderName\", aValue)\n        // ... etc ...\n        .and() // return to the JwtBuilder\n\n// ... etc ...\n----\n\n+++\u003ca name=\"jwt-header-map\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-header-map\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n===== Header Parameter Map\n\nThe `add` method is also overloaded to support multiple parameters in a `Map`:\n\n[,java]\n----\nJwts.builder()\n\n    .header()\n        .add(multipleHeaderParamsMap)\n        // ... etc ...\n        .and() // return to the JwtBuilder\n\n// ... etc ...\n----\n\n==== Jwts HeaderBuilder\n\nUsing `Jwts.builder().header()` shown above is the preferred way to modify a header when using the `JwtBuilder`.\n\nHowever, if you would like to create a 'standalone' `Header` outside of the context of using the `JwtBuilder`, you\ncan use `Jwts.header()` instead to return an independent `Header` builder.  For example:\n\n[,java]\n----\nHeader header = Jwts.header()\n\n        .keyId(\"aKeyId\")\n        .x509Url(aUri)\n        .add(\"someName\", anyValue)\n        .add(mapValues)\n        // ... etc ...\n\n        .build()  // \u003c---- not 'and()'\n----\n\nThere are only two differences between `Jwts.header()` and `Jwts.builder().header()`:\n\n. `Jwts.header()` builds a 'detached' `Header` that is not associated with any particular JWT, whereas\n`Jwts.builder().header()` always modifies the header of the immediate JWT being constructed by its parent\n`JwtBuilder`.\n. `Jwts.header()` has a `build()` method to produce an explicit `Header` instance and\n`Jwts.builder().header()` does not (it has an `and()` method instead) because its parent `JwtBuilder` will implicitly\ncreate the header instance when necessary.\n\nA standalone header might be useful if you want to aggregate common header parameters in a single 'template'\ninstance so you don't have to repeat them for each `JwtBuilder` usage.  Then this 'template' `Header` can be used to\npopulate `JwtBuilder` usages by just appending it to the `JwtBuilder` header, for example:\n\n[,java]\n----\n// perhaps somewhere in application configuration:\nHeader commonHeaders = Jwts.header()\n    .issuer(\"My Company\")\n    // ... etc ...\n    .build();\n\n// --------------------------------\n\n// somewhere else during actual Jwt construction:\nString jwt = Jwts.builder()\n\n    .header()\n        .add(commonHeaders)                   // \u003c----\n        .add(\"specificHeader\", specificValue) // jwt-specific headers...\n        .and()\n\n    .subject(\"whatever\")\n    // ... etc ...\n    .compact();\n----\n\n+++\u003ca name=\"jwt-payload\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Payload\n\nA JWT `payload` can be anything at all - anything that can be represented as a byte array, such as text, images,\ndocuments, and more.  But since a JWT `header` is always JSON, it makes sense that the `payload` could also be JSON,\nespecially for representing identity claims.\n\nAs a result, the `JwtBuilder` supports two distinct payload options:\n\n* `content` if you would like the payload to be arbitrary byte array content, or\n* `claims` (and supporting helper methods) if you would like the payload to be a JSON Claims `Object`.\n\nEither option may be used, but not both. Using both will cause `compact()` to throw an exception.\n\n+++\u003ca name=\"jwt-content\"\u003e++++++\u003c/a\u003e+++\n\n==== Arbitrary Content\n\nYou can set the JWT payload to be any arbitrary byte array content by using the `JwtBuilder` `content` method.\nFor example:\n\n[,java]\n----\nbyte[] content = \"Hello World\".getBytes(StandardCharsets.UTF_8);\n\nString jwt = Jwts.builder()\n\n    .content(content, \"text/plain\") // \u003c---\n\n    // ... etc ...\n\n    .build();\n----\n\nNotice this particular example of `content` uses the two-argument convenience variant:\n\n. The first argument is the actual byte content to set as the JWT payload\n. The second argument is a String identifier of an IANA Media Type.\n\nThe second argument will cause the `JwtBuilder` to automatically set the `cty` (Content Type) header according to the\nJWT specification's https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.10[recommended compact format].\n\nThis two-argument variant is typically recommended over the single-argument `content(byte[])` method because it\nguarantees the JWT recipient can inspect the `cty` header to determine how to convert the `payload` byte array into\na final form that the application can use.\n\nWithout setting the `cty` header, the JWT recipient _must_ know via out-of-band (external) information how to process\nthe byte array, which is usually less convenient and always requires code changes if the content format ever changes.\nFor these reasons, it is strongly recommended to use the two-argument `content` method variant.\n\n+++\u003ca name=\"jwt-claims\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-claims\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n==== JWT Claims\n\nInstead of a content byte array, a JWT payload may contain assertions or claims for a JWT recipient. In\nthis case, the payload is a `Claims` JSON `Object`, and JJWT supports claims creation with type-safe\nbuilder methods.\n\n+++\u003ca name=\"jwt-claims-standard\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-claims-standard\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n===== Standard Claims\n\nThe `JwtBuilder` provides convenient builder methods for standard registered Claim names defined in the JWT\nspecification.  They are:\n\n* `issuer`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.1[`iss` (Issuer) Claim]\n* `subject`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.2[`sub` (Subject) Claim]\n* `audience`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.3[`aud` (Audience) Claim]\n* `expiration`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.4[`exp` (Expiration Time) Claim]\n* `notBefore`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.5[`nbf` (Not Before) Claim]\n* `issuedAt`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.6[`iat` (Issued At) Claim]\n* `id`: sets the https://tools.ietf.org/html/rfc7519#section-4.1.7[`jti` (JWT ID) Claim]\n\nFor example:\n\n[,java]\n----\n\nString jws = Jwts.builder()\n\n    .issuer(\"me\")\n    .subject(\"Bob\")\n    .audience().add(\"you\").and()\n    .expiration(expiration) //a java.util.Date\n    .notBefore(notBefore) //a java.util.Date\n    .issuedAt(new Date()) // for example, now\n    .id(UUID.randomUUID().toString()) //just an example id\n\n    /// ... etc ...\n----\n\n+++\u003ca name=\"jwt-claims-custom\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-claims-custom\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n===== Custom Claims\n\nIf you need to set one or more custom claims that don't match the standard setter method claims shown above, you\ncan simply call the `JwtBuilder` `claim` method one or more times as needed:\n\n[,java]\n----\nString jws = Jwts.builder()\n\n    .claim(\"hello\", \"world\")\n\n    // ... etc ...\n----\n\nEach time `claim` is called, it simply appends the key-value pair to an internal `Claims` builder, potentially\noverwriting any existing identically-named key/value pair.\n\nObviously, you do not need to call `claim` for any \u003c\u003cjws-create-claims-standard,standard claim name\u003e\u003e, and it is\nrecommended instead to call the standard respective type-safe named builder method as this enhances readability.\n\n+++\u003ca name=\"jws-create-claims-instance\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n+++\u003ca name=\"jwt-claims-instance\"\u003e++++++\u003c/a\u003e+++\n+++\u003ca name=\"jwt-claims-map\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-claims-map\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n===== Claims Map\n\nIf you want to add multiple claims at once, you can use `JwtBuilder` `claims(Map)` method:\n\n[,java]\n----\n\nMap\u003cString,?\u003e claims = getMyClaimsMap(); //implement me\n\nString jws = Jwts.builder()\n\n    .claims(claims)\n\n    // ... etc ...\n----\n\n+++\u003ca name=\"jwt-compression\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-create-compression\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n=== JWT Compression\n\nIf your JWT payload is large (contains a lot of data), you might want to compress the JWT to reduce its size.  Note\nthat this is _not_ a standard feature for all JWTs - only JWEs - and is not likely to be supported by other JWT\nlibraries for non-JWE tokens.  JJWT supports compression for both JWSs and JWEs, however.\n\nPlease see the main \u003c\u003ccompression,Compression\u003e\u003e section to see how to compress and decompress JWTs.\n\n+++\u003ca name=\"jwt-read\"\u003e++++++\u003c/a\u003e+++\n\n== Reading a JWT\n\nYou read (parse) a JWT as follows:\n\n. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.\n. Optionally call `keyLocator`, `verifyWith` or `decryptWith` methods if you expect to parse \u003c\u003cjws,signed\u003e\u003e or \u003c\u003cjwe,encrypted\u003e\u003e JWTs.\n. Call the `build()` method on the `JwtParserBuilder` to create and return a thread-safe `JwtParser`.\n. Call one of the various `parse*` methods with your compact JWT string, depending on the type of JWT you expect.\n. Wrap the `parse*` call in a try/catch block in case parsing, signature verification, or decryption fails.\n\nFor example:\n\n[,java]\n----\nJwt\u003c?,?\u003e jwt;\n\ntry {\n    jwt = Jwts.parser()     // (1)\n\n    .keyLocator(keyLocator) // (2) dynamically locate signing or encryption keys\n    //.verifyWith(key)      //     or a constant key used to verify all signed JWTs\n    //.decryptWith(key)     //     or a constant key used to decrypt all encrypted JWTs\n\n    .build()                // (3)\n\n    .parse(compact);        // (4) or parseSignedClaims, parseEncryptedClaims, parseSignedContent, etc\n\n    // we can safely trust the JWT\n\ncatch (JwtException ex) {   // (5)\n\n    // we *cannot* use the JWT as intended by its creator\n}\n----\n\n[NOTE]\n====\n*Type-safe JWTs:* If you are certain your parser will only ever encounter a specific kind of JWT (for example, you only\never use signed JWTs with `Claims` payloads, or encrypted JWTs with `byte[]` content payloads, etc), you can call the\nassociated type-safe `parseSignedClaims`, `parseEncryptedClaims`, (etc) method variant instead of the generic `parse` method.\n\nThese `parse*` methods will return the type-safe JWT you are expecting, for example, a `Jws\u003cClaims\u003e` or `Jwe\u003cbyte[]\u003e`\ninstead of a generic `Jwt\u003c?,?\u003e` instance.\n====\n\n+++\u003ca name=\"jwt-read-key\"\u003e++++++\u003c/a\u003e+++\n\n=== Constant Parsing Key\n\nIf the JWT parsed is a JWS or JWE, a key will be necessary to verify the signature or decrypt it.  If a JWS and\nsignature verification fails, or if a JWE and decryption fails, the JWT cannot be safely trusted and should be\ndiscarded.\n\nSo which key do we use?\n\n* If parsing a JWS and the JWS was signed with a `SecretKey`, the same `SecretKey` should be specified on the\n`JwtParserBuilder`.  For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .verifyWith(secretKey) // \u003c----\n\n  .build()\n  .parseSignedClaims(jwsString);\n----\n\n* If parsing a JWS and the JWS was signed with a `PrivateKey`, that key's corresponding `PublicKey` (not the\n`PrivateKey`) should be specified on the `JwtParserBuilder`.  For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .verifyWith(publicKey) // \u003c---- publicKey, not privateKey\n\n  .build()\n  .parseSignedClaims(jwsString);\n----\n\n* If parsing a JWE and the JWE was encrypted with direct encryption using a `SecretKey`, the same `SecretKey` should be\nspecified on the `JwtParserBuilder`. For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .decryptWith(secretKey) // \u003c---- or a Password from Keys.password(charArray)\n\n  .build()\n  .parseEncryptedClaims(jweString);\n----\n\n* If parsing a JWE and the JWE was encrypted with a key algorithm using with a `PublicKey`, that key's corresponding\n`PrivateKey` (not the `PublicKey`) should be specified on the `JwtParserBuilder`.  For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .decryptWith(privateKey) // \u003c---- privateKey, not publicKey\n\n  .build()\n  .parseEncryptedClaims(jweString);\n----\n\n==== Multiple Keys?\n\nBut you might have noticed something - what if your application doesn't use just a single `SecretKey` or `KeyPair`? What\nif JWSs and JWEs can be created with different ``SecretKey``s or public/private keys, or a combination of both?  How do\nyou know which key to specify if you don't inspect the JWT first?\n\nIn these cases, you can't call the ``JwtParserBuilder``'s `verifyWith` or `decryptWith` methods with a single key -\ninstead, you'll need to configure a parsing Key Locator, discussed next.\n\n+++\u003ca name=\"key-locator\"\u003e++++++\u003c/a\u003e+++\n\n=== Dynamic Key Lookup\n\nIt is common in many applications to receive JWTs that can be encrypted or signed by different cryptographic keys.  For\nexample, maybe a JWT created to assert a specific user identity uses a Key specific to that exact user. Or perhaps JWTs\nspecific to a particular customer all use that customer's Key.  Or maybe your application creates JWTs that are\nencrypted with a key specific to your application for your own use (e.g. a user session token).\n\nIn all of these and similar scenarios, you won't know which key was used to sign or encrypt a JWT until the JWT is\nreceived, at parse time, so you can't 'hard code' any verification or decryption key using the ``JwtParserBuilder``'s\n`verifyWith` or `decryptWith` methods.  Those are only to be used when the same key is used to verify or decrypt\n_all_ JWSs or JWEs, which won't work for dynamically signed or encrypted JWTs.\n\n+++\u003ca name=\"key-locator-custom\"\u003e++++++\u003c/a\u003e+++\n\n==== Key Locator\n\nIf you need to support dynamic key lookup when encountering JWTs, you'll need to implement\nthe `Locator\u003cKey\u003e` interface and specify an instance on the `JwtParserBuilder` via the `keyLocator` method. For\nexample:\n\n[,java]\n----\nLocator\u003cKey\u003e keyLocator = getMyKeyLocator();\n\nJwts.parser()\n\n    .keyLocator(keyLocator) // \u003c----\n\n    .build()\n    // ... etc ...\n----\n\nA `Locator\u003cKey\u003e` is used to lookup _both_ JWS signature verification keys _and_ JWE decryption keys.  You need to\ndetermine which key to return based on information in the JWT `header`, for example:\n\n[,java]\n----\npublic class MyKeyLocator extends LocatorAdapter\u003cKey\u003e {\n\n    @Override\n    public Key locate(ProtectedHeader\u003c?\u003e header) { // a JwsHeader or JweHeader\n        // implement me\n    }\n}\n----\n\nThe `JwtParser` will invoke the `locate` method after parsing the JWT `header`, but _before parsing the `payload`,\nor verifying any JWS signature or decrypting any JWE ciphertext_. This allows you to inspect the `header` argument\nfor any information that can help you look up the `Key` to use for verifying _that specific jwt_.  This is very\npowerful for applications with more complex security models that might use different keys at different times or for\ndifferent users or customers.\n\n+++\u003ca name=\"key-locator-strategy\"\u003e++++++\u003c/a\u003e+++\n\n==== Key Locator Strategy\n\nWhat data might you inspect to determine how to lookup a signature verification or decryption key?\n\nThe JWT specifications' preferred approach is to set a `kid` (Key ID) header value when the JWT is being created,\nfor example:\n\n[,java]\n----\nKey key = getSigningKey(); // or getEncryptionKey() for JWE\n\nString keyId = getKeyId(key); //any mechanism you have to associate a key with an ID is fine\n\nString jws = Jwts.builder()\n\n    .header().keyId(keyId).and()               // \u003c--- add `kid` header\n\n    .signWith(key)                             // for JWS\n    //.encryptWith(key, keyAlg, encryptionAlg) // for JWE\n    .compact();\n----\n\nThen during parsing, your `Locator\u003cKey\u003e` implementation can inspect the `header` to get the `kid` value and then use it\nto look up the verification or decryption key from somewhere, like a database, keystore or Hardware Security Module\n(HSM).  For example:\n\n[,java]\n----\npublic class MyKeyLocator extends LocatorAdapter\u003cKey\u003e {\n\n    @Override\n    public Key locate(ProtectedHeader\u003c?\u003e header) { // both JwsHeader and JweHeader extend ProtectedHeader\n\n        //inspect the header, lookup and return the verification key\n        String keyId = header.getKeyId(); //or any other parameter that you need to inspect\n\n        Key key = lookupKey(keyId); //implement me\n\n        return key;\n    }\n}\n----\n\nNote that inspecting the `header.getKeyId()` is just the most common approach to look up a key - you could inspect any\nnumber of header parameters to determine how to lookup the verification or decryption key.  It is all based on how\nthe JWT was created.\n\nIf you extend `LocatorAdapter\u003cKey\u003e` as shown above, but for some reason have different lookup strategies for\nsignature verification keys versus decryption keys, you can forego overriding the `locate(ProtectedHeader\u003c?\u003e)` method\nin favor of two respective `locate(JwsHeader)` and `locate(JweHeader)` methods:\n\n[,java]\n----\npublic class MyKeyLocator extends LocatorAdapter\u003cKey\u003e {\n\n    @Override\n    public Key locate(JwsHeader header) {\n        String keyId = header.getKeyId(); //or any other parameter that you need to inspect\n        return lookupSignatureVerificationKey(keyId); //implement me\n    }\n\n    @Override\n    public Key locate(JweHeader header) {\n        String keyId = header.getKeyId(); //or any other parameter// that you need to inspect\n        return lookupDecryptionKey(keyId); //implement me\n    }\n}\n----\n\n[NOTE]\n====\n*Simpler Lookup*: If possible, try to keep the key lookup strategy the same between JWSs and JWEs (i.e. using\nonly `locate(ProtectedHeader\u003c?\u003e)`), preferably using only\nthe `kid` (Key ID) header value or perhaps a public key thumbprint.  You will find the implementation is much\nsimpler and easier to maintain over time, and also creates smaller headers for compact transmission.\n====\n\n+++\u003ca name=\"key-locator-retvals\"\u003e++++++\u003c/a\u003e+++\n\n==== Key Locator Return Values\n\nRegardless of which implementation strategy you choose, remember to return the appropriate type of key depending\non the type of JWS or JWE algorithm used.  That is:\n\n* For JWS:\n ** For HMAC-based signature algorithms, the returned verification key should be a `SecretKey`, and,\n ** For asymmetric signature algorithms, the returned verification key should be a `PublicKey` (not a `PrivateKey`).\n* For JWE:\n ** For JWE direct encryption, the returned decryption key should be a `SecretKey`.\n ** For password-based key derivation algorithms, the returned decryption key should be a\n`io.jsonwebtoken.security.Password`.  You can create a `Password` instance by calling\n`Keys.password(char[] passwordCharacters)`.\n ** For asymmetric key management algorithms, the returned decryption key should be a `PrivateKey` (not a `PublicKey`).\n\n+++\u003ca name=\"key-locator-provider\"\u003e++++++\u003c/a\u003e+++\n\n==== Provider-constrained Keys\n\nIf any verification or decryption key returned from a Key `Locator` must be used with a specific security `Provider`\n(such as for PKCS11 or Hardware Security Module (HSM) keys), you must make that `Provider` available for JWT parsing\nin one of 3 ways, listed in order of recommendation and simplicity:\n\n. https://docs.oracle.com/en/java/javase/17/security/howtoimplaprovider.html#GUID-831AA25F-F702-442D-A2E4-8DA6DEA16F33[Configure the Provider in the JVM],\neither by modifying the `java.security` file or by registering the `Provider` dynamically via\nhttps://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/security/Security.html#addProvider(java.security.Provider)[Security.addProvider(Provider)].\nThis is the recommended approach so you do not need to modify code anywhere that may need to parse JWTs.\n. Set the `Provider` as the parser default by calling `JwtParserBuilder#provider(Provider)`.  This will\nensure the provider is used by default with _all_ located keys unless overridden by a key-specific Provider. This\nis only recommended when you are confident that all JWTs encountered by the parser instance will use keys\nattributed to the same `Provider`, unless overridden by a specific key.\n. Associate the `Provider` with a specific key using `Keys.builder` so it is used for that key only.  This option is\nuseful if some located keys require a specific provider, while other located keys can assume a default provider. For\nexample:\n+\n[,java]\n----\npublic Key locate(Header\u003c?\u003e header) {\n\n    PrivateKey /* or SecretKey */ key = findKey(header); // implement me\n\n    Provider keySpecificProvider = findKeyProvider(key); // implement me\n    if (keySpecificProvider != null) {\n        // Ensure the key-specific provider (e.g. for PKCS11 or HSM) will be used\n        // during decryption with the KeyAlgorithm in the JWE 'alg' header\n        return Keys.builder(key).provider(keySpecificProvider).build();\n    }\n\n    // otherwise default provider is fine:\n    return key;\n}\n----\n\n+++\u003ca name=\"jwt-read-claims\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-read-claims\"\u003e++++++\u003c/a\u003e+++\n// legacy anchor for old links\n\n=== Claim Assertions\n\nYou can enforce that the JWT you are parsing conforms to expectations that you require and are important for your\napplication.\n\nFor example, let's say that you require that the JWT you are parsing has a specific `sub` (subject) value,\notherwise you may not trust the token.  You can do that by using one of the various `require`* methods on the\n`JwtParserBuilder`:\n\n[,java]\n----\ntry {\n    Jwts.parser().requireSubject(\"jsmith\")/* etc... */.build().parse(s);\n} catch (InvalidClaimException ice) {\n    // the sub claim was missing or did not have a 'jsmith' value\n}\n----\n\nIf it is important to react to a missing vs an incorrect value, instead of catching `InvalidClaimException`,\nyou can catch either `MissingClaimException` or `IncorrectClaimException`:\n\n[,java]\n----\ntry {\n    Jwts.parser().requireSubject(\"jsmith\")/* etc... */.build().parse(s);\n} catch(MissingClaimException mce) {\n    // the parsed JWT did not have the sub claim\n} catch(IncorrectClaimException ice) {\n    // the parsed JWT had a sub claim, but its value was not equal to 'jsmith'\n}\n----\n\nYou can also require custom claims by using the `require(claimName, requiredValue)` method - for example:\n\n[,java]\n----\ntry {\n    Jwts.parser().require(\"myClaim\", \"myRequiredValue\")/* etc... */.build().parse(s);\n} catch(InvalidClaimException ice) {\n    // the 'myClaim' claim was missing or did not have a 'myRequiredValue' value\n}\n----\n\n(or, again, you could catch either `MissingClaimException` or `IncorrectClaimException` instead).\n\nPlease see the `JwtParserBuilder` class and/or JavaDoc for a full list of the various `require`* methods you may use\nfor claims assertions.\n\n+++\u003ca name=\"jwt-read-clock\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-read-clock\"\u003e++++++\u003c/a\u003e+++\n// legacy anchor for old links\n\n=== Accounting for Clock Skew\n\nWhen parsing a JWT, you might find that `exp` or `nbf` claim assertions fail (throw exceptions) because the clock on\nthe parsing machine is not perfectly in sync with the clock on the machine that created the JWT.  This can cause\nobvious problems since `exp` and `nbf` are time-based assertions, and clock times need to be reliably in sync for shared\nassertions.\n\nYou can account for these differences (usually no more than a few minutes) when parsing using the ``JwtParserBuilder``'s\n`clockSkewSeconds`. For example:\n\n[,java]\n----\nlong seconds = 3 * 60; //3 minutes\n\nJwts.parser()\n\n    .clockSkewSeconds(seconds) // \u003c----\n\n    // ... etc ...\n    .build()\n    .parse(jwt);\n----\n\nThis ensures that minor clock differences between the machines can be ignored. Two or three minutes should be more than\nenough; it would be fairly strange if a production machine's clock was more than 5 minutes difference from most\natomic clocks around the world.\n\n+++\u003ca name=\"jwt-read-clock-custom\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-read-clock-custom\"\u003e++++++\u003c/a\u003e+++\n// legacy anchor for old links\n\n==== Custom Clock Support\n\nIf the above `clockSkewSeconds` isn't sufficient for your needs, the timestamps created\nduring parsing for timestamp comparisons can be obtained via a custom time source.  Call the ``JwtParserBuilder``'s\n`clock` method with an implementation of the `io.jsonwebtoken.Clock` interface.  For example:\n\n[,java]\n----\nClock clock = new MyClock();\n\nJwts.parser().clock(myClock) //... etc ...\n----\n\nThe ``JwtParser``'s default `Clock` implementation simply returns `new Date()` to reflect the time when parsing occurs,\nas most would expect.  However, supplying your own clock could be useful, especially when writing test cases to\nguarantee deterministic behavior.\n\n+++\u003ca name=\"jwt-read-decompression\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Decompression\n\nIf you used JJWT to compress a JWT and you used a custom compression algorithm, you will need to tell the\n`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT.\n\nPlease see the \u003c\u003ccompression,Compression\u003e\u003e section below to see how to decompress JWTs during parsing.\n\n+++\u003ca name=\"jws\"\u003e++++++\u003c/a\u003e+++\n\n== Signed JWTs\n\nThe JWT specification provides for the ability to\nhttps://en.wikipedia.org/wiki/Digital_signature[cryptographically _sign_] a JWT.  Signing a JWT:\n\n. guarantees the JWT was created by someone we know (it is authentic) as well as\n. guarantees that no-one has manipulated or changed the JWT after it was created (its integrity is maintained).\n\nThese two properties - authenticity and integrity - assure us that a JWT contains information we can trust.  If a\nJWT fails authenticity or integrity checks, we should always reject that JWT because we can't trust it.\n\nBut before we dig in to showing you how to create a JWS using JJWT, let's briefly discuss Signature Algorithms and\nKeys, specifically as they relate to the JWT specifications.  Understanding them is critical to being able to create a\nJWS properly.\n\n+++\u003ca name=\"jws-alg\"\u003e++++++\u003c/a\u003e+++\n\n=== Standard Signature Algorithms\n\nThe JWT specifications identify 13 standard signature algorithms - 3 secret key algorithms and 10 asymmetric\nkey algorithms:\n\n|===\n| Identifier | Signature Algorithm\n\n| `HS256`\n| HMAC using SHA-256\n\n| `HS384`\n| HMAC using SHA-384\n\n| `HS512`\n| HMAC using SHA-512\n\n| `ES256`\n| ECDSA using P-256 and SHA-256\n\n| `ES384`\n| ECDSA using P-384 and SHA-384\n\n| `ES512`\n| ECDSA using P-521 and SHA-512\n\n| `RS256`\n| RSASSA-PKCS-v1_5 using SHA-256\n\n| `RS384`\n| RSASSA-PKCS-v1_5 using SHA-384\n\n| `RS512`\n| RSASSA-PKCS-v1_5 using SHA-512\n\n| `PS256`\n| RSASSA-PSS using SHA-256 and MGF1 with SHA-256^*1*^\n\n| `PS384`\n| RSASSA-PSS using SHA-384 and MGF1 with SHA-384^*1*^\n\n| `PS512`\n| RSASSA-PSS using SHA-512 and MGF1 with SHA-512^*1*^\n\n| `EdDSA`\n| Edwards-Curve Digital Signature Algorithm (EdDSA)^*2*^\n|===\n\n^*1*.{sp}{fn-require-java15-plus}^\n\n^*2*.{sp}{fn-require-java15-plus}^\n\nThese are all represented as constants in the `io.jsonwebtoken.Jwts.SIG` registry class.\n\n+++\u003ca name=\"jws-key\"\u003e++++++\u003c/a\u003e+++\n\n=== Signature Algorithms Keys\n\nWhat's really important about the above standard signature algorithms - other than their security properties - is that\nthe JWT specification https://tools.ietf.org/html/rfc7518#section-3[RFC 7518, Sections 3.2 through 3.5]\n_requires_ (mandates) that you MUST use keys that are sufficiently strong for a chosen algorithm.\n\nThis means that JJWT - a specification-compliant library - will also enforce that you use sufficiently strong keys\nfor the algorithms you choose.  If you provide a weak key for a given algorithm, JJWT will reject it and throw an\nexception.\n\nThis is not because we want to make your life difficult, we promise! The reason why the JWT specification, and\nconsequently JJWT, mandates key lengths is that the security model of a particular algorithm can completely break\ndown if you don't adhere to the mandatory key properties of the algorithm, effectively having no security at all.  No\none wants completely insecure JWTs, right?  Right!\n\nSo what are the key strength requirements?\n\n+++\u003ca name=\"jws-key-hmacsha\"\u003e++++++\u003c/a\u003e+++\n\n==== HMAC-SHA\n\nJWT HMAC-SHA signature algorithms `HS256`, `HS384`, and `HS512` require a secret key that is _at least_ as many bits as\nthe algorithm's signature (digest) length per https://tools.ietf.org/html/rfc7518#section-3.2[RFC 7512 Section 3.2].\nThis means:\n\n* `HS256` is HMAC-SHA-256, and that produces digests that are 256 bits (32 bytes) long, so `HS256` _requires_ that you\nuse a secret key that is at least 32 bytes long.\n* `HS384` is HMAC-SHA-384, and that produces digests that are 384 bits (48 bytes) long, so `HS384` _requires_ that you\nuse a secret key that is at least 48 bytes long.\n* `HS512` is HMAC-SHA-512, and that produces digests that are 512 bits (64 bytes) long, so `HS512` _requires_ that you\nuse a secret key that is at least 64 bytes long.\n\n+++\u003ca name=\"jws-key-rsa\"\u003e++++++\u003c/a\u003e+++\n\n==== RSA\n\nJWT RSA signature algorithms `RS256`, `RS384`, `RS512`, `PS256`, `PS384` and `PS512` all require a minimum key length\n(aka an RSA modulus bit length) of `2048` bits per RFC 7512 Sections\nhttps://tools.ietf.org/html/rfc7518#section-3.3[3.3] and https://tools.ietf.org/html/rfc7518#section-3.5[3.5].\nAnything smaller than this (such as 1024 bits) will be rejected with an `WeakKeyException`.\n\nThat said, in keeping with best practices and increasing key lengths for security longevity, JJWT\nrecommends that you use:\n\n* at least 2048 bit keys with `RS256` and `PS256`\n* at least 3072 bit keys with `RS384` and `PS384`\n* at least 4096 bit keys with `RS512` and `PS512`\n\nThese are only JJWT suggestions and not requirements. JJWT only enforces JWT specification requirements and\nfor any RSA key, the requirement is the RSA key (modulus) length in bits MUST be \u003e= 2048 bits.\n\n+++\u003ca name=\"jws-key-ecdsa\"\u003e++++++\u003c/a\u003e+++\n\n==== Elliptic Curve\n\nJWT Elliptic Curve signature algorithms `ES256`, `ES384`, and `ES512` all require a key length\n(aka an Elliptic Curve order bit length) equal to the algorithm signature's individual\n`R` and `S` components per https://tools.ietf.org/html/rfc7518#section-3.4[RFC 7512 Section 3.4].  This means:\n\n* `ES256` requires that you use a private key that is exactly 256 bits (32 bytes) long.\n* `ES384` requires that you use a private key that is exactly 384 bits (48 bytes) long.\n* `ES512` requires that you use a private key that is exactly 521 bits (65 or 66 bytes) long (depending on format).\n\n+++\u003ca name=\"jws-key-eddsa\"\u003e++++++\u003c/a\u003e+++\n\n==== Edwards Curve\n\nThe JWT Edwards Curve signature algorithm `EdDSA` supports two sizes of private and public ``EdECKey``s (these types\nwere introduced in Java 15):\n\n* `Ed25519` algorithm keys must be 256 bits (32 bytes) long and produce signatures 512 bits (64 bytes) long.\n* `Ed448` algorithm keys must be 456 bits (57 bytes) long and produce signatures 912 bits (114 bytes) long.\n\n+++\u003ca name=\"jws-key-create\"\u003e++++++\u003c/a\u003e+++\n\n==== Creating Safe Keys\n\nIf you don't want to think about bit length requirements or just want to make your life easier, JJWT has\nprovided convenient builder classes that can generate sufficiently secure keys for any given\nJWT signature algorithm you might want to use.\n\n+++\u003ca name=\"jws-key-create-secret\"\u003e++++++\u003c/a\u003e+++\n\n===== Secret Keys\n\nIf you want to generate a sufficiently strong `SecretKey` for use with the JWT HMAC-SHA algorithms, use the respective\nalgorithm's `key()` builder method:\n\n[,java]\n----\nSecretKey key = Jwts.SIG.HS256.key().build(); //or HS384.key() or HS512.key()\n----\n\nUnder the hood, JJWT uses the JCA default provider's `KeyGenerator` to create a secure-random key with the correct\nminimum length for the given algorithm.\n\nIf you want to specify a specific JCA `Provider` or `SecureRandom` to use during key generation, you may specify those\nas builder arguments. For example:\n\n[,java]\n----\nSecretKey key = Jwts.SIG.HS256.key().provider(aProvider).random(aSecureRandom).build();\n----\n\nIf you need to save this new `SecretKey`, you can Base64 (or Base64URL) encode it:\n\n[,java]\n----\nString secretString = Encoders.BASE64.encode(key.getEncoded());\n----\n\nEnsure you save the resulting `secretString` somewhere safe -\n\u003c\u003cbase64-not-encryption,Base64-encoding is not encryption\u003e\u003e, so it's still considered sensitive information. You can\nfurther encrypt it, etc, before saving to disk (for example).\n\n+++\u003ca name=\"jws-key-create-asym\"\u003e++++++\u003c/a\u003e+++\n\n===== Asymmetric Keys\n\nIf you want to generate sufficiently strong Elliptic Curve or RSA asymmetric key pairs for use with JWT ECDSA or RSA\nalgorithms, use an algorithm's respective `keyPair()` builder method:\n\n[,java]\n----\nKeyPair keyPair = Jwts.SIG.RS256.keyPair().build(); //or RS384, RS512, PS256, etc...\n----\n\nOnce you've generated a `KeyPair`, you can use the private key (`keyPair.getPrivate()`) to create a JWS and the\npublic key (`keyPair.getPublic()`) to parse/verify a JWS.\n\n[NOTE]\n====\n* *The `PS256`, `PS384`, and `PS512` algorithms require JDK 11 or a compatible JCA Provider\n(like BouncyCastle) in the runtime classpath.*\n* *The `EdDSA` algorithms requires JDK 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.*\n\nIf you want to use either set of algorithms, and you are on an earlier JDK that does not support them,\nsee the \u003c\u003cInstallation,Installation\u003e\u003e section to see how to enable BouncyCastle.  All other algorithms are\nnatively supported by the JDK.\n====\n\n+++\u003ca name=\"jws-create\"\u003e++++++\u003c/a\u003e+++\n\n=== Creating a JWS\n\nYou create a JWS as follows:\n\n. Use the `Jwts.builder()` method to create a `JwtBuilder` instance.\n. Call `JwtBuilder` methods to set the `payload` content or claims and any header parameters as desired.\n. Specify the `SecretKey` or asymmetric `PrivateKey` you want to use to sign the JWT.\n. Finally, call the `compact()` method to compact and sign, producing the final jws.\n\nFor example:\n\n[,java]\n----\nString jws = Jwts.builder() // (1)\n\n    .subject(\"Bob\")         // (2)\n\n    .signWith(key)          // (3) \u003c---\n\n    .compact();             // (4)\n----\n\n+++\u003ca name=\"jws-create-key\"\u003e++++++\u003c/a\u003e+++\n\n==== Signing Key\n\nIt is usually recommended to specify the signing key by calling the ``JwtBuilder``'s `signWith` method and let JJWT\ndetermine the most secure algorithm allowed for the specified key.:\n\n[,java]\n----\nString jws = Jwts.builder()\n\n   // ... etc ...\n\n   .signWith(key) // \u003c---\n\n   .compact();\n----\n\nFor example, if you call `signWith` with a `SecretKey` that is 256 bits (32 bytes) long, it is not strong enough for\n`HS384` or `HS512`, so JJWT will automatically sign the JWT using `HS256`.\n\nWhen using `signWith` JJWT will also automatically set the required `alg` header with the associated algorithm\nidentifier.\n\nSimilarly, if you called `signWith` with an RSA `PrivateKey` that was 4096 bits long, JJWT will use the `RS512`\nalgorithm and automatically set the `alg` header to `RS512`.\n\nThe same selection logic applies for Elliptic Curve ``PrivateKey``s.\n\n[NOTE]\n====\n*You cannot sign JWTs with ``PublicKey``s as this is always insecure.* JJWT will reject any specified\n`PublicKey` for signing with an `InvalidKeyException`.\n====\n\n+++\u003ca name=\"jws-create-key-secret\"\u003e++++++\u003c/a\u003e+++\n\n===== SecretKey Formats\n\nIf you want to sign a JWS using HMAC-SHA algorithms, and you have a secret key `String` or\nhttps://docs.oracle.com/javase/8/docs/api/java/security/Key.html#getEncoded--[encoded byte array], you will need\nto convert it into a `SecretKey` instance to use as the `signWith` method argument.\n\nIf your secret key is:\n\n* An https://docs.oracle.com/javase/8/docs/api/java/security/Key.html#getEncoded--[encoded byte array]:\n+\n[,java]\n----\nSecretKey key = Keys.hmacShaKeyFor(encodedKeyBytes);\n----\n\n* A Base64-encoded string:\n+\n[,java]\n----\nSecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));\n----\n\n* A Base64URL-encoded string:\n+\n[,java]\n----\nSecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString));\n----\n\n* A raw (non-encoded) string (e.g. a password String):\n+\n[,java]\n----\nPassword key = Keys.password(secretString.toCharArray());\n----\n\n[WARNING]\n====\nIt is almost always incorrect to call any variant of `secretString.getBytes` in any cryptographic context. +\nSafe cryptographic keys are never represented as direct (unencoded) strings.  If you have a password that should\nbe represented as a `Key` for `HMAC-SHA` algorithms, it is _strongly_ recommended to use a key derivation\nalgorithm to derive a cryptographically-strong `Key` from the password, and never use the password directly.\n====\n\n+++\u003ca name=\"jws-create-key-algoverride\"\u003e++++++\u003c/a\u003e+++\n\n===== SignatureAlgorithm Override\n\nIn some specific cases, you might want to override JJWT's default selected signature algorithm for a given key.\n\nFor example, if you have an RSA `PrivateKey` that is 2048 bits, JJWT would automatically choose the `RS256` algorithm.\nIf you wanted to use `RS384` or `RS512` instead, you could manually specify it with the overloaded `signWith` method\nthat accepts the `SignatureAlgorithm` as an additional argument:\n\n[,java]\n----\n\n   .signWith(privateKey, Jwts.SIG.RS512) // \u003c---\n\n   .compact();\n----\n\nThis is allowed because the JWT specification allows any RSA algorithm strength for any RSA key \u003e= 2048 bits.  JJWT just\nprefers `RS512` for keys \u003e= 4096 bits, followed by `RS384` for keys \u003e= 3072 bits and finally `RS256` for keys \u003e= 2048\nbits.\n\n*In all cases however, regardless of your chosen algorithms, JJWT will assert that the specified key is allowed to be\nused for that algorithm when possible according to the JWT specification requirements.*\n\n+++\u003ca name=\"jws-create-compression\"\u003e++++++\u003c/a\u003e+++\n\n==== JWS Compression\n\nIf your JWT payload is large (contains a lot of data), and you are certain that JJWT will also be the same library\nthat reads/parses your JWS, you might want to compress the JWS to reduce its size.\n\n[WARNING]\n====\n*Not Standard for JWS*: JJWT supports compression for JWS, but it is not a standard feature for JWS.  The\nJWT RFC specifications standardize this _only_ for JWEs, and it is not likely to be supported by other JWT libraries\nfor JWS.  Use JWS compression only if you are certain that JJWT (or another library that supports JWS compression)\nwill be parsing the JWS.\n====\n\nPlease see the main \u003c\u003ccompression,Compression\u003e\u003e section to see how to compress and decompress JWTs.\n\n+++\u003ca name=\"jws-read\"\u003e++++++\u003c/a\u003e+++\n\n=== Reading a JWS\n\nYou read (parse) a JWS as follows:\n\n. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.\n. Call either \u003c\u003ckey-locator,keyLocator\u003e\u003e or `verifyWith` methods to determine the key used to verify the JWS signature.\n. Call the `build()` method on the `JwtParserBuilder` to return a thread-safe `JwtParser`.\n. Finally, call the `parseSignedClaims(String)` method with your jws `String`, producing the original JWS.\n. The entire call is wrapped in a try/catch block in case parsing or signature validation fails.  We'll cover\nexceptions and causes for failure later.\n\nFor example:\n\n[,java]\n----\nJws\u003cClaims\u003e jws;\n\ntry {\n    jws = Jwts.parser()            // (1)\n\n    .keyLocator(keyLocator)        // (2) dynamically lookup verification keys based on each JWS\n    //.verifyWith(key)             //     or a static key used to verify all encountered JWSs\n\n    .build()                       // (3)\n    .parseSignedClaims(jwsString); // (4) or parseSignedContent(jwsString)\n\n    // we can safely trust the JWT\n\ncatch (JwtException ex) {          // (5)\n\n    // we *cannot* use the JWT as intended by its creator\n}\n----\n\n[NOTE]\n====\n.Type-safe JWSs\n\n* If you are expecting a JWS with a Claims `payload`, call the ``JwtParser``'s `parseSignedClaims` method.\n* If you are expecting a JWS with a content `payload`, call the ``JwtParser``'s `parseSignedContent` method.\n====\n\n+++\u003ca name=\"jws-read-key\"\u003e++++++\u003c/a\u003e+++\n\n==== Verification Key\n\nThe most important thing to do when reading a JWS is to specify the key used to verify the JWS's\ncryptographic signature.  If signature verification fails, the JWT cannot be safely trusted and should be\ndiscarded.\n\nSo which key do we use for verification?\n\n* If the jws was signed with a `SecretKey`, the same `SecretKey` should be specified on the `JwtParserBuilder`. +\nFor example:\n+\n[,java]\n----\nJwts.parser()\n\n  .verifyWith(secretKey) // \u003c----\n\n  .build()\n  .parseSignedClaims(jwsString);\n----\n\n* If the jws was signed with a `PrivateKey`, that key's corresponding `PublicKey` (not the `PrivateKey`) should be\nspecified on the `JwtParserBuilder`.  For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .verifyWith(publicKey) // \u003c---- publicKey, not privateKey\n\n  .build()\n  .parseSignedClaims(jwsString);\n----\n\n+++\u003ca name=\"jws-read-key-locator\"\u003e++++++\u003c/a\u003e++++++\u003ca name=\"jws-read-key-resolver\"\u003e++++++\u003c/a\u003e+++\n// legacy anchors for old links\n\n==== Verification Key Locator\n\nBut you might have noticed something - what if your application doesn't use just a single `SecretKey` or `KeyPair`? What\nif JWSs can be created with different ``SecretKey``s or public/private keys, or a combination of both?  How do you\nknow which key to specify if you can't inspect the JWT first?\n\nIn these cases, you can't call the ``JwtParserBuilder``'s `verifyWith` method with a single key - instead, you'll need a\nKey Locator.  Please see the \u003c\u003ckey-locator,Key Lookup\u003e\u003e section to see how to dynamically obtain different keys when\nparsing JWSs or JWEs.\n\n+++\u003ca name=\"jws-read-decompression\"\u003e++++++\u003c/a\u003e+++\n\n==== JWS Decompression\n\nIf you used JJWT to compress a JWS and you used a custom compression algorithm, you will need to tell the\n`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT.\n\nPlease see the \u003c\u003ccompression,Compression\u003e\u003e section below to see how to decompress JWTs during parsing.\n\n+++\u003ca name=\"jws-unencoded\"\u003e++++++\u003c/a\u003e+++\n\n=== Unencoded Payload Option\n\nIn some cases, especially if a JWS payload is large, it could be desirable to _not_ Base64URL-encode the JWS payload,\nor even exclude the payload from the compact JWS string entirely.  The JWT RFC specifications provide support\nfor these use cases via the\nhttps://www.rfc-editor.org/rfc/rfc7797.html[JSON Web Signature (JWS) Unencoded Payload Option] specification,\nwhich JJWT supports.\n\nThis option comes with both benefits and disadvantages:\n\n==== Benefits\n\nA JWS producer can still create a JWS string to use for payload integrity verification without having to either:\n\n. Base64URL-encode the (potentially very large) payload, saving the time that could take.\n. Include the payload in the compact JWS string at all. Omitting the payload from the JWS compact string\nentirely produces smaller JWSs that can be more efficient to transfer.\n\n==== Disadvantages\n\n. Your application, and not JJWT, incurs the responsibility to ensure the payload is not modified during transmission\nso the recipient can verify the JWS signature. For example, by using a sufficiently strong TLS (https) cipher\nsuite as well as any additional care before and after transmission, since\nhttps://tozny.com/blog/end-to-end-encryption-vs-https/[TLS does not guarantee end-to-end security].\n. If you choose to include the unencoded payload in the JWS compact string, your application\nhttps://www.rfc-editor.org/rfc/rfc7797.html#section-5.2[MUST] ensure that the payload does not contain a\nperiod (`.`) character anywhere in the payload.  The JWS recipient will experience parsing errors otherwise.\n\nBefore attempting to use this option, one should be aware of the RFC's\nhttps://www.rfc-editor.org/rfc/rfc7797.html#section-8[security considerations] first.\n\n[NOTE]\n====\n.Protected JWS Only\n\nThe RFC specification defines the Unencoded Payload option for use only with JWSs. It may not be used with\nwith unprotected JWTs or encrypted JWEs.\n====\n\n+++\u003ca name=\"jws-unencoded-detached\"\u003e++++++\u003c/a\u003e+++\n\n==== Detached Payload Example\n\nThis example shows creating and parsing a compact JWS using an unencoded payload that is detached, i.e. where the\npayload is not embedded in the compact JWS string at all.\n\nWe need to do three things during creation:\n\n. Specify the JWS signing key; it's a JWS and still needs to be signed.\n. Specify the raw payload bytes via the ``JwtBuilder``'s `content` method.\n. Indicate that the payload should _not_ be Base64Url-encoded using the ``JwtBuilder``'s `encodePayload(false)` method.\n\n[,java]\n----\n// create a test key for this example:\nSecretKey testKey = Jwts.SIG.HS512.key().build();\n\nString message = \"Hello World. It's a Beautiful Day!\";\nbyte[] content = message.getBytes(StandardCharsets.UTF_8);\n\nString jws = Jwts.builder().signWith(testKey) // #1\n        .content(content)                     // #2\n        .encodePayload(false)                 // #3\n        .compact();\n----\n\nTo parse the resulting `jws` string, we need to do two things when creating the `JwtParser`:\n\n. Specify the signature verification key.\n. Specify the externally-transmitted unencoded payload bytes, required for signature verification.\n\n[,java]\n----\nJws\u003cbyte[]\u003e parsed = Jwts.parser().verifyWith(testKey) // 1\n        .build()\n        .parseSignedContent(jws, content);             // 2\n\nassertArrayEquals(content, parsed.getPayload());\n----\n\n+++\u003ca name=\"jws-unencoded-nondetached\"\u003e++++++\u003c/a\u003e+++\n\n==== Non-Detached Payload Example\n\nThis example shows creating and parsing a compact JWS with what the RFC calls a 'non-detached' unencoded payload, i.e.\na raw string directly embedded as the payload in the compact JWS string.\n\nWe need to do three things during creation:\n\n. Specify the JWS signing key; it's a JWS and still needs to be signed.\n. Specify the raw payload string via the ``JwtBuilder``'s `content` method.  Per\nhttps://www.rfc-editor.org/rfc/rfc7797.html#section-5.2[the RFC], the payload string *_MUST NOT contain any\nperiod (`.`) characters_*.\n. Indicate that the payload should _not_ be Base64Url-encoded using the ``JwtBuilder``'s `encodePayload(false)` method.\n\n[,java]\n----\n// create a test key for this example:\nSecretKey testKey = Jwts.SIG.HS512.key().build();\n\nString claimsString = \"{\\\"sub\\\":\\\"joe\\\",\\\"iss\\\":\\\"me\\\"}\";\n\nString jws = Jwts.builder().signWith(testKey) // #1\n        .content(claimsString)                // #2\n        .encodePayload(false)                 // #3\n        .compact();\n----\n\nIf you were to print the `jws` string, you'd see something like this:\n\n----\neyJhbGciOiJIUzUxMiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19.{\"sub\":\"joe\",\"iss\":\"me\"}.wkoxYEd//...etc...\n----\n\nSee how the `claimsString` is embedded directly as the center `payload` token instead of a standard Base64URL value?\nThis is why no period (`.`) characters can exist in the payload.  If they did, any standard JWT parser would see more\nthan two periods total, which is required for parsing standard JWSs.\n\nTo parse the resulting `jws` string, we need to do two things when creating the `JwtParser`:\n\n. Specify the signature verification key.\n. Indicate that we want to support Unencoded Payload Option JWSs by enabling the `b64` `crit` header parameter.\n\n[,java]\n----\nJws\u003cClaims\u003e parsed = Jwts.parser().verifyWith(testKey) // 1\n        .critical().add(\"b64\").and()                   // 2\n        .build()\n        .parseSignedClaims(jws);\n\nassert \"joe\".equals(parsed.getPayload().getSubject());\nassert \"me\".equals(parsed.getPayload().getIssuer());\n----\n\nDid you notice we used the `.parseSignedClaims(String)` method instead of `.parseSignedClaims(String, byte[])`? This is\nbecause the non-detached payload is already present and JJWT has what it needs for signature verification.\n\nAdditionally, we needed to specify the `b64` critical value:  because we're not using the two-argument\n`parseSignedClaims(jws, content)` method, the parser has no way of knowing if you wish to allow or support unencoded\npayloads. Unencoded payloads have additional security considerations as described above, so they are disabled by\nthe parser by default unless you indicate you want to support them by using `critical().add(\"b64\")`.\n\nFinally, even if the payload contains a non-detached String, you could still use the two-argument method using the\npayload String's UTF-8 bytes instead:\n\n[,java]\n----\nparsed = Jwts.parser().verifyWith(testKey)\n        .build()\n        .parseSignedClaims(jws, claimsString.getBytes(StandardCharsets.UTF_8)); // \u003c---\n----\n\n+++\u003ca name=\"jwe\"\u003e++++++\u003c/a\u003e+++\n\n== Encrypted JWTs\n\nThe JWT specification also provides for the ability to encrypt and decrypt a JWT.  Encrypting a JWT:\n\n. guarantees that no-one other than the intended JWT recipient can see the JWT `payload` (it is confidential), and\n. guarantees that no-one has manipulated or changed the JWT after it was created (its integrity is maintained).\n\nThese two properties - confidentiality and integrity - assure us that an encrypted JWT contains a `payload` that\nno-one else can see, _nor_ has anyone changed or altered the data in transit.\n\nEncryption and confidentiality seem somewhat obvious: if you encrypt a message, it is confidential by the notion that\nrandom 3rd parties cannot make sense of the encrypted message. But some might be surprised to know that *_general\nencryption does _not_ guarantee that someone hasn't tampered/altered an encrypted message in transit_*.  Most of us\nassume that if a message can be decrypted, then the message would be authentic and unchanged - after all, if you can\ndecrypt it, it must not have been tampered with, right? Because if it was changed, decryption would surely fail, right?\n\nUnfortunately, this is not actually guaranteed in all cryptographic ciphers. There are certain attack vectors where\nit is possible to change an encrypted payload (called 'ciphertext'), and the message recipient is still able to\nsuccessfully decrypt the (modified) payload.  In these cases, the ciphertext integrity was not maintained - a\nmalicious 3rd party could intercept a message and change the payload content, even if they don't understand what is\ninside the payload, and the message recipient could never know.\n\nTo combat this, there is a category of encryption algorithms that ensures                                                                                 both confidentiality _and_ integrity of the\nciphertext data.  These types of algorithms are called\nhttps://en.wikipedia.org/wiki/Authenticated_encryption[Authenticated Encryption] algorithms.\n\nAs a result, to ensure JWTs do not suffer from this problem, the JWE RFC specifications require that any encryption\nalgorithm used to encrypt a JWT _MUST_ be an Authenticated Encryption algorithm.  JWT users can be sufficiently\nconfident their encrypted JWTs maintain the properties of both confidentiality and integrity.\n\n+++\u003ca name=\"jwe-enc\"\u003e++++++\u003c/a\u003e+++\n\n=== JWE Encryption Algorithms\n\nThe JWT specification defines 6 standard Authenticated Encryption algorithms used to encrypt a JWT `payload`:\n\n|===\n| Identifier | Required Key Bit Length | Encryption Algorithm\n\n| `A128CBC‑HS256`\n| 256\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.3[AES_128_CBC_HMAC_SHA_256] authenticated encryption algorithm\n\n| `A192CBC-HS384`\n| 384\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.4[AES_192_CBC_HMAC_SHA_384] authenticated encryption algorithm\n\n| `A256CBC-HS512`\n| 512\n| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.5[AES_256_CBC_HMAC_SHA_512] authenticated encryption algorithm\n\n| `A128GCM`\n| 128\n| AES GCM using 128-bit key^*1*^\n\n| `A192GCM`\n| 192\n| AES GCM using 192-bit key^*1*^\n\n| `A256GCM`\n| 256\n| AES GCM using 256-bit key^*1*^\n|===\n\n^*1*.{sp}{fn-require-java8-plus}^\n\nThese are all represented as constants in the `io.jsonwebtoken.Jwts.ENC` registry singleton as\nimplementations of the `io.jsonwebtoken.security.AeadAlgorithm` interface.\n\nAs shown in the table above, each algorithm requires a key of sufficient length.  The JWT specification\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.3[RFC 7518, Sections 5.2.3 through 5.3]\n_requires_ (mandates) that you MUST use keys that are sufficiently strong for a chosen algorithm.  This means that\nJJWT - a specification-compliant library - will also enforce that you use sufficiently strong keys\nfor the algorithms you choose.  If you provide a weak key for a given algorithm, JJWT will reject it and throw an\nexception.\n\nThe reason why the JWT specification, and consequently JJWT, mandates key lengths is that the security model of a\nparticular algorithm can completely break down if you don't adhere to the mandatory key properties of the algorithm,\neffectively having no security at all.\n\n+++\u003ca name=\"jwe-enc-symmetric\"\u003e++++++\u003c/a\u003e+++\n\n==== Symmetric Ciphers\n\nYou might have noticed something about the above Authenticated Encryption algorithms: they're all variants of the\nAES algorithm, and AES always uses a symmetric (secret) key to perform encryption and decryption.  That's kind of\nstrange, isn't it?\n\nWhat about RSA and Elliptic Curve asymmetric key cryptography? And Diffie-Hellman key exchange?  What about\npassword-based key derivation algorithms? Surely any of those could be desirable depending on the use case, no?\n\nYes, they definitely can, and the JWT specifications do support them, albeit indirectly:  those other\nalgorithms _are_ indeed supported and used, but they aren't used to encrypt the JWT `payload` directly.  They are\nused to _produce_ the actual key used to encrypt the `JWT` payload.\n\nThis is all done via the JWT specification's concept of a Key Management Algorithm, covered next.  After we cover that,\nwe'll show you how to encrypt and parse your own JWTs with the `JwtBuilder` and `JwtParserBuilder`.\n\n+++\u003ca name=\"jwe-alg\"\u003e++++++\u003c/a\u003e+++\n\n=== JWE Key Management Algorithms\n\nAs stated above, all standard JWA Encryption Algorithms are AES-based authenticated encryption algorithms.  So what\nabout RSA and Elliptic Curve cryptography? And password-based key derivation, or Diffie-Hellman exchange?\n\nAll of those are supported as well, but they are not used directly for encryption. They are used to _produce_ the\nkey that will be used to directly encrypt the JWT `payload`.\n\nThat is, JWT encryption can be thought of as a two-step process, shown in the following pseudocode:\n\n[,groovy]\n----\nKey algorithmKey = getKeyManagementAlgorithmKey(); // PublicKey, SecretKey, or Password\n\nSecretKey contentEncryptionKey = keyManagementAlgorithm.produceEncryptionKey(algorithmKey); // 1\n\nbyte[] ciphertext = encryptionAlgorithm.encrypt(payload, contentEncryptionKey);             // 2\n----\n\nSteps:\n\n. Use the `algorithmKey` to produce the actual key that will be used to encrypt the payload.  The JWT specifications\ncall this result the 'Content Encryption Key'.\n. Take the resulting Content Encryption Key and use it directly with the Authenticated Encryption algorithm to\nactually encrypt the JWT `payload`.\n\nSo why the indirection?  Why not just use any `PublicKey`, `SecretKey` or `Password` to encrypt the `payload`\n_directly_ ?\n\nThere are quite a few reasons for this.\n\n. Asymmetric key encryption (like RSA and Elliptic Curve) tends to be slow.  Like _really_ slow.  Symmetric key\ncipher algorithms in contrast are _really fast_.  This matters a lot in production applications that could be\nhandling a JWT on every HTTP request, which could be thousands per second.\n. RSA encryption (for example) can only encrypt a relatively small amount of data. A 2048-bit RSA key can only\nencrypt up to a maximum of 245 bytes.  A 4096-bit RSA key can only encrypt up to a maximum of 501 bytes.  There are\nplenty of JWTs that can exceed 245 bytes, and that would make RSA unusable.\n. Passwords usually make for very poor encryption keys - they often have poor entropy, or they themselves are\noften too short to be used directly with algorithms that mandate minimum key lengths to help ensure safety.\n\nFor these reasons and more, using one secure algorithm to generate or encrypt a key used for another (very fast) secure\nalgorithm has been proven to be a great way to increase security through many more secure algorithms while\nalso still resulting in very fast and secure output.  This is after all how TLS (for https encryption) works -\ntwo parties can use more complex cryptography (like RSA or Elliptic Curve) to negotiate a small, fast encryption key.\nThis fast encryption key is produced during the 'TLS handshake' and is called the TLS 'session key'.\n\nSo the JWT specifications work much in the same way: one key from any number of various algorithm types can be used\nto produce a final symmetric key, and that symmetric key is used to encrypt the JWT `payload`.\n\n+++\u003ca name=\"jwe-alg-standard\"\u003e++++++\u003c/a\u003e+++\n\n==== JWE Standard Key Management Algorithms\n\nThe JWT specification defines 17 standard Key Management Algorithms used to produce the JWE\nContent Encryption Key (CEK):\n\n|===\n| Identifier | Key Management Algorithm\n\n| `RSA1_5`\n| RSAES-PKCS1-v1_5\n\n| `RSA-OAEP`\n| RSAES OAEP using default parameters\n\n| `RSA-OAEP-256`\n| RSAES OAEP using SHA-256 and MGF1 with SHA-256\n\n| `A128KW`\n| AES Key Wrap with default initial value using 128-bit key\n\n| `A192KW`\n| AES Key Wrap with default initial value using 192-bit key\n\n| `A256KW`\n| AES Key Wrap with default initial value using 256-bit key\n\n| `dir`\n| Direct use of a shared symmetric key as the Content Encryption Key\n\n| `ECDH-ES`\n| Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using Concat KDF\n\n| `ECDH-ES+A128KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A128KW\"\n\n| `ECDH-ES+A192KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A192KW\"\n\n| `ECDH-ES+A256KW`\n| ECDH-ES using Concat KDF and CEK wrapped with \"A256KW\"\n\n| `A128GCMKW`\n| Key wrapping with AES GCM using 128-bit key^*1*^\n\n| `A192GCMKW`\n| Key wrapping with AES GCM using 192-bit key^*1*^\n\n| `A256GCMKW`\n| Key wrapping with AES GCM using 256-bit key^*1*^\n\n| `PBES2-HS256+A128KW`\n| PBES2 with HMAC SHA-256 and \"A128KW\" wrapping^*1*^\n\n| `PBES2-HS384+A192KW`\n| PBES2 with HMAC SHA-384 and \"A192KW\" wrapping^*1*^\n\n| `PBES2‑HS512+A256KW`\n| PBES2 with HMAC SHA-512 and \"A256KW\" wrapping^*1*^\n|===\n\n^*1*.{sp}{fn-require-java8-plus}^\n\nThese are all represented as constants in the `io.jsonwebtoken.Jwts.KEY` registry singleton as\nimplementations of the `io.jsonwebtoken.security.KeyAlgorithm` interface.\n\nBut 17 algorithms are a lot to choose from.  When would you use them?  The sections below describe when you might\nchoose each category of algorithms and how they behave.\n\n+++\u003ca name=\"jwe-alg-rsa\"\u003e++++++\u003c/a\u003e+++\n\n===== RSA Key Encryption\n\nThe JWT RSA key management algorithms `RSA1_5`, `RSA-OAEP`, and `RSA-OAEP-256` are used when you want to use the\nJWE recipient's RSA _public_ key during encryption.  This ensures that only the JWE recipient can decrypt\nand read the JWE (using their RSA `private` key).\n\nDuring JWE creation, these algorithms:\n\n* Generate a new secure-random Content Encryption Key (CEK) suitable for the desired \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e.\n* Encrypt the JWE payload with the desired encryption algorithm using the new CEK, producing the JWE payload ciphertext.\n* Encrypt the CEK itself with the specified RSA key wrap algorithm using the JWE recipient's RSA public key.\n* Embed the payload ciphertext and encrypted CEK in the resulting JWE.\n\nDuring JWE decryption, these algorithms:\n\n* Retrieve the encrypted Content Encryption Key (CEK) embedded in the JWE.\n* Decrypt the encrypted CEK with the discovered RSA key unwrap algorithm using the JWE recipient's RSA private key,\nproducing the decrypted Content Encryption Key (CEK).\n* Decrypt the JWE ciphertext payload with the JWE's identified \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e using the decrypted CEK.\n\n[WARNING]\n====\nRFC 7518 Sections https://www.rfc-editor.org/rfc/rfc7518.html#section-4.2[4.2] and\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.3[4.3] _require_ (mandate) that RSA keys \u003e= 2048 bits\nMUST be used with these algorithms. JJWT will throw an exception if it detects weaker keys being used.\n====\n\n+++\u003ca name=\"jwe-alg-aes\"\u003e++++++\u003c/a\u003e+++\n\n===== AES Key Encryption\n\nThe JWT AES key management algorithms `A128KW`, `A192KW`, `A256KW`, `A128GCMKW`, `A192GCMKW`, and `A256GCMKW` are\nused when you have a symmetric secret key, but you don't want to use that secret key to directly\nencrypt/decrypt the JWT.\n\nInstead, a new secure-random key is generated each time a JWE is created, and that new/random key is used to directly\nencrypt/decrypt the JWT payload.  The secure-random key is itself encrypted with your symmetric secret key\nusing the AES Wrap algorithm, and the encrypted key is embedded in the resulting JWE.\n\nThis allows the JWE to be encrypted with a random short-lived key, reducing material exposure of the potentially\nlonger-lived symmetric secret key.\n\nBecause these particular algorithms use a symmetric secret key, they are best suited when the JWE creator and\nreceiver are the same, ensuring the secret key does not need to be shared with multiple parties.\n\nDuring JWE creation, these algorithms:\n\n* Generate a new secure-random Content Encryption Key (CEK) suitable for the desired \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e.\n* Encrypt the JWE payload with the desired encryption algorithm using the new CEK, producing the JWE payload ciphertext.\n* Encrypt the CEK itself with the specified AES key algorithm (either AES Key Wrap or AES with GCM encryption),\nproducing the encrypted CEK.\n* Embed the payload ciphertext and encrypted CEK in the resulting JWE.\n\nDuring JWE decryption, these algorithms:\n\n* Retrieve the encrypted Content Encryption Key (CEK) embedded in the JWE.\n* Decrypt the encrypted CEK with the discovered AES key algorithm using the symmetric secret key.\n* Decrypt the JWE ciphertext payload with the JWE's identified \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e using the decrypted CEK.\n\n[WARNING]\n====\nThe symmetric key used for the AES key algorithms MUST be 128, 192 or 256 bits as required by the specific AES\nkey algorithm.  JJWT will throw an exception if it detects weaker keys than what is required.\n====\n\n+++\u003ca name=\"jwe-alg-dir\"\u003e++++++\u003c/a\u003e+++\n\n===== Direct Key Encryption\n\nThe JWT `dir` (direct) key management algorithm is used when you have a symmetric secret key, and you want to use it\nto directly encrypt the JWT payload.\n\nBecause this algorithm uses a symmetric secret key, it is best suited when the JWE creator and receiver are the\nsame, ensuring the secret key does not need to be shared with multiple parties.\n\nThis is the simplest key algorithm for direct encryption that does not perform any key encryption.  It is essentially\na 'no op' key algorithm, allowing the shared key to be used to directly encrypt the JWT payload.\n\nDuring JWE creation, this algorithm:\n\n* Encrypts the JWE payload with the desired encryption algorithm directly using the symmetric secret key,\nproducing the JWE payload ciphertext.\n* Embeds the payload ciphertext in the resulting JWE.\n\nNote that because this algorithm does not produce an encrypted key value, an encrypted CEK is _not_ embedded in the\nresulting JWE.\n\nDuring JWE decryption, this algorithm decrypts the JWE ciphertext payload with the JWE's\nidentified \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e directly using the symmetric secret key.  No encrypted CEK is used.\n\n[WARNING]\n====\nThe symmetric secret key MUST be 128, 192 or 256 bits as required by the associated\n\u003c\u003cjwe-enc,AEAD encryption algorithm\u003e\u003e used to encrypt the payload. JJWT will throw an exception if it detects\nweaker keys than what is required.\n====\n\n+++\u003ca name=\"jwe-alg-pbes2\"\u003e++++++\u003c/a\u003e+++\n\n===== Password-Based Key Encryption\n\nThe JWT password-based key encryption algorithms `PBES2-HS256+A128KW`, `PBES2-HS384+A192KW`, and `PBES2-HS512+A256KW`\nare used when you want to use a password (character array) to encrypt and decrypt a JWT.\n\nHowever, because passwords are usually too weak or problematic to use directly in cryptographic contexts, these\nalgorithms utilize key derivation techniques with work factors (e.g. computation iterations) and secure-random salts\nto produce stronger cryptographic keys suitable for cryptographic operations.\n\nThis allows the payload to be encrypted with a random short-lived cryptographically-stronger key, reducing the need to\nexpose the longer-lived (and potentially weaker) password.\n\nBecause these algorithms use a secret password, they are best suited when the JWE creator and receiver are the\nsame, ensuring the secret password does not need to be shared with multiple parties.\n\nDuring JWE creation, these algorithms:\n\n* Generate a new secure-random Content Encryption Key (CEK) suitable for the desired \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e.\n* Encrypt the JWE payload with the desired encryption algorithm using the new CEK, producing the JWE payload ciphertext.\n* Derive a 'key encryption key' (KEK) with the desired \"PBES2 with HMAC SHA\" algorithm using the password, a suitable\nnumber of computational iterations, and a secure-random salt value.\n* Encrypt the generated CEK with the corresponding AES Key Wrap algorithm using the password-derived KEK.\n* Embed the payload ciphertext and encrypted CEK in the resulting JWE.\n\n[NOTE]\n====\n.Secure defaults\n\nWhen using these algorithms, if you do not specify a work factor (i.e. number of computational\niterations), JJWT will automatically use an\nhttps://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2[OWASP PBKDF2 recommended]\ndefault appropriate for the specified `PBES2` algorithm.\n====\n\nDuring JWE decryption, these algorithms:\n\n* Retrieve the encrypted Content Encryption Key (CEK) embedded in the JWE.\n* Derive the 'key encryption key' (KEK) with the discovered \"PBES2 with HMAC SHA\" algorithm using the password and the\nnumber of computational iterations and secure-random salt value discovered in the JWE header.\n* Decrypt the encrypted CEK with the corresponding AES Key Unwrap algorithm using the password-derived KEK.\n* Decrypt the JWE ciphertext payload with the JWE's identified \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e using the decrypted CEK.\n\n+++\u003ca name=\"jwe-alg-ecdhes\"\u003e++++++\u003c/a\u003e+++\n\n===== Elliptic Curve Diffie-Hellman Ephemeral Static Key Agreement (ECDH-ES)\n\nThe JWT Elliptic Curve Diffie-Hellman Ephemeral Static key agreement algorithms `ECDH-ES`, `ECDH-ES+A128KW`,\n`ECDH-ES+A192KW`, and `ECDH-ES+A256KW` are used when you want to use the JWE recipient's Elliptic Curve _public_ key\nduring encryption.  This ensures that only the JWE recipient can decrypt and read the JWE (using their Elliptic Curve\n_private_ key).\n\nDuring JWE creation, these algorithms:\n\n* Obtain the Content Encryption Key (CEK) used to encrypt the JWE payload as follows:\n ** Inspect the JWE recipient's Elliptic Curve public key and determine its Curve.\n ** Generate a new secure-random ephemeral Elliptic Curve public/private key pair on this same Curve.\n ** Add the ephemeral EC public key to the JWE\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1[epk header] for inclusion in the final JWE.\n ** Produce an ECDH shared secret with the ECDH Key Agreement algorithm using the JWE recipient's EC public key\nand the ephemeral EC private key.\n ** Derive a symmetric secret key with the Concat Key Derivation Function\n(https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf[NIST.800-56A], Section 5.8.1) using\nthis ECDH shared secret and any provided\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.2[PartyUInfo] and/or\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.3[PartyVInfo].\n ** If the key algorithm is `ECDH-ES`:\n  *** Use the Concat KDF-derived symmetric secret key directly as the Content Encryption Key (CEK). No encrypted key\nis created, nor embedded in the resulting JWE.\n ** Otherwise, if the key algorithm is `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, or `ECDH-ES+A256KW`:\n  *** Generate a new secure-random Content Encryption Key (CEK) suitable for the desired \u003c\u003cjwe-enc,encryption algorithm\u003e\u003e.\n  *** Encrypt this new CEK with the corresponding AES Key Wrap algorithm using the Concat KDF-derived secret key,\nproducing the encrypted CEK.\n  *** Embed the encrypted CEK in the resulting JWE.\n* Encrypt the JWE payload with the desired encryption algorithm using the obtained CEK, producing the JWE payload\nciphertext.\n* Embed the payload ciphertext in the resulting JWE.\n\nDuring JWE decryption, these algorithms:\n\n* Obtain the Content Encryption Key (CEK) used to decrypt the JWE payload as follows:\n ** Retrieve the required ephemeral Elliptic Curve public key from the JWE's\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.1[epk header].\n ** Ensure the ephemeral EC public key exists on the same curve as the JWE recipient's EC private key.\n ** Produce the ECDH shared secret with the ECDH Key Agreement algorithm using the JWE recipient's EC private key\nand the ephemeral EC public key.\n ** Derive a symmetric secret key with the Concat Key Derivation Function\n(https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf[NIST.800-56A], Section 5.8.1) using\nthis ECDH shared secret and any\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.2[PartyUInfo] and/or\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-4.6.1.3[PartyVInfo] found in the JWE header.\n ** If the key algorithm is `ECDH-ES`:\n  *** Use the Concat KDF-derived secret key directly as the Content Encryption Key (CEK). No encrypted key is used.\n ** Otherwise, if the key algorithm is `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, or `ECDH-ES+A256KW`:\n  *** Obtain the encrypted key ciphertext embedded in the JWE.\n  *** Decrypt the encrypted key ciphertext with the associated AES Key Unwrap algorithm using the Concat KDF-derived\nsecret key, producing the unencrypted Content Encryption Key (CEK).\n* Decrypt the JWE payload ciphertext with the JWE's discovered encryption algorithm using the obtained CEK.\n\n+++\u003ca name=\"jwe-create\"\u003e++++++\u003c/a\u003e+++\n\n=== Creating a JWE\n\nNow that we know the difference between a JWE Encryption Algorithm and a JWE Key Management Algorithm, how do we use\nthem to encrypt a JWT?\n\nYou create an encrypted JWT (called a 'JWE') as follows:\n\n. Use the `Jwts.builder()` method to create a `JwtBuilder` instance.\n. Call `JwtBuilder` methods to set the `payload` content or claims and any \u003c\u003cjws-create-header,header\u003e\u003e parameters as desired.\n. Call the `encryptWith` method, specifying the Key, Key Algorithm, and Encryption Algorithm you want to use.\n. Finally, call the `compact()` method to compact and encrypt, producing the final jwe.\n\nFor example:\n\n[,java]\n----\nString jwe = Jwts.builder()                              // (1)\n\n    .subject(\"Bob\")                                      // (2)\n\n    .encryptWith(key, keyAlgorithm, encryptionAlgorithm) // (3)\n\n    .compact();                                          // (4)\n----\n\nBefore calling `compact()`,  you may set any \u003c\u003cjws-create-header,header\u003e\u003e parameters and \u003c\u003cjws-create-claims,claims\u003e\u003e\nexactly the same way as described for JWS.\n\n+++\u003ca name=\"jwe-compression\"\u003e++++++\u003c/a\u003e+++\n\n==== JWE Compression\n\nIf your JWT payload or Claims set is large (contains a lot of data), you might want to compress the JWE to reduce\nits size.  Please see the main \u003c\u003ccompression,Compression\u003e\u003e section to see how to compress and decompress JWTs.\n\n+++\u003ca name=\"jwe-read\"\u003e++++++\u003c/a\u003e+++\n\n=== Reading a JWE\n\nYou read (parse) a JWE as follows:\n\n. Use the `Jwts.parser()` method to create a `JwtParserBuilder` instance.\n. Call either \u003c\u003ckey-locator,keyLocator\u003e\u003e or `decryptWith` methods to determine the key used to decrypt the JWE.\n. Call the ``JwtParserBuilder``'s `build()` method to create a thread-safe `JwtParser`.\n. Parse the jwe string with the ``JwtParser``'s `parseEncryptedClaims` or `parseEncryptedContent` method.\n. Wrap the entire call is in a try/catch block in case decryption or integrity verification fails.\n\nFor example:\n\n[,java]\n----\nJwe\u003cClaims\u003e jwe;\n\ntry {\n    jwe = Jwts.parser()               // (1)\n\n    .keyLocator(keyLocator)           // (2) dynamically lookup decryption keys based on each JWE\n    //.decryptWith(key)               //     or a static key used to decrypt all encountered JWEs\n\n    .build()                          // (3)\n    .parseEncryptedClaims(jweString); // (4) or parseEncryptedContent(jweString);\n\n    // we can safely trust the JWT\n\ncatch (JwtException ex) {             // (5)\n\n    // we *cannot* use the JWT as intended by its creator\n}\n----\n\n[NOTE]\n====\n.Type-safe JWEs\n\n* If you are expecting a JWE with a Claims `payload`, call the ``JwtParser``'s `parseEncryptedClaims` method.\n* If you are expecting a JWE with a content `payload`, call the ``JwtParser``'s `parseEncryptedContent` method.\n====\n\n+++\u003ca name=\"jwe-read-key\"\u003e++++++\u003c/a\u003e+++\n\n==== Decryption Key\n\nThe most important thing to do when reading a JWE is to specify the key used during decryption.  If decryption or\nintegrity protection checks fail, the JWT cannot be safely trusted and should be discarded.\n\nSo which key do we use for decryption?\n\n* If the jwe was encrypted _directly_ with a `SecretKey`, the same `SecretKey` must be specified on the\n`JwtParserBuilder`. For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .decryptWith(secretKey) // \u003c----\n\n  .build()\n  .parseEncryptedClaims(jweString);\n----\n\n* If the jwe was encrypted using a key produced by a Password-based key derivation `KeyAlgorithm`, the same\n`Password` must be specified on the `JwtParserBuilder`. For example:\n+\n[,java]\n----\nPassword password = Keys.password(passwordChars);\n\nJwts.parser()\n\n  .decryptWith(password) // \u003c---- an `io.jsonwebtoken.security.Password` instance\n\n  .build()\n  .parseEncryptedClaims(jweString);\n----\n\n* If the jwe was encrypted with a key produced by an asymmetric `KeyAlgorithm`, the corresponding `PrivateKey` (not\nthe `PublicKey`) must be specified on the `JwtParserBuilder`.  For example:\n+\n[,java]\n----\nJwts.parser()\n\n  .decryptWith(privateKey) // \u003c---- a `PrivateKey`, not a `PublicKey`\n\n  .build()\n  .parseSignedClaims(jweString);\n----\n\n+++\u003ca name=\"jwe-key-locator\"\u003e++++++\u003c/a\u003e+++\n\n==== Decryption Key Locator\n\nWhat if your application doesn't use just a single `SecretKey` or `KeyPair`? What\nif JWEs can be created with different ``SecretKey``s, ``Password``s or public/private keys, or a combination of all of\nthem?  How do you know which key to specify if you can't inspect the JWT first?\n\nIn these cases, you can't call the ``JwtParserBuilder``'s `decryptWith` method with a single key - instead, you'll need\nto use a Key `Locator`.  Please see the \u003c\u003ckey-locator,Key Lookup\u003e\u003e section to see how to dynamically obtain different\nkeys when parsing JWSs or JWEs.\n\n+++\u003ca name=\"jwe-key-pkcs11\"\u003e++++++\u003c/a\u003e+++\n\n==== ECDH-ES Decryption with PKCS11 PrivateKeys\n\nThe JWT `ECDH-ES`, `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, and `ECDH-ES+A256KW` key algorithms validate JWE input using\npublic key information, even when using ``PrivateKey``s to decrypt.  Ordinarily this is automatically performed\nby JJWT when your `PrivateKey` instances implement the\nhttps://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/security/interfaces/ECKey.html[ECKey] or\nhttps://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/security/interfaces/EdECKey.html[EdECKey]\n(or BouncyCastle equivalent) interfaces, which is the case for most JCA `Provider` implementations.\n\nHowever, if your decryption ``PrivateKey``s are stored in a Hardware Security Module (HSM) and/or you use the\nhttps://docs.oracle.com/en/java/javase/17/security/pkcs11-reference-guide1.html#GUID-6DA72F34-6C6A-4F7D-ADBA-5811576A9331[SunPKCS11 Provider],\nit is likely that your `PrivateKey` instances _do not_ implement `ECKey`.\n\nIn these cases, you need to provide both the PKCS11 `PrivateKey` and it's companion `PublicKey` during decryption\nby using the `Keys.builder` method. For example:\n\n[,java]\n----\nKeyPair pair = getMyPkcs11KeyPair();\nPrivateKey jwtParserDecryptionKey = Keys.builder(pair.getPrivate())\n    .publicKey(pair.getPublic()) // PublicKey must implement ECKey or EdECKey or BouncyCastle equivalent\n    .build();\n----\n\nYou then use the resulting `jwtParserDecryptionKey` (not `pair.getPrivate()`) with the `JwtParserBuilder` or as\nthe return value from a custom \u003c\u003ckey-locator,Key Locator\u003e\u003e implementation.  For example:\n\n[,java]\n----\nPrivateKey decryptionKey = Keys.builder(pkcs11PrivateKey).publicKey(pkcs11PublicKey).build();\n\nJwts.parser()\n    .decryptWith(decryptionKey) // \u003c----\n    .build()\n    .parseEncryptedClaims(jweString);\n----\n\nOr as the return value from your key locator:\n\n[,java]\n----\nJwts.parser()\n    .keyLocator(keyLocator) // your keyLocator.locate(header) would return Keys.builder...\n    .build()\n    .parseEncryptedClaims(jweString);\n----\n\nPlease see the \u003c\u003ckey-locator-provider,Provider-constrained Keys\u003e\u003e section for more information, as well as\ncode examples of how to implement a Key `Locator` using the `Keys.builder` technique.\n\n+++\u003ca name=\"jwe-read-decompression\"\u003e++++++\u003c/a\u003e+++\n\n==== JWE Decompression\n\nIf a JWE is compressed using the `DEF` (https://www.rfc-editor.org/rfc/rfc1951[DEFLATE]) or `GZIP`\n(https://www.rfc-editor.org/rfc/rfc1952.html[GZIP]) compression algorithms, it will automatically be decompressed\nafter decryption, and there is nothing you need to configure.\n\nIf, however, a custom compression algorithm was used to compress the JWE, you will need to tell the\n`JwtParserBuilder` how to resolve your `CompressionAlgorithm` to decompress the JWT.\n\nPlease see the \u003c\u003ccompression,Compression\u003e\u003e section below to see how to decompress JWTs during parsing.\n\n+++\u003ca name=\"jwk\"\u003e++++++\u003c/a\u003e+++\n\n== JSON Web Keys (JWKs)\n\nhttps://www.rfc-editor.org/rfc/rfc7517.html[JSON Web Keys] (JWKs) are JSON serializations of cryptographic keys,\nallowing key material to be embedded in JWTs or transmitted between parties in a standard JSON-based text format. They\nare essentially a JSON-based alternative to other text-based key formats, such as the\nhttps://serverfault.com/a/9717[DER, PEM and PKCS12] text strings or files commonly used when configuring TLS on web\nservers, for example.\n\nFor example, an identity web service may expose its RSA or Elliptic Curve Public Keys to 3rd parties in the JWK format.\nA client may then parse the public key JWKs to verify the service's \u003c\u003cjws,JWS\u003e\u003e tokens, as well as send encrypted\ninformation to the service using \u003c\u003cjwe,JWE\u003e\u003es.\n\nJWKs can be converted to and from standard Java `Key` types as expected using the same builder/parser patterns we've\nseen for JWTs.\n\n+++\u003ca name=\"jwk-create\"\u003e++++++\u003c/a\u003e+++\n\n=== Create a JWK\n\nYou create a JWK as follows:\n\n. Use the `Jwks.builder()` method to create a `JwkBuilder` instance.\n. Call the `key` method with the Java key you wish to represent as a JWK.\n. Call builder methods to set any additional key parameters or metadata, such as a `kid` (Key ID), X509 Certificates,\netc as desired.\n. Call the `build()` method to produce the resulting JWK.\n\nFor example:\n\n[,java]\n----\nSecretKey key = getSecretKey();     // or RSA or EC PublicKey or PrivateKey\nSecretJwk = Jwks.builder().key(key) // (1) and (2)\n\n    .id(\"mySecretKeyId\")            // (3)\n    // ... etc ...\n\n    .build();                       // (4)\n----\n\n==== JWK from a Map\n\nIf you have a `Map\u003cString,?\u003e` of name/value pairs that reflect an existing JWK, you add them and build a type-safe\n`Jwk` instance:\n\n[,java]\n----\nMap\u003cString,?\u003e jwkValues = getMyJwkMap();\n\nJwk\u003c?\u003e jwk = Jwks.builder().add(jwkValues).build();\n----\n\n+++\u003ca name=\"jwk-read\"\u003e++++++\u003c/a\u003e+++\n\n=== Read a JWK\n\nYou can read/parse a JWK by building a `JwkParser` and parsing the JWK JSON string with its `parse` method:\n\n[,java]\n----\nString json = getJwkJsonString();\nJwk\u003c?\u003e jwk = Jwks.parser()\n    //.provider(aJcaProvider)     // optional\n    //.deserializer(deserializer) // optional\n    .build()                      // create the parser\n    .parse(json);                 // actually parse the JSON\n\nKey key = jwk.toKey();            // convert to a Java Key instance\n----\n\nAs shown above you can specify a custom JCA Provider or \u003c\u003cjson,JSON deserializer\u003e\u003e in the same way as the `JwtBuilder`.\n\n+++\u003ca name=\"jwk-private\"\u003e++++++\u003c/a\u003e+++\n\n=== PrivateKey JWKs\n\nUnlike Java, the JWA specification requires a private JWKs to contain _both_ public key _and_ private key material\n(see https://www.rfc-editor.org/rfc/rfc7518.html#section-6.2.2[RFC 7518, Section 6.1.1] and\nhttps://www.rfc-editor.org/rfc/rfc7518.html#section-6.3.2[RFC 7518, Section 6.3.2]).\n\nIn this sense, a private JWK (represented as a `PrivateJwk` or a subtype, such as `RsaPrivateJwk`, `EcPrivateJwk`, etc)\ncan be thought of more like a Java `KeyPair` instance.  Consequently, when creating a `PrivateJwk` instance,\nthe ``PrivateKey``'s corresponding `PublicKey` is required.\n\n+++\u003ca name=\"jwk-private-public\"\u003e++++++\u003c/a\u003e+++\n\n==== Private JWK `PublicKey`\n\nIf you do not provide a `PublicKey` when creating a `PrivateJwk`, JJWT will automatically derive the `PublicKey` from\nthe `PrivateKey` instance if possible. However, because this can add\nsome computing time, it is typically recommended to provide the `PublicKey` when possible to avoid this extra work.\n\nFor example:\n\n[,java]\n----\nRSAPrivateKey rsaPrivateKey = getRSAPrivateKey(); // or ECPrivateKey\n\nRsaPrivateJwk jwk = Jwks.builder().key(rsaPrivateKey)\n\n        //.publicKey(rsaPublicKey)  // optional, but recommended to avoid extra computation work\n\n        .build();\n----\n\n+++\u003ca name=\"jwk-private-keypair\"\u003e++++++\u003c/a\u003e+++\n\n==== Private JWK from KeyPair\n\nIf you have a Java `KeyPair` instance, then you have both the public and private key material necessary to create a\n`PrivateJwk`. For example:\n\n[,java]\n----\nKeyPair rsaKeyPair = getRSAKeyPair();\nRsaPrivateJwk rsaPrivJwk = Jwks.builder().rsaKeyPair(rsaKeyPair).build();\n\nKeyPair ecKeyPair = getECKeyPair();\nEcPrivateJwk ecPrivJwk = Jwks.builder().ecKeyPair(ecKeyPair).build();\n\nKeyPair edEcKeyPair = getEdECKeyPair();\nOctetPrivateJwk edEcPrivJwk = Jwks.builder().octetKeyPair(edEcKeyPair).build();\n----\n\nNote that:\n\n* An exception will be thrown when calling `rsaKeyPair` if the specified `KeyPair` instance does not contain\n`RSAPublicKey` and `RSAPrivateKey` instances.\n* Similarly, an exception will be thrown when calling `ecKeyPair` if\nthe `KeyPair` instance does not contain `ECPublicKey` and `ECPrivateKey` instances.\n* Finally, an exception will be\nthrown when calling `octetKeyPair` if the `KeyPair` instance does not contain X25519, X448, Ed25519, or Ed448 keys\n(introduced in JDK 11 and 15 or when using BouncyCastle).\n\n+++\u003ca name=\"jwk-private-topub\"\u003e++++++\u003c/a\u003e+++\n\n==== Private JWK Public Conversion\n\nBecause private JWKs contain public key material, you can always obtain the private JWK's corresponding public JWK and\nJava `PublicKey` or `KeyPair`.  For example:\n\n[,java]\n----\nRsaPrivateJwk privateJwk = Jwks.builder().key(rsaPrivateKey).build(); // or ecPrivateKey or edEcPrivateKey\n\n// Get the matching public JWK and/or PublicKey:\nRsaPublicJwk pubJwk = privateJwk.toPublicJwk();       // JWK instance\nRSAPublicKey pubKey = pubJwk.toKey();                 // Java PublicKey instance\nKeyPair pair = privateJwk.toKeyPair();                // io.jsonwebtoken.security.KeyPair retains key types\njava.security.KeyPair jdkPair = pair.toJavaKeyPair(); // does not retain pub/private key types\n----\n\n+++\u003ca name=\"jwk-thumbprint\"\u003e++++++\u003c/a\u003e+++\n\n=== JWK Thumbprints\n\nA https://www.rfc-editor.org/rfc/rfc7638.html[JWK Thumbprint] is a digest (aka hash) of a canonical JSON\nrepresentation of a JWK's public properties. 'Canonical' in this case means that only RFC-specified values in any JWK\nare used in an exact order thumbprint calculation.  This ensures that anyone can calculate a JWK's same exact\nthumbprint, regardless of custom parameters or JSON key/value ordering differences in a JWK.\n\nAll `Jwk` instances support https://www.rfc-editor.org/rfc/rfc7638.html[JWK Thumbprint]s via the\n`thumbprint()` and `thumbprint(HashAlgorithm)` methods:\n\n[,java]\n----\nHashAlgorithm hashAlg = Jwks.HASH.SHA256; // or SHA384, SHA512, etc.\n\nJwk\u003c?\u003e jwk = Jwks.builder(). /* ... */ .build();\n\nJwkThumbprint sha256Thumbprint = jwk.thumbprint(); // SHA-256 thumbprint by default\n\nJwkThumbprint anotherThumbprint = jwk.thumbprint(Jwks.HASH.SHA512); // or a specified hash algorithm\n----\n\nThe resulting `JwkThumbprint` instance provides some useful methods:\n\n* `jwkThumbprint.toByteArray()`: the thumbprint's actual digest bytes - i.e. the raw output from the hash algorithm\n* `jwkThumbprint.toString()`: the digest bytes as a Base64URL-encoded string\n* `jwkThumbprint.getHashAlgorithm()`: the specific `HashAlgorithm` used to compute the thumbprint. Many standard IANA\n                                    hash algorithms are available as constants in the `Jwks.HASH` utility class.\n* `jwkThumbprint.toURI()`: the thumbprint's canonical URI as defined by the https://www.rfc-editor.org/rfc/rfc9278.html[JWK Thumbprint URI] specification\n\n+++\u003ca name=\"jwk-thumbprint-kid\"\u003e++++++\u003c/a\u003e+++\n\n==== JWK Thumbprint as a Key ID\n\nBecause a thumbprint is an order-guaranteed unique digest of a JWK, JWK thumbprints are often used as convenient\nunique identifiers for a JWK (e.g. the JWK's `kid` (Key ID) value). These identifiers can be useful when\n\u003c\u003ckey-locator,locating keys\u003e\u003e for JWS signature verification or JWE decryption, for example.\n\nFor example:\n\n[,java]\n----\nString kid = jwk.thumbprint().toString(); // Thumbprint bytes as a Base64URL-encoded string\nKey key = findKey(kid);\nassert jwk.toKey().equals(key);\n----\n\nHowever, because `Jwk` instances are immutable, you can't set the key id after the JWK is created. For example, the\nfollowing is not possible:\n\n[,java]\n----\nString kid = jwk.thumbprint().toString();\njwk.setId(kid) // Jwks are immutable - there is no `setId` method\n----\n\nInstead, you may use the `idFromThumbprint` methods on the `JwkBuilder` when creating a `Jwk`:\n\n[,java]\n----\nJwk\u003c?\u003e jwk = Jwks.builder().key(aKey)\n\n    .idFromThumbprint() // or idFromThumbprint(HashAlgorithm)\n\n    .build();\n----\n\nCalling either `idFromThumbprint` method will ensure that calling `jwk.getId()` equals `thumbprint.toString()`\n(which is `Encoders.BASE64URL.encode(thumbprint.toByteArray())`).\n\n+++\u003ca name=\"jwk-thumbprint-uri\"\u003e++++++\u003c/a\u003e+++\n\n==== JWK Thumbprint URI\n\nA JWK's thumbprint's canonical URI as defined by the https://www.rfc-editor.org/rfc/rfc9278.html[JWK Thumbprint URI]\nspecification may be obtained by calling the thumbprint's `toURI()` method:\n\n[,java]\n----\nURI canonicalThumbprintURI = jwk.thumbprint().toURI();\n----\n\nPer the RFC specification, if you call `canonicalThumbprintURI.toString()`, you would see a string that looks like this:\n\n[,text]\n----\nurn:ietf:params:oauth:jwk-thumbprint:HASH_ALG_ID:BASE64URL_DIGEST\n----\n\nwhere:\n\n* `urn:ietf:params:oauth:jwk-thumbprint:` is the URI scheme+prefix\n* `HASH_ALG_ID` is the standard identifier used to compute the thumbprint as defined in the\nhttps://www.iana.org/assignments/named-information/named-information.xhtml[IANA Named Information Hash Algorithm Registry].\nThis is the same as `thumbprint.getHashAlgorithm().getId()`.\n* `BASE64URL_DIGEST` is the Base64URL-encoded thumbprint bytes, equal to `jwkThumbprint.toString()`.\n\n+++\u003ca name=\"jwk-security\"\u003e++++++\u003c/a\u003e+++\n\n=== JWK Security Considerations\n\nBecause they contain secret or private key material, `SecretJwk` and `PrivateJwk` (e.g. `RsaPrivateJwk`, +\n`EcPrivateJwk`, etc) instances should be used with great care and never accidentally transmitted to 3rd parties.\n\nEven so, JJWT's `Jwk` implementations will suppress certain values in `toString()` output for safety as described\nnext.\n\n+++\u003ca name=\"jwk-tostring\"\u003e++++++\u003c/a\u003e+++\n\n==== JWK `toString()` Safety\n\nBecause it would be incredibly easy to accidentally print key material to `System.out.println()` or application\nlogs, all `Jwk` implementations will print redacted values instead of actual secret or private key material.\n\nFor example, consider the following Secret JWK JSON example from\nhttps://www.rfc-editor.org/rfc/rfc7515#appendix-A.1.1[RFC 7515, Appendix A.1.1]:\n\n[,json]\n----\n{\n  \"kty\": \"oct\",\n  \"k\": \"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\",\n  \"kid\": \"HMAC key used in https://www.rfc-editor.org/rfc/rfc7515#appendix-A.1.1 example.\"\n}\n----\n\nThe `k` value (`+AyAyM1SysPpby...+`) reflects secure key material and should never be accidentally\nexposed.\n\nIf you were to parse this JSON as a `Jwk`, calling `toString()` will _NOT_ print this value.  It will\ninstead print the string literal `\u003credacted\u003e` for any secret or private key data value.  For example:\n\n[,java]\n----\nString json = getExampleSecretKeyJson();\nJwk\u003c?\u003e jwk = Jwks.parser().build().parse(json);\n\nSystem.out.printn(jwk);\n----\n\nThis code would print the following string literal to the System console:\n\n[,text]\n----\n{kty=oct, k=\u003credacted\u003e, kid=HMAC key used in https://www.rfc-editor.org/rfc/rfc7515#appendix-A.1.1 example.}\n----\n\nThis is true for all secret or private key members in `SecretJwk` and `PrivateJwk` (e.g. `RsaPrivateJwk`,\n`EcPrivateJwk`, etc) instances.\n\n+++\u003ca name=\"jwkset\"\u003e++++++\u003c/a\u003e+++\n\n== JWK Sets\n\nThe JWK specification specification also defines the concept of a\nhttps://datatracker.ietf.org/doc/html/rfc7517#section-5[JWK Set]:\n\n A JWK Set is a JSON object that represents a set of JWKs.  The JSON\n object MUST have a \"keys\" member, with its value being an array of\n JWKs.\n\nFor example:\n\n[,txt]\n----\n{\n  \"keys\": [jwk1, jwk2, ...]\n}\n----\n\nWhere `jwk1`, `jwk2`, etc., are each a single \u003c\u003cjwk,JWK\u003e\u003e JSON Object.\n\nA JWK Set _may_ have other members that are peers to the `keys` member, but the JWK specification does not define any\nothers - any such additional members would be custom or unique based on an application's needs or preferences.\n\nA JWK Set can be useful for conveying multiple keys simultaneously.  For example, an identity web service could expose\nall of its RSA or Elliptic Curve public keys that might be used for various purposes or different algorithms to\n3rd parties or API clients as a single JWK Set JSON Object or document.  An API client can then parse the JWK Set\nto obtain the keys that might be used to verify or decrypt JWTs sent by the web service.\n\nJWK Sets are (mostly) simple collections of JWKs, and they are easily supported by JJWT with parallel builder/parser\nconcepts we've seen above.\n\n+++\u003ca name=\"jwkset-create\"\u003e++++++\u003c/a\u003e+++\n\n=== Create a JWK Set\n\nYou create a JWK Set as follows:\n\n. Use the `Jwks.set()` method to create a `JwkSetBuilder` instance.\n. Call the `add(Jwk)` method any number of times to add one or more JWKs to the set.\n. Call builder methods to set any additional JSON members if desired, or the `operationPolicy(KeyOperationPolicy)`\nbuilder method to control what key operations may be assigned to any given JWK added to the set.\n. Call the `build()` method to produce the resulting JWK Set.\n\nFor example:\n\n[,java]\n----\nJwk\u003c?\u003e jwk = Jwks.builder()/* ... */.build();\nSecretJwk = Jwks.set()              // 1\n    .add(jwk)                       // 2, appends a key\n    //.add(aCollection)             //    append multiple keys\n    //.keys(allJwks)                //    sets/replaces all keys\n    //.add(\"aName\", \"aValue\")       // 3, optional\n    //.operationPolicy(Jwks.OP      // 3, optional\n    //     .policy()\n    //     /* etc... */\n    //     .build())\n    //.provider(aJcaProvider)       //    optional\n    .build();                       // (4)\n----\n\nAs shown, you can optionally configure the `.operationPolicy(KeyOperationPolicy)` method using a\n`Jwts.OP.policy()` builder.  A `KeyOperationPolicy` allows you control what operations are allowed for any JWK\nbefore being added to the JWK Set; any JWK that does not match the policy will be rejected and not added to the set.\nJJWT internally defaults to a standard RFC-compliant policy, but you can create a\npolicy to override the default if desired using the `Jwks.OP.policy()` builder method.\n\n+++\u003ca name=\"jwkset-read\"\u003e++++++\u003c/a\u003e+++\n\n=== Read a JWK Set\n\nYou can read/parse a JWK Set by building a JWK Set `Parser` and parsing the JWK Set JSON with one of its various\n`parse` methods:\n\n[,java]\n----\nJwkSet jwkSet = Jwks.setParser()\n    //.provider(aJcaProvider)      // optional\n    //.deserializer(deserializer)  // optional\n    //.policy(aKeyOperationPolicy) // optional\n    .build()                       // create the parser\n    .parse(json);                  // actually parse JSON String, InputStream, Reader, etc.\n\njwkSet.forEach(jwk -\u003e System.out.println(jwk));\n----\n\nAs shown above, you can specify a custom JCA Provider, \u003c\u003cjson,JSON deserializer\u003e\u003e or `KeyOperationPolicy` in the\nsame way as the `JwkSetBuilder`. Any JWK that does not match the default (or configured) policy will be\nrejected. You can create a policy to override the default if desired using the `Jwks.OP.policy()` builder method.\n\n+++\u003ca name=\"compression\"\u003e++++++\u003c/a\u003e+++\n\n== Compression\n\n[WARNING]\n====\nThe JWT specification standardizes compression for JWEs (Encrypted JWTs) ONLY, however JJWT supports it for JWS\n(Signed JWTs) as well.\n\nIf you are positive that a JWS you create with JJWT will _also_ be parsed with JJWT,\nyou can use this feature with both JWEs and JWSs, otherwise it is best to only use it for JWEs.\n====\n\nIf a JWT's `payload` is sufficiently large - that is, it is a large content byte array or JSON with a lot of\nname/value pairs (or individual values are very large or verbose) - you can reduce the size of the compact JWT by\ncompressing the payload.\n\nThis might be important to you if the resulting JWT is used in a URL for example, since URLs are best kept under\n4096 characters due to browser, user mail agent, or HTTP gateway compatibility issues.  Smaller JWTs also help reduce\nbandwidth utilization, which may or may not be important depending on your application's volume or needs.\n\nIf you want to compress your JWT, you can use the ``JwtBuilder``'s  `compressWith(CompressionAlgorithm)` method.  For\nexample:\n\n[,java]\n----\nJwts.builder()\n\n   .compressWith(Jwts.ZIP.DEF) // DEFLATE compression algorithm\n\n   // .. etc ...\n----\n\nIf you use any of the algorithm constants in the `Jwts.ZIP` class, that's it, you're done.  You don't have to\ndo anything during parsing or configure the `JwtParserBuilder` for compression - JJWT will automatically decompress\nthe payload as expected.\n\n+++\u003ca name=\"compression-custom\"\u003e++++++\u003c/a\u003e+++\n\n=== Custom Compression Algorithm\n\nIf the default `Jwts.ZIP` compression algorithms are not suitable for your needs, you can create your own\n`CompressionAlgorithm` implementation(s).\n\nJust as you would with the default algorithms, you may specify that you want a JWT compressed by calling the\n``JwtBuilder``'s `compressWith` method, supplying your custom implementation instance.  For example:\n\n[,java]\n----\nCompressionAlgorithm myAlg = new MyCompressionAlgorithm();\n\nJwts.builder()\n\n   .compressWith(myAlg) // \u003c----\n\n   // .. etc ...\n----\n\nWhen you call `compressWith`, the JWT `payload` will be compressed with your algorithm, and the\nhttps://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.3[`zip` (Compression Algorithm)]\nheader will automatically be set to the value returned by your algorithm's `algorithm.getId()` method as\nrequired by the JWT specification.\n\n+++\u003ca name=\"compression-custom-locator\"\u003e++++++\u003c/a\u003e+++\n// legacy link\nHowever, the `JwtParser` needs to be aware of this custom algorithm as well, so it can use it while parsing. You do this\nby modifying the ``JwtParserBuilder``'s `zip()` collection.  For example:\n\n[,java]\n----\nCompressionAlgorithm myAlg = new MyCompressionAlgorithm();\n\nJwts.parser()\n\n    .zip().add(myAlg).and() // \u003c----\n\n    // .. etc ...\n----\n\nThis adds additional `CompressionAlgorithm` implementations to the parser's overall total set of supported compression\nalgorithms (which already includes all of the `Jwts.ZIP` algorithms by default).\n\nThe parser will then automatically check to see if the JWT `zip` header has been set to see if a compression\nalgorithm has been used to compress the JWT.  If set, the parser will automatically look up your\n`CompressionAlgorithm` by its `getId()` value, and use it to decompress the JWT.\n\n+++\u003ca name=\"json\"\u003e++++++\u003c/a\u003e+++\n\n== JSON Support\n\nA `JwtBuilder` will serialize the `Header` and `Claims` maps (and potentially any Java objects they\ncontain) to JSON with a `Serializer\u003cMap\u003cString, ?\u003e\u003e` instance.  Similarly, a `JwtParser` will\ndeserialize JSON into the `Header` and `Claims` using a `Deserializer\u003cMap\u003cString, ?\u003e\u003e` instance.\n\nIf you don't explicitly configure a ``JwtBuilder``'s `Serializer` or a ``JwtParserBuilder``'s `Deserializer`, JJWT will\nautomatically attempt to discover and use the following JSON implementations if found in the runtime classpath. +\nThey are checked in order, and the first one found is used:\n\n. Jackson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-jackson` as a project runtime\ndependency.  Jackson supports POJOs as claims with full marshaling/unmarshaling as necessary.\n. Gson: This will automatically be used if you specify `io.jsonwebtoken:jjwt-gson` as a project runtime dependency.\nGson also supports POJOs as claims with full marshaling/unmarshaling as necessary.\n. JSON-Java (`org.json`): This will be used automatically if you specify `io.jsonwebtoken:jjwt-orgjson` as a\nproject runtime dependency.\n+\n[NOTE]\n====\n`org.json` APIs are natively enabled in Android environments so this is the recommended JSON processor for\nAndroid applications _unless_ you want to use POJOs as claims.  The `org.json` library supports simple\nObject-to-JSON marshaling, but it _does not_ support JSON-to-Object unmarshalling.\n====\n\n*If you want to use POJOs as claim values, use either the `io.jsonwebtoken:jjwt-jackson` or\n`io.jsonwebtoken:jjwt-gson` dependency* (or implement your own Serializer and Deserializer if desired). *But beware*,\nJackson will force a sizable (\u003e 1 MB) dependency to an Android application thus increasing the app download size for\nmobile users.\n\n+++\u003ca name=\"json-custom\"\u003e++++++\u003c/a\u003e+++\n\n=== Custom JSON Processor\n\nIf you don't want to use JJWT's runtime dependency approach, or just want to customize how JSON serialization and\ndeserialization works, you can implement the `Serializer` and `Deserializer` interfaces and specify instances of\nthem on the `JwtBuilder` and `JwtParserBuilder` respectively.  For example:\n\nWhen creating a JWT:\n\n[,java]\n----\nSerializer\u003cMap\u003cString,?\u003e\u003e serializer = getMySerializer(); //implement me\n\nJwts.builder()\n\n    .json(serializer)\n\n    // ... etc ...\n----\n\nWhen reading a JWT:\n\n[,java]\n----\nDeserializer\u003cMap\u003cString,?\u003e\u003e deserializer = getMyDeserializer(); //implement me\n\nJwts.parser()\n\n    .json(deserializer)\n\n    // ... etc ...\n----\n\n+++\u003ca name=\"json-jackson\"\u003e++++++\u003c/a\u003e+++\n\n=== Jackson JSON Processor\n\nIf you want to use Jackson for JSON processing, just including the `io.jsonwebtoken:jjwt-jackson` dependency as a\nruntime dependency is all that is necessary in most projects, since Gradle and Maven will automatically pull in\nthe necessary Jackson dependencies as well.\n\nAfter including this dependency, JJWT will automatically find the Jackson implementation on the runtime classpath and\nuse it internally for JSON parsing.  There is nothing else you need to do - JJWT will automatically create a new\nJackson ObjectMapper for its needs as required.\n\nHowever, if you have an application-wide Jackson `ObjectMapper` (as is typically recommended for most applications),\nyou can configure JJWT to use your own `ObjectMapper` instead.\n\nYou do this by declaring the `io.jsonwebtoken:jjwt-jackson` dependency with *compile* scope (not runtime\nscope which is the typical JJWT default).  That is:\n\n*Maven*\n\n[,xml,subs=\"+attributes\"]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.jsonwebtoken\u003c/groupId\u003e\n    \u003cartifactId\u003ejjwt-jackson\u003c/artifactId\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e \u003c!-- Not runtime --\u003e\n\u003c/dependency\u003e\n----\n\n*Gradle or Android*\n\n[,groovy,subs=\"+attributes\"]\n----\ndependencies {\n    implementation 'io.jsonwebtoken:jjwt-jackson:{project-version}'\n}\n----\n\nAnd then you can specify the `JacksonSerializer` using your own `ObjectMapper` on the `JwtBuilder`:\n\n[,java]\n----\nObjectMapper objectMapper = getMyObjectMapper(); //implement me\n\nString jws = Jwts.builder()\n\n    .json(new JacksonSerializer(objectMapper))\n\n    // ... etc ...\n----\n\nand the `JacksonDeserializer` using your `ObjectMapper` on the `JwtParserBuilder`:\n\n[,java]\n----\nObjectMapper objectMapper = getMyObjectMapper(); //implement me\n\nJwts.parser()\n\n    .json(new JacksonDeserializer(objectMapper))\n\n    // ... etc ...\n----\n\n+++\u003ca name=\"json-jackson-custom-types\"\u003e++++++\u003c/a\u003e+++\n\n==== Parsing of Custom Claim Types\n\nBy default, JJWT will only convert simple claim types: String, Date, Long, Integer, Short and Byte.  If you need to\ndeserialize other types you can configure the `JacksonDeserializer` by passing a `Map` of claim names to types in\nthrough a constructor. For example:\n\n[,java]\n----\nnew JacksonDeserializer(Maps.of(\"user\", User.class).build())\n----\n\nThis would trigger the value in the `user` claim to be deserialized into the custom type of `User`.  Given the claims\npayload of:\n\n[,json]\n----\n{\n    \"issuer\": \"https://example.com/issuer\",\n    \"user\": {\n      \"firstName\": \"Jill\",\n      \"lastName\": \"Coder\"\n    }\n}\n----\n\nThe `User` object could be retrieved from the `user` claim with the following code:\n\n[,java]\n----\nJwts.parser()\n\n    .json(new JacksonDeserializer(Maps.of(\"user\", User.class).build())) // \u003c-----\n\n    .build()\n\n    .parseUnprotectedClaims(aJwtString)\n\n    .getPayload()\n\n    .get(\"user\", User.class); // \u003c-----\n----\n\n[NOTE]\n====\nUsing this constructor is mutually exclusive with the `JacksonDeserializer(ObjectMapper)` constructor\n\u003c\u003cjson-jackson,described above\u003e\u003e. This is because JJWT configures an `ObjectMapper` directly and could have negative\nconsequences for a shared `ObjectMapper` instance. This should work for most applications, if you need a more advanced\nparsing options, \u003c\u003cjson-jackson,configure the mapper directly\u003e\u003e.\n====\n\n+++\u003ca name=\"json-gson\"\u003e++++++\u003c/a\u003e+++\n\n=== Gson JSON Processor\n\nIf you want to use Gson for JSON processing, just including the `io.jsonwebtoken:jjwt-gson` dependency as a\nruntime dependency is all that is necessary in most projects, since Gradle and Maven will automatically pull in\nthe necessary Gson dependencies as well.\n\nAfter including this dependency, JJWT will automatically find the Gson implementation on the runtime classpath and\nuse it internally for JSON parsing.  There is nothing else you need to do - just declaring the dependency is\nall that is required, no code or config is necessary.\n\nIf you're curious, JJWT will automatically create an internal default Gson instance for its own needs as follows:\n\n[,java]\n----\nnew GsonBuilder()\n    .registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)\n    .disableHtmlEscaping().create();\n----\n\nThe `registerTypeHierarchyAdapter` builder call is required to serialize JWKs with secret or private values.\n\nHowever, if you prefer to use a different Gson instance instead of JJWT's default, you can configure JJWT to use your\nown - just don't forget to register the necessary JJWT type hierarchy adapter.\n\nYou do this by declaring the `io.jsonwebtoken:jjwt-gson` dependency with *compile* scope (not runtime\nscope which is the typical JJWT default).  That is:\n\n*Maven*\n\n[,xml,subs=\"+attributes\"]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.jsonwebtoken\u003c/groupId\u003e\n    \u003cartifactId\u003ejjwt-gson\u003c/artifactId\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e \u003c!-- Not runtime --\u003e\n\u003c/dependency\u003e\n----\n\n*Gradle or Android*\n\n[,groovy,subs=\"+attributes\"]\n----\ndependencies {\n    implementation 'io.jsonwebtoken:jjwt-gson:{project-version}'\n}\n----\n\nAnd then you can specify the `GsonSerializer` using your own `Gson` instance on the `JwtBuilder`:\n\n[,java]\n----\n\nGson gson = new GsonBuilder()\n    // don't forget this line!:\n    .registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)\n    .disableHtmlEscaping().create();\n\nString jws = Jwts.builder()\n\n    .json(new GsonSerializer(gson))\n\n    // ... etc ...\n----\n\nand the `GsonDeserializer` using your `Gson` instance on the `JwtParser`:\n\n[,java]\n----\nGson gson = getGson(); //implement me\n\nJwts.parser()\n\n    .json(new GsonDeserializer(gson))\n\n    // ... etc ...\n----\n\nAgain, as shown above, it is critical to create your `Gson` instance using the `GsonBuilder` and include the line:\n\n[,java]\n----\n.registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)\n----\n\nto ensure JWK serialization works as expected.\n\n+++\u003ca name=\"base64\"\u003e++++++\u003c/a\u003e+++\n\n== Base64 Support\n\nJJWT uses a very fast pure-Java https://tools.ietf.org/html/rfc4648[Base64] codec for Base64 and\nBase64Url encoding and decoding that is guaranteed to work deterministically in all JDK and Android environments.\n\nYou can access JJWT's encoders and decoders using the `io.jsonwebtoken.io.Encoders` and `io.jsonwebtoken.io.Decoders`\nutility classes.\n\n`io.jsonwebtoken.io.Encoders`:\n\n* `BASE64` is an RFC 4648 https://tools.ietf.org/html/rfc4648#section-4[Base64] encoder\n* `BASE64URL` is an RFC 4648 https://tools.ietf.org/html/rfc4648#section-5[Base64URL] encoder\n\n`io.jsonwebtoken.io.Decoders`:\n\n* `BASE64` is an RFC 4648 https://tools.ietf.org/html/rfc4648#section-4[Base64] decoder\n* `BASE64URL` is an RFC 4648 https://tools.ietf.org/html/rfc4648#section-5[Base64URL] decoder\n\n+++\u003ca name=\"base64-security\"\u003e++++++\u003c/a\u003e+++\n\n=== Understanding Base64 in Security Contexts\n\nAll cryptographic operations, like encryption and message digest calculations, result in binary data - raw byte arrays.\n\nBecause raw byte arrays cannot be represented natively in JSON, the JWT\nspecifications employ the Base64URL encoding scheme to represent these raw byte values in JSON documents or compound\nstructures like a JWT.\n\nThis means that the Base64 and Base64URL algorithms take a raw byte array and converts the bytes into a string suitable\nto use in text documents and protocols like HTTP.  These algorithms can also convert these strings back\ninto the original raw byte arrays for decryption or signature verification as necessary.\n\nThat's nice and convenient, but there are two very important properties of Base64 (and Base64URL) text strings that\nare critical to remember when they are used in security scenarios like with JWTs:\n\n* \u003c\u003cbase64-not-encryption,Base64 is not encryption\u003e\u003e\n* \u003c\u003cbase64-changing-characters,Changing Base64 characters\u003e\u003e *does not automatically invalidate data*.\n\n+++\u003ca name=\"base64-not-encryption\"\u003e++++++\u003c/a\u003e+++\n\n==== Base64 is not encryption\n\nBase64-encoded text is _not_ encrypted.\n\nWhile a byte array representation can be converted to text with the Base64 algorithms,\nanyone in the world can take Base64-encoded text, decode it with any standard Base64 decoder, and obtain the\nunderlying raw byte array data.  No key or secret is required to decode Base64 text - anyone can do it.\n\nBased on this, when encoding sensitive byte data with Base64 - like a shared or private key - *the resulting\nstring is NOT safe to expose publicly*.\n\nA base64-encoded key is still sensitive information and must be kept as secret and as safe as the original source\nof the bytes (e.g. a Java `PrivateKey` or `SecretKey` instance).\n\nAfter Base64-encoding data into a string, it is possible to then encrypt the string to keep it safe from prying\neyes if desired, but this is different.  Encryption is not encoding.  They are separate concepts.\n\n+++\u003ca name=\"base64-changing-characters\"\u003e++++++\u003c/a\u003e+++\n\n==== Changing Base64 Characters\n\nIn an effort to see if signatures or encryption is truly validated correctly, some try to edit a JWT\nstring - particularly the Base64-encoded signature part - to see if the edited string fails security validations.\n\nThis conceptually makes sense: change the signature string, you would assume that signature validation would fail.\n\n_But this doesn't always work. Changing base64 characters is an invalid test_.\n\nWhy?\n\nBecause of the way the Base64 algorithm works, there are multiple Base64 strings that can represent the same raw byte\narray.\n\nGoing into the details of the Base64 algorithm is out of scope for this documentation, but there are many good\nStackoverflow https://stackoverflow.com/questions/33663113/multiple-strings-base64-decoded-to-same-byte-array?noredirect=1\u0026lq=1[answers]\nand https://github.com/jwtk/jjwt/issues/211#issuecomment-283076269[JJWT issue comments] that explain this in detail.\nHere's one https://stackoverflow.com/questions/29941270/why-do-base64-decode-produce-same-byte-array-for-different-strings[good answer]:\n\n[IMPORTANT]\n====\nRemember that Base64 encodes each 8 bit entity into 6 bit chars. The resulting string then needs exactly\n11 * 8 / 6 bytes, or 14 2/3 chars. But you can't write partial characters. Only the first 4 bits (or 2/3 of the\nlast char) are significant. The last two bits are not decoded. Thus all of:\n\n[,text]\n----\ndGVzdCBzdHJpbmo\ndGVzdCBzdHJpbmp\ndGVzdCBzdHJpbmq\ndGVzdCBzdHJpbmr \n----\nAll decode to the same 11 bytes (116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 106).\n====\n\nAs you can see by the above 4 examples, they all decode to the same exact 11 bytes.  So just changing one or two\ncharacters at the end of a Base64 string may not work and can often result in an invalid test.\n\n+++\u003ca name=\"base64-invalid-characters\"\u003e++++++\u003c/a\u003e+++\n\n===== Adding Invalid Characters\n\nJJWT's default Base64/Base64URL decoders automatically ignore illegal Base64 characters located in the beginning and\nend of an encoded string. Therefore, prepending or appending invalid characters like `{` or `]` or similar will also\nnot fail JJWT's signature checks either.  Why?\n\nBecause such edits - whether changing a trailing character or two, or appending invalid characters - do not actually\nchange the _real_ signature, which in cryptographic contexts, is always a byte array. Instead, tests like these\nchange a text encoding of the byte array, and as we covered above, they are different things.\n\nSo JJWT 'cares' more about the real byte array and less about its text encoding because that is what actually matters\nin cryptographic operations.  In this sense, JJWT follows the https://en.wikipedia.org/wiki/Robustness_principle[Robustness Principle]\nin being _slightly_ lenient on what is accepted per the rules of Base64, but if anything in the real underlying\nbyte array is changed, then yes, JJWT's cryptographic assertions will definitely fail.\n\nTo help understand JJWT's approach, we have to remember why signatures exist. From our documentation above on\n\u003c\u003cjws,signing JWTs\u003e\u003e:\n\n____\n* guarantees it was created by someone we know (it is authentic), as well as\n* guarantees that no-one has manipulated or changed it after it was created (its integrity is maintained).\n____\n\nJust prepending or appending invalid text to try to 'trick' the algorithm doesn't change the integrity of the\nunderlying claims or signature byte arrays, nor the authenticity of the claims byte array, because those byte\narrays are still obtained intact.\n\nPlease see https://github.com/jwtk/jjwt/issues/518[JJWT Issue #518] and its referenced issues and links for more\ninformation.\n\n+++\u003ca name=\"base64-custom\"\u003e++++++\u003c/a\u003e+++\n\n=== Custom Base64\n\nIf for some reason you want to specify your own Base64Url encoder and decoder, you can use the `JwtBuilder`\n`encoder` method to set the encoder:\n\n[,java]\n----\nEncoder\u003cbyte[], String\u003e encoder = getMyBase64UrlEncoder(); //implement me\n\nString jws = Jwts.builder()\n\n    .b64Url(encoder)\n\n    // ... etc ...\n----\n\nand the ``JwtParserBuilder``'s `decoder` method to set the decoder:\n\n[,java]\n----\nDecoder\u003cString, byte[]\u003e decoder = getMyBase64UrlDecoder(); //implement me\n\nJwts.parser()\n\n    .b64Url(decoder)\n\n    // ... etc ...\n----\n\n+++\u003ca name=\"examples\"\u003e++++++\u003c/a\u003e+++\n\n== Examples\n\n* \u003c\u003cexample-jws-hs,JWS Signed with HMAC\u003e\u003e\n* \u003c\u003cexample-jws-rsa,JWS Signed with RSA\u003e\u003e\n* \u003c\u003cexample-jws-ecdsa,JWS Signed with ECDSA\u003e\u003e\n* \u003c\u003cexample-jws-eddsa,JWS Signed with EdDSA\u003e\u003e\n* \u003c\u003cexample-jwe-dir,JWE Encrypted Directly with a SecretKey\u003e\u003e\n* \u003c\u003cexample-jwe-rsa,JWE Encrypted with RSA\u003e\u003e\n* \u003c\u003cexample-jwe-aeskw,JWE Encrypted with AES Key Wrap\u003e\u003e\n* \u003c\u003cexample-jwe-ecdhes,JWE Encrypted with ECDH-ES\u003e\u003e\n* \u003c\u003cexample-jwe-password,JWE Encrypted with a Password\u003e\u003e\n* \u003c\u003cexample-jwk-secret,SecretKey JWK\u003e\u003e\n* \u003c\u003cexample-jwk-rsapub,RSA Public JWK\u003e\u003e\n* \u003c\u003cexample-jwk-rsapriv,RSA Private JWK\u003e\u003e\n* \u003c\u003cexample-jwk-ecpub,Elliptic Curve Public JWK\u003e\u003e\n* \u003c\u003cexample-jwk-ecpriv,Elliptic Curve Private JWK\u003e\u003e\n* \u003c\u003cexample-jwk-edpub,Edwards Elliptic Curve Public JWK\u003e\u003e\n* \u003c\u003cexample-jwk-edpriv,Edwards Elliptic Curve Private JWK\u003e\u003e\n\n+++\u003ca name=\"example-jws-hs\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Signed with HMAC\n\nThis is an example showing how to digitally sign a JWT using an https://en.wikipedia.org/wiki/HMAC[HMAC]\n(hash-based message authentication code).  The JWT specifications define 3 standard HMAC signing algorithms:\n\n* `HS256`: HMAC with SHA-256. This requires a 256-bit (32 byte) `SecretKey` or larger.\n* `HS384`: HMAC with SHA-384. This requires a 384-bit (48 byte) `SecretKey` or larger.\n* `HS512`: HMAC with SHA-512. This requires a 512-bit (64 byte) `SecretKey` or larger.\n\nExample:\n\n[,java]\n----\n// Create a test key suitable for the desired HMAC-SHA algorithm:\nMacAlgorithm alg = Jwts.SIG.HS512; //or HS384 or HS256\nSecretKey key = alg.key().build();\n\nString message = \"Hello World!\";\nbyte[] content = message.getBytes(StandardCharsets.UTF_8);\n\n// Create the compact JWS:\nString jws = Jwts.builder().content(content, \"text/plain\").signWith(key, alg).compact();\n\n// Parse the compact JWS:\ncontent = Jwts.parser().verifyWith(key).build().parseSignedContent(jws).getPayload();\n\nassert message.equals(new String(content, StandardCharsets.UTF_8));\n----\n\n+++\u003ca name=\"example-jws-rsa\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Signed with RSA\n\nThis is an example showing how to digitally sign and verify a JWT using RSA cryptography. The JWT specifications\ndefine \u003c\u003cjws-alg,6 standard RSA signing algorithms\u003e\u003e.  All 6 require that \u003c\u003cjws-key-rsa,RSA keys 2048-bits or larger\u003e\u003e\nmust be used.\n\nIn this example, Bob will sign a JWT using his RSA private key, and Alice can verify it came from Bob using Bob's RSA\npublic key:\n\n[,java]\n----\n// Create a test key suitable for the desired RSA signature algorithm:\nSignatureAlgorithm alg = Jwts.SIG.RS512; //or PS512, RS256, etc...\nKeyPair pair = alg.keyPair().build();\n\n// Bob creates the compact JWS with his RSA private key:\nString jws = Jwts.builder().subject(\"Alice\")\n    .signWith(pair.getPrivate(), alg) // \u003c-- Bob's RSA private key\n    .compact();\n\n// Alice receives and verifies the compact JWS came from Bob:\nString subject = Jwts.parser()\n    .verifyWith(pair.getPublic()) // \u003c-- Bob's RSA public key\n    .build().parseSignedClaims(jws).getPayload().getSubject();\n\nassert \"Alice\".equals(subject);\n----\n\n+++\u003ca name=\"example-jws-ecdsa\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Signed with ECDSA\n\nThis is an example showing how to digitally sign and verify a JWT using the Elliptic Curve Digital Signature Algorithm.\nThe JWT specifications define \u003c\u003cjws-alg,3 standard ECDSA signing algorithms\u003e\u003e:\n\n* `ES256`: ECDSA using P-256 and SHA-256. This requires an EC Key exactly 256 bits (32 bytes) long.\n* `ES384`: ECDSA using P-384 and SHA-384. This requires an EC Key exactly 384 bits (48 bytes) long.\n* `ES512`: ECDSA using P-521 and SHA-512. This requires an EC Key exactly 521 bits (65 or 66 bytes depending on format) long.\n\nIn this example, Bob will sign a JWT using his EC private key, and Alice can verify it came from Bob using Bob's EC\npublic key:\n\n[,java]\n----\n// Create a test key suitable for the desired ECDSA signature algorithm:\nSignatureAlgorithm alg = Jwts.SIG.ES512; //or ES256 or ES384\nKeyPair pair = alg.keyPair().build();\n\n// Bob creates the compact JWS with his EC private key:\nString jws = Jwts.builder().subject(\"Alice\")\n    .signWith(pair.getPrivate(), alg) // \u003c-- Bob's EC private key\n    .compact();\n\n// Alice receives and verifies the compact JWS came from Bob:\nString subject = Jwts.parser()\n    .verifyWith(pair.getPublic()) // \u003c-- Bob's EC public key\n    .build().parseSignedClaims(jws).getPayload().getSubject();\n\nassert \"Alice\".equals(subject);\n----\n\n+++\u003ca name=\"example-jws-eddsa\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Signed with EdDSA\n\nThis is an example showing how to digitally sign and verify a JWT using the\nhttps://www.rfc-editor.org/rfc/rfc8032[Edwards Curve Digital Signature Algorithm] using\n`Ed25519` or `Ed448` keys.\n\n[NOTE]\n====\nThe `Ed25519` and `Ed448` algorithms require JDK 15 or a compatible JCA Provider\n(like BouncyCastle) in the runtime classpath.\n\nIf you are using JDK 14 or earlier and you want to use them, see\nthe \u003c\u003cInstallation,Installation\u003e\u003e section to see how to enable BouncyCastle.\n====\n\nThe `EdDSA` signature algorithm is defined for JWS in https://www.rfc-editor.org/rfc/rfc8037#section-3.1[RFC 8037, Section 3.1]\nusing keys for two Edwards curves:\n\n* `Ed25519`: `EdDSA` using curve `Ed25519`. `Ed25519` algorithm keys must be 255 bits long and produce\n           signatures 512 bits (64 bytes) long.\n* `Ed448`: `EdDSA` using curve `Ed448`. `Ed448` algorithm keys must be 448 bits long and produce signatures\n         912 bits (114 bytes) long.\n\nIn this example, Bob will sign a JWT using his Edwards Curve private key, and Alice can verify it came from Bob\nusing Bob's Edwards Curve public key:\n\n[,java]\n----\n// Create a test key suitable for the EdDSA signature algorithm using Ed25519 or Ed448 keys:\nCurve curve = Jwks.CRV.Ed25519; //or Ed448\nKeyPair pair = curve.keyPair().build();\n\n// Bob creates the compact JWS with his Edwards Curve private key:\nString jws = Jwts.builder().subject(\"Alice\")\n    .signWith(pair.getPrivate(), Jwts.SIG.EdDSA) // \u003c-- Bob's Edwards Curve private key w/ EdDSA\n    .compact();\n\n// Alice receives and verifies the compact JWS came from Bob:\nString subject = Jwts.parser()\n    .verifyWith(pair.getPublic()) // \u003c-- Bob's Edwards Curve public key\n    .build().parseSignedClaims(jws).getPayload().getSubject();\n\nassert \"Alice\".equals(subject);\n----\n\n+++\u003ca name=\"example-jwe-dir\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Encrypted Directly with a SecretKey\n\nThis is an example showing how to encrypt a JWT \u003c\u003cjwe-alg-dir,directly using a symmetric secret key\u003e\u003e.  The\nJWT specifications define \u003c\u003cjwe-enc,6 standard AEAD Encryption algorithms\u003e\u003e:\n\n* `A128GCM`: AES GCM using a 128-bit (16 byte) `SecretKey` or larger.\n* `A192GCM`: AES GCM using a 192-bit (24 byte) `SecretKey` or larger.\n* `A256GCM`: AES GCM using a 256-bit (32 byte) `SecretKey` or larger.\n* `A128CBC-HS256`: https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.3[AES_128_CBC_HMAC_SHA_256] using a\n256-bit (32 byte) `SecretKey`.\n* `A192CBC-HS384`: https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.4[AES_192_CBC_HMAC_SHA_384] using a\n384-bit (48 byte) `SecretKey`.\n* `A256CBC-HS512`: https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.5[AES_256_CBC_HMAC_SHA_512] using a\n512-bit (64 byte) `SecretKey`.\n\nThe AES GCM (`A128GCM`, `A192GCM` and `A256GCM`) algorithms are strongly recommended - they are faster and more\nefficient than the `A*CBC-HS*` variants, but they do require JDK 8 or later (or JDK 7 + BouncyCastle).\n\nExample:\n\n[,java]\n----\n// Create a test key suitable for the desired payload encryption algorithm:\n// (A*GCM algorithms are recommended, but require JDK \u003e= 8 or BouncyCastle)\nAeadAlgorithm enc = Jwts.ENC.A256GCM; //or A128GCM, A192GCM, A256CBC-HS512, etc...\nSecretKey key = enc.key().build();\n\nString message = \"Live long and prosper.\";\nbyte[] content = message.getBytes(StandardCharsets.UTF_8);\n\n// Create the compact JWE:\nString jwe = Jwts.builder().content(content, \"text/plain\").encryptWith(key, enc).compact();\n\n// Parse the compact JWE:\ncontent = Jwts.parser().decryptWith(key).build().parseEncryptedContent(jwe).getPayload();\n\nassert message.equals(new String(content, StandardCharsets.UTF_8));\n----\n\n+++\u003ca name=\"example-jwe-rsa\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Encrypted with RSA\n\nThis is an example showing how to encrypt and decrypt a JWT using RSA cryptography.\n\nBecause RSA cannot encrypt much data, RSA is used to encrypt and decrypt a secure-random key, and that generated key\nin turn is used to actually encrypt the payload as described in the link:jwe-alg-rsa[RSA Key Encryption] section\nabove. As such, RSA Key Algorithms must be paired with an AEAD Encryption Algorithm, as shown below.\n\nIn this example, Bob will encrypt a JWT using Alice's RSA public key to ensure only she may read it.  Alice can then\ndecrypt the JWT using her RSA private key:\n\n[,java]\n----\n// Create a test KeyPair suitable for the desired RSA key algorithm:\nKeyPair pair = Jwts.SIG.RS512.keyPair().build();\n\n// Choose the key algorithm used encrypt the payload key:\nKeyAlgorithm\u003cPublicKey, PrivateKey\u003e alg = Jwts.KEY.RSA_OAEP_256; //or RSA_OAEP or RSA1_5\n// Choose the Encryption Algorithm to encrypt the payload:\nAeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...\n\n// Bob creates the compact JWE with Alice's RSA public key so only she may read it:\nString jwe = Jwts.builder().audience().add(\"Alice\").and()\n    .encryptWith(pair.getPublic(), alg, enc) // \u003c-- Alice's RSA public key\n    .compact();\n\n// Alice receives and decrypts the compact JWE:\nSet\u003cString\u003e audience = Jwts.parser()\n    .decryptWith(pair.getPrivate()) // \u003c-- Alice's RSA private key\n    .build().parseEncryptedClaims(jwe).getPayload().getAudience();\n\nassert audience.contains(\"Alice\");\n----\n\n+++\u003ca name=\"example-jwe-aeskw\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Encrypted with AES Key Wrap\n\nThis is an example showing how to encrypt and decrypt a JWT using AES Key Wrap algorithms.\n\nThese algorithms use AES to encrypt and decrypt a secure-random key, and that generated key in turn is used to actually encrypt\nthe payload as described in the link:jwe-alg-aes[AES Key Encryption] section above. This allows the payload to be\nencrypted with a random short-lived key, reducing material exposure of the potentially longer-lived symmetric secret\nkey.  This approach requires the AES Key Wrap algorithms to be paired with an AEAD content encryption algorithm,\nas shown below.\n\nThe AES GCM Key Wrap algorithms (`A128GCMKW`, `A192GCMKW` and `A256GCMKW`) are preferred - they are faster and more\nefficient than the `A*KW` variants, but they do require JDK 8 or later (or JDK 7 + BouncyCastle).\n\n[,java]\n----\n// Create a test SecretKey suitable for the desired AES Key Wrap algorithm:\nSecretKeyAlgorithm alg = Jwts.KEY.A256GCMKW; //or A192GCMKW, A128GCMKW, A256KW, etc...\nSecretKey key = alg.key().build();\n\n// Chooose the Encryption Algorithm used to encrypt the payload:\nAeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...\n\n// Create the compact JWE:\nString jwe = Jwts.builder().issuer(\"me\").encryptWith(key, alg, enc).compact();\n\n// Parse the compact JWE:\nString issuer = Jwts.parser().decryptWith(key).build()\n    .parseEncryptedClaims(jwe).getPayload().getIssuer();\n\nassert \"me\".equals(issuer);\n----\n\n+++\u003ca name=\"example-jwe-ecdhes\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Encrypted with ECDH-ES\n\nThis is an example showing how to encrypt and decrypt a JWT using Elliptic Curve Diffie-Hellman Ephemeral Static\nKey Agreement (ECDH-ES) algorithms.\n\nThese algorithms use ECDH-ES to encrypt and decrypt a secure-random key, and that\ngenerated key in turn is used to actually encrypt the payload as described in the\nlink:jwe-alg-ecdhes[Elliptic Curve Diffie-Hellman Ephemeral Static Key Agreement] section above. Because of this, ECDH-ES\nKey Algorithms must be paired with an AEAD Encryption Algorithm, as shown below.\n\nIn this example, Bob will encrypt a JWT using Alice's Elliptic Curve public key to ensure only she may read it. +\nAlice can then decrypt the JWT using her Elliptic Curve private key:\n\n[,java]\n----\n// Create a test KeyPair suitable for the desired EC key algorithm:\nKeyPair pair = Jwts.SIG.ES512.keyPair().build();\n\n// Choose the key algorithm used encrypt the payload key:\nKeyAlgorithm\u003cPublicKey, PrivateKey\u003e alg = Jwts.KEY.ECDH_ES_A256KW; //ECDH_ES_A192KW, etc...\n// Choose the Encryption Algorithm to encrypt the payload:\nAeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...\n\n// Bob creates the compact JWE with Alice's EC public key so only she may read it:\nString jwe = Jwts.builder().audience().add(\"Alice\").and()\n    .encryptWith(pair.getPublic(), alg, enc) // \u003c-- Alice's EC public key\n    .compact();\n\n// Alice receives and decrypts the compact JWE:\nSet\u003cString\u003e audience = Jwts.parser()\n    .decryptWith(pair.getPrivate()) // \u003c-- Alice's EC private key\n    .build().parseEncryptedClaims(jwe).getPayload().getAudience();\n\nassert audience.contains(\"Alice\");\n----\n\n+++\u003ca name=\"example-jwe-password\"\u003e++++++\u003c/a\u003e+++\n\n=== JWT Encrypted with a Password\n\nThis is an example showing how to encrypt and decrypt a JWT using Password-based key-derivation algorithms.\n\nThese algorithms use a password to securely derive a random key, and that derived random key in turn is used to actually\nencrypt the payload as described in the link:jwe-alg-pbes2[Password-based Key Encryption] section above. This allows\nthe payload to be encrypted with a random short-lived cryptographically-stronger key, reducing the need to\nexpose the longer-lived (and potentially weaker) password.\n\nThis approach requires the Password-based Key Wrap algorithms to be paired with an AEAD content encryption algorithm,\nas shown below.\n\n[,java]\n----\n//DO NOT use this example password in a real app, it is well-known to password crackers:\nString pw = \"correct horse battery staple\";\nPassword password = Keys.password(pw.toCharArray());\n\n// Choose the desired PBES2 key derivation algorithm:\nKeyAlgorithm\u003cPassword, Password\u003e alg = Jwts.KEY.PBES2_HS512_A256KW; //or PBES2_HS384_A192KW or PBES2_HS256_A128KW\n\n// Optionally choose the number of PBES2 computational iterations to use to derive the key.\n// This is optional - if you do not specify a value, JJWT will automatically choose a value\n// based on your chosen PBES2 algorithm and OWASP PBKDF2 recommendations here:\n// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2\n//\n// If you do specify a value, ensure the iterations are large enough for your desired alg\n//int pbkdf2Iterations = 120000; //for HS512. Needs to be much higher for smaller hash algs.\n\n// Choose the Encryption Algorithm used to encrypt the payload:\nAeadAlgorithm enc = Jwts.ENC.A256GCM; //or A192GCM, A128GCM, A256CBC-HS512, etc...\n\n// Create the compact JWE:\nString jwe = Jwts.builder().issuer(\"me\")\n    // Optional work factor is specified in the header:\n    //.header().pbes2Count(pbkdf2Iterations)).and()\n    .encryptWith(password, alg, enc)\n    .compact();\n\n// Parse the compact JWE:\nString issuer = Jwts.parser().decryptWith(password)\n    .build().parseEncryptedClaims(jwe).getPayload().getIssuer();\n\nassert \"me\".equals(issuer);\n----\n\n+++\u003ca name=\"example-jwk-secret\"\u003e++++++\u003c/a\u003e+++\n\n=== SecretKey JWK\n\nExample creating and parsing a secret JWK:\n\n[,java]\n----\nSecretKey key = Jwts.SIG.HS512.key().build(); // or HS384 or HS256\nSecretJwk jwk = Jwks.builder().key(key).idFromThumbprint().build();\n\nassert jwk.getId().equals(jwk.thumbprint().toString());\nassert key.equals(jwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(jwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof SecretJwk;\nassert jwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-rsapub\"\u003e++++++\u003c/a\u003e+++\n\n=== RSA Public JWK\n\nExample creating and parsing an RSA Public JWK:\n\n[,java]\n----\nRSAPublicKey key = (RSAPublicKey)Jwts.SIG.RS512.keyPair().build().getPublic();\nRsaPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build();\n\nassert jwk.getId().equals(jwk.thumbprint().toString());\nassert key.equals(jwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(jwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof RsaPublicJwk;\nassert jwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-rsapriv\"\u003e++++++\u003c/a\u003e+++\n\n=== RSA Private JWK\n\nExample creating and parsing an RSA Private JWK:\n\n[,java]\n----\nKeyPair pair = Jwts.SIG.RS512.keyPair().build();\nRSAPublicKey pubKey = (RSAPublicKey) pair.getPublic();\nRSAPrivateKey privKey = (RSAPrivateKey) pair.getPrivate();\n\nRsaPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build();\nRsaPublicJwk pubJwk = privJwk.toPublicJwk();\n\nassert privJwk.getId().equals(privJwk.thumbprint().toString());\nassert pubJwk.getId().equals(pubJwk.thumbprint().toString());\nassert privKey.equals(privJwk.toKey());\nassert pubKey.equals(pubJwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(privJwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof RsaPrivateJwk;\nassert privJwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-ecpub\"\u003e++++++\u003c/a\u003e+++\n\n=== Elliptic Curve Public JWK\n\nExample creating and parsing an Elliptic Curve Public JWK:\n\n[,java]\n----\nECPublicKey key = (ECPublicKey) Jwts.SIG.ES512.keyPair().build().getPublic();\nEcPublicJwk jwk = Jwks.builder().key(key).idFromThumbprint().build();\n\nassert jwk.getId().equals(jwk.thumbprint().toString());\nassert key.equals(jwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(jwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof EcPublicJwk;\nassert jwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-ecpriv\"\u003e++++++\u003c/a\u003e+++\n\n=== Elliptic Curve Private JWK\n\nExample creating and parsing an Elliptic Curve Private JWK:\n\n[,java]\n----\nKeyPair pair = Jwts.SIG.ES512.keyPair().build();\nECPublicKey pubKey = (ECPublicKey) pair.getPublic();\nECPrivateKey privKey = (ECPrivateKey) pair.getPrivate();\n\nEcPrivateJwk privJwk = Jwks.builder().key(privKey).idFromThumbprint().build();\nEcPublicJwk pubJwk = privJwk.toPublicJwk();\n\nassert privJwk.getId().equals(privJwk.thumbprint().toString());\nassert pubJwk.getId().equals(pubJwk.thumbprint().toString());\nassert privKey.equals(privJwk.toKey());\nassert pubKey.equals(pubJwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(privJwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof EcPrivateJwk;\nassert privJwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-edpub\"\u003e++++++\u003c/a\u003e+++\n\n=== Edwards Elliptic Curve Public JWK\n\nExample creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, X448) Public JWK\n(the JWT https://www.rfc-editor.org/rfc/rfc8037[RFC 8037] specification calls these `Octet` keys, hence the\n`OctetPublicJwk` interface names):\n\n[,java]\n----\nPublicKey key = Jwks.CRV.Ed25519.keyPair().build().getPublic(); // or Ed448, X25519, X448\nOctetPublicJwk\u003cPublicKey\u003e jwk = builder().octetKey(key).idFromThumbprint().build();\n\nassert jwk.getId().equals(jwk.thumbprint().toString());\nassert key.equals(jwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(jwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof OctetPublicJwk;\nassert jwk.equals(parsed);\n----\n\n+++\u003ca name=\"example-jwk-edpriv\"\u003e++++++\u003c/a\u003e+++\n\n=== Edwards Elliptic Curve Private JWK\n\nExample creating and parsing an Edwards Elliptic Curve (Ed25519, Ed448, X25519, X448) Private JWK\n(the JWT https://www.rfc-editor.org/rfc/rfc8037[RFC 8037] specification calls these `Octet` keys, hence the\n`OctetPrivateJwk` and `OctetPublicJwk` interface names):\n\n[,java]\n----\nKeyPair pair = Jwks.CRV.Ed448.keyPair().build(); // or Ed25519, X25519, X448\nPublicKey pubKey = pair.getPublic();\nPrivateKey privKey = pair.getPrivate();\n\nOctetPrivateJwk\u003cPrivateKey, PublicKey\u003e privJwk = builder().octetKey(privKey).idFromThumbprint().build();\nOctetPublicJwk\u003cPublicKey\u003e pubJwk = privJwk.toPublicJwk();\n\nassert privJwk.getId().equals(privJwk.thumbprint().toString());\nassert pubJwk.getId().equals(pubJwk.thumbprint().toString());\nassert privKey.equals(privJwk.toKey());\nassert pubKey.equals(pubJwk.toKey());\n\nbyte[] utf8Bytes = new JacksonSerializer().serialize(privJwk); // or GsonSerializer(), etc\nString jwkJson = new String(utf8Bytes, StandardCharsets.UTF_8);\nJwk\u003c?\u003e parsed = Jwks.parser().build().parse(jwkJson);\n\nassert parsed instanceof OctetPrivateJwk;\nassert privJwk.equals(parsed);\n----\n\n== Learn More\n\n* https://web.archive.org/web/20230427122653/https://stormpath.com/blog/jjwt-how-it-works-why[JSON Web Token for Java and Android]\n* https://web.archive.org/web/20230426235608/https://stormpath.com/blog/jwt-java-create-verify[How to Create and Verify JWTs in Java]\n* https://web.archive.org/web/20230428094039/https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage[Where to Store Your JWTs - Cookies vs HTML5 Web Storage]\n* https://web.archive.org/web/20230428184004/https://stormpath.com/blog/jwt-the-right-way[Use JWT the Right Way!]\n* https://web.archive.org/web/20230427151310/https://stormpath.com/blog/token-auth-for-java[Token Authentication for Java Applications]\n* xref:CHANGELOG.adoc[JJWT Changelog]\n\n== Author\n\nMaintained by Les Hazlewood \u0026 the extended Java community :heart:\n\n+++\u003ca name=\"license\"\u003e++++++\u003c/a\u003e+++\n\n== License\n\nThis project is open-source via the http://www.apache.org/licenses/LICENSE-2.0[Apache 2.0 License].\n","funding_links":[],"categories":["Java","Projects","Web Framework Hardening","Java 程序设计","安全","项目","Libraries"],"sub_categories":["Security","网络服务_其他","安全","Java"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwtk%2Fjjwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwtk%2Fjjwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwtk%2Fjjwt/lists"}