[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-4087":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":46,"readmeContent":47,"aiSummary":48,"trendingCount":16,"starSnapshotCount":16,"syncStatus":49,"lastSyncTime":50,"discoverSource":51},4087,"jjwt","jwtk\u002Fjjwt","jwtk","Java JWT: JSON Web Token for Java and Android","",null,"Java",11083,1385,269,30,0,5,10,31,15,44.43,"Apache License 2.0",false,"master",true,[27,28,29,30,5,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"hacktoberfest","jackson","java","java-jwt","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","2026-06-12 02:00:58",":doctype: book\n= Java JWT: JSON Web Token for Java and Android\n:project-version: 0.13.0\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\u002F\u002F 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:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg?branch=master[Build Status,link=https:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Factions\u002Fworkflows\u002Fci.yml?query=branch%3Amaster]\nimage:https:\u002F\u002Fcoveralls.io\u002Frepos\u002Fgithub\u002Fjwtk\u002Fjjwt\u002Fbadge.svg?branch=master[Coverage Status,link=https:\u002F\u002Fcoveralls.io\u002Fgithub\u002Fjwtk\u002Fjjwt?branch=master]\nimage:https:\u002F\u002Fsnyk-widget.herokuapp.com\u002Fbadge\u002Fmvn\u002Fio.jsonwebtoken\u002Fjjwt-root\u002Fbadge.svg[Vuln score,link=https:\u002F\u002Fsnyk-widget.herokuapp.com\u002Fbadge\u002Fmvn\u002Fio.jsonwebtoken\u002Fjjwt-root\u002Fbadge.svg]\nimage:https:\u002F\u002Fsnyk.io\u002Ftest\u002Fgithub\u002Fjwtk\u002Fjjwt\u002Fbadge.svg[Known Vulns,link=https:\u002F\u002Fsnyk.io\u002Ftest\u002Fgithub\u002Fjwtk\u002Fjjwt\u002Fbadge.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:\u002F\u002Fdatatracker.ietf.org\u002Fwg\u002Fjose\u002Fdocuments\u002F[JOSE Working Group] RFC specifications:\n\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519[RFC 7519: JSON Web Token (JWT)]\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7515[RFC 7515: JSON Web Signature (JWS)]\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7516[RFC 7516: JSON Web Encryption (JWE)]\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7517[RFC 7517: JSON Web Key (JWK)]\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518[RFC 7518: JSON Web Algorithms (JWA)]\n* https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7638.html[RFC 7638: JSON Web Key Thumbprint]\n* https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9278.html[RFC 9278: JSON Web Key Thumbprint URI]\n* https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7797.html[RFC 7797: JWS Unencoded Payload Option]\n* https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc8037[RFC 8037: Edwards Curve algorithms and JWKs]\n\nIt was created by https:\u002F\u002Fgithub.com\u002Flhazlewood[Les Hazlewood]\nand is supported and maintained by a https:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fgraphs\u002Fcontributors[community] of contributors.\n\nJJWT is open source under the terms of the http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0[Apache 2.0 License].\n\n====\n[discrete]\n== Table of Contents\n---\ntoc::[]\n====\n\n+++\u003Ca name=\"features\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFluent_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:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7518.html#section-5.2.3[AES_128_CBC_HMAC_SHA_256] authenticated encryption algorithm\n\n| `A192CBC-HS384`\n| https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7518.html#section-5.2.4[AES_192_CBC_HMAC_SHA_384] authenticated encryption algorithm\n\n| `A256CBC-HS512`\n| https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7518.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\">++++++\u003C\u002Fa>+++\n\n=== Currently Unsupported Features\n\n* https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7515#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\">++++++\u003C\u002Fa>+++\n\n== Community\n\n+++\u003Ca name=\"help\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions\u002Fnew?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\u002For codebase.  If you have a\nusability question, instead please\nhttps:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions\u002Fnew?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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions[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\">++++++\u003C\u002Fa>+++\n\n=== Contributing\n\n+++\u003Ca name=\"contributing-pull-requests\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions[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:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions[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\">++++++\u003C\u002Fa>+++\n\n==== Help Wanted\n\nIf you would like to help, but don't know where to start, please visit the\nhttps:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Flabels\u002Fhelp%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>>. Feel free\nto https:\u002F\u002Fgithub.com\u002Fjwtk\u002Fjjwt\u002Fdiscussions[discuss or ask questions first] if you're not sure. :)\n\n+++\u003Ca name=\"overview\">++++++\u003C\u002Fa>+++\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\u002Fvalue 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\u002Fvalue 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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7515[JWS]) or encrypted (making it a\nhttps:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7516[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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAuthenticated_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\">++++++\u003C\u002Fa>+++\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>> or an\n\u003C\u003Cinstall-android,Android project>>.\n\n+++\u003Ca name=\"install-jdk\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\n\n==== Maven\n\n[,xml,subs=\"+attributes\"]\n----\n\u003Cdependency>\n    \u003CgroupId>io.jsonwebtoken\u003C\u002FgroupId>\n    \u003CartifactId>jjwt-api\u003C\u002FartifactId>\n    \u003Cversion>{project-version}\u003C\u002Fversion>\n\u003C\u002Fdependency>\n\u003Cdependency>\n    \u003CgroupId>io.jsonwebtoken\u003C\u002FgroupId>\n    \u003CartifactId>jjwt-impl\u003C\u002FartifactId>\n    \u003Cversion>{project-version}\u003C\u002Fversion>\n    \u003Cscope>runtime\u003C\u002Fscope>\n\u003C\u002Fdependency>\n\u003Cdependency>\n    \u003CgroupId>io.jsonwebtoken\u003C\u002FgroupId>\n    \u003CartifactId>jjwt-jackson\u003C\u002FartifactId> \u003C!-- or jjwt-gson if Gson is preferred -->\n    \u003Cversion>{project-version}\u003C\u002Fversion>\n    \u003Cscope>runtime\u003C\u002Fscope>\n\u003C\u002Fdependency>\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>\n    \u003CgroupId>org.bouncycastle\u003C\u002FgroupId>\n    \u003CartifactId>bcprov-jdk18on\u003C\u002FartifactId> or bcprov-jdk15to18 on JDK 7\n    \u003Cversion>1.76\u003C\u002Fversion>\n    \u003Cscope>runtime\u003C\u002Fscope>\n\u003C\u002Fdependency>\n-->\n----\n\n+++\u003Ca name=\"install-jdk-gradle\">++++++\u003C\u002Fa>+++\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}' \u002F\u002F or 'io.jsonwebtoken:jjwt-gson:{project-version}' for gson\n    \u002F*\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    *\u002F\n    \u002F\u002F runtimeOnly 'org.bouncycastle:bcprov-jdk18on:1.76' \u002F\u002F or bcprov-jdk15to18 on JDK 7\n}\n----\n\n+++\u003Ca name=\"install-android\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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') \u002F\u002Fprovided by Android natively\n    }\n    \u002F*\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    *\u002F\n    \u002F\u002Fimplementation('org.bouncycastle:bcprov-jdk18on:1.76') \u002F\u002F or bcprov-jdk15to18 for JDK 7\n}\n----\n\n+++\u003Ca name=\"install-android-proguard\">++++++\u003C\u002Fa>+++\n\n==== Proguard\n\nYou can use the following https:\u002F\u002Fdeveloper.android.com\u002Fstudio\u002Fbuild\u002Fshrink-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\">++++++\u003C\u002Fa>+++\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>> 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\") \u002F\u002Fremove old\u002Flegacy Android-provided BC provider\n            Security.addProvider(BouncyCastleProvider()) \u002F\u002F add 'real'\u002Fcorrect BC provider\n        }\n    }\n\n    \u002F\u002F ... etc ...\n}\n----\n\n+++\u003Ca name=\"install-understandingdependencies\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\n\n== Quickstart\n\nMost complexity is hidden behind a convenient and readable builder-based\nhttp:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFluent_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 javax.crypto.SecretKey;\n\n\u002F\u002F We need a signing key, so we'll create one just for this example. Usually\n\u002F\u002F 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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#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    \u002F\u002FOK, we can trust this JWT\n\n} catch (JwtException e) {\n\n    \u002F\u002Fdon'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\">++++++\u003C\u002Fa>+++\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>> as desired.\n. Call builder methods to set the payload \u003C\u003Cjwt-content,content>> or \u003C\u003Cjwt-claims,claims>>.\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()                     \u002F\u002F (1)\n\n    .header()                                   \u002F\u002F (2) optional\n        .keyId(\"aKeyId\")\n        .and()\n\n    .subject(\"Bob\")                             \u002F\u002F (3) JSON Claims, or\n    \u002F\u002F.content(aByteArray, \"text\u002Fplain\")        \u002F\u002F     any byte[] content, with media type\n\n    .signWith(signingKey)                       \u002F\u002F (4) if signing, or\n    \u002F\u002F.encryptWith(key, keyAlg, encryptionAlg)  \u002F\u002F     if encrypting\n\n    .compact();                                 \u002F\u002F (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>> or \u003C\u003Cjwe,encrypting>> the JWT before calling the `compact()` builder method.\n====\n\n+++\u003Ca name=\"jwt-header\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-header\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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\u002For multiple individual\nheader parameters (name\u002Fvalue pairs).\n\n+++\u003Ca name=\"jwt-header-builder\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-header-instance\">++++++\u003C\u002Fa>+++\n\u002F\u002F legacy anchors for old links\n\n==== JwtBuilder Header\n\nThe easiest and recommended way to set one or more JWT header parameters (name\u002Fvalue 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()                        \u002F\u002F \u003C----\n        .keyId(\"aKeyId\")\n        .x509Url(aUri)\n        .add(\"someName\", anyValue)\n        .add(mapValues)\n        \u002F\u002F ... etc ...\n        .and()                      \u002F\u002F go back to the JwtBuilder\n\n    .subject(\"Joe\")                 \u002F\u002F resume JwtBuilder calls...\n    \u002F\u002F ... 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\u002Fsetter 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\">++++++\u003C\u002Fa>+++\n\n===== Custom Header Parameters\n\nIn addition to type-safe builder methods for standard header parameters, `JwtBuilder.header()` can also support\narbitrary name\u002Fvalue pairs via the `add` method:\n\n[,java]\n----\nJwts.builder()\n\n    .header()\n        .add(\"aHeaderName\", aValue)\n        \u002F\u002F ... etc ...\n        .and() \u002F\u002F return to the JwtBuilder\n\n\u002F\u002F ... etc ...\n----\n\n+++\u003Ca name=\"jwt-header-map\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-header-map\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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        \u002F\u002F ... etc ...\n        .and() \u002F\u002F return to the JwtBuilder\n\n\u002F\u002F ... 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        \u002F\u002F ... etc ...\n\n        .build()  \u002F\u002F \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\u002F\u002F perhaps somewhere in application configuration:\nHeader commonHeaders = Jwts.header()\n    .issuer(\"My Company\")\n    \u002F\u002F ... etc ...\n    .build();\n\n\u002F\u002F --------------------------------\n\n\u002F\u002F somewhere else during actual Jwt construction:\nString jwt = Jwts.builder()\n\n    .header()\n        .add(commonHeaders)                   \u002F\u002F \u003C----\n        .add(\"specificHeader\", specificValue) \u002F\u002F jwt-specific headers...\n        .and()\n\n    .subject(\"whatever\")\n    \u002F\u002F ... etc ...\n    .compact();\n----\n\n+++\u003Ca name=\"jwt-payload\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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\u002Fplain\") \u002F\u002F \u003C---\n\n    \u002F\u002F ... 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:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7515.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\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-claims\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-claims-standard\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.1[`iss` (Issuer) Claim]\n* `subject`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.2[`sub` (Subject) Claim]\n* `audience`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.3[`aud` (Audience) Claim]\n* `expiration`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.4[`exp` (Expiration Time) Claim]\n* `notBefore`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.5[`nbf` (Not Before) Claim]\n* `issuedAt`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#section-4.1.6[`iat` (Issued At) Claim]\n* `id`: sets the https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7519#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) \u002F\u002Fa java.util.Date\n    .notBefore(notBefore) \u002F\u002Fa java.util.Date\n    .issuedAt(new Date()) \u002F\u002F for example, now\n    .id(UUID.randomUUID().toString()) \u002F\u002Fjust an example id\n\n    \u002F\u002F\u002F ... etc ...\n----\n\n+++\u003Ca name=\"jwt-claims-custom\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-claims-custom\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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    \u002F\u002F ... 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\u002Fvalue pair.\n\nObviously, you do not need to call `claim` for any \u003C\u003Cjws-create-claims-standard,standard claim name>>, 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\">++++++\u003C\u002Fa>+++\n\u002F\u002F legacy anchors for old links\n+++\u003Ca name=\"jwt-claims-instance\">++++++\u003C\u002Fa>+++\n+++\u003Ca name=\"jwt-claims-map\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-claims-map\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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,?> claims = getMyClaimsMap(); \u002F\u002Fimplement me\n\nString jws = Jwts.builder()\n\n    .claims(claims)\n\n    \u002F\u002F ... etc ...\n----\n\n+++\u003Ca name=\"jwt-compression\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-create-compression\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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>> section to see how to compress and decompress JWTs.\n\n+++\u003Ca name=\"jwt-read\">++++++\u003C\u002Fa>+++\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>> or \u003C\u003Cjwe,encrypted>> 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\u002Fcatch block in case parsing, signature verification, or decryption fails.\n\nFor example:\n\n[,java]\n----\nJwt\u003C?,?> jwt;\n\ntry {\n    jwt = Jwts.parser()     \u002F\u002F (1)\n\n    .keyLocator(keyLocator) \u002F\u002F (2) dynamically locate signing or encryption keys\n    \u002F\u002F.verifyWith(key)      \u002F\u002F     or a constant key used to verify all signed JWTs\n    \u002F\u002F.decryptWith(key)     \u002F\u002F     or a constant key used to decrypt all encrypted JWTs\n\n    .build()                \u002F\u002F (3)\n\n    .parse(compact);        \u002F\u002F (4) or parseSignedClaims, parseEncryptedClaims, parseSignedContent, etc\n\n    \u002F\u002F we can safely trust the JWT\n\ncatch (JwtException ex) {   \u002F\u002F (5)\n\n    \u002F\u002F 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>` or `Jwe\u003Cbyte[]>`\ninstead of a generic `Jwt\u003C?,?>` instance.\n====\n\n+++\u003Ca name=\"jwt-read-key\">++++++\u003C\u002Fa>+++\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) \u002F\u002F \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) \u002F\u002F \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) \u002F\u002F \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) \u002F\u002F \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\u002Fprivate 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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\n\n==== Key Locator\n\nIf you need to support dynamic key lookup when encountering JWTs, you'll need to implement\nthe `Locator\u003CKey>` interface and specify an instance on the `JwtParserBuilder` via the `keyLocator` method. For\nexample:\n\n[,java]\n----\nLocator\u003CKey> keyLocator = getMyKeyLocator();\n\nJwts.parser()\n\n    .keyLocator(keyLocator) \u002F\u002F \u003C----\n\n    .build()\n    \u002F\u002F ... etc ...\n----\n\nA `Locator\u003CKey>` 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> {\n\n    @Override\n    public Key locate(ProtectedHeader\u003C?> header) { \u002F\u002F a JwsHeader or JweHeader\n        \u002F\u002F 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\">++++++\u003C\u002Fa>+++\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(); \u002F\u002F or getEncryptionKey() for JWE\n\nString keyId = getKeyId(key); \u002F\u002Fany mechanism you have to associate a key with an ID is fine\n\nString jws = Jwts.builder()\n\n    .header().keyId(keyId).and()               \u002F\u002F \u003C--- add `kid` header\n\n    .signWith(key)                             \u002F\u002F for JWS\n    \u002F\u002F.encryptWith(key, keyAlg, encryptionAlg) \u002F\u002F for JWE\n    .compact();\n----\n\nThen during parsing, your `Locator\u003CKey>` 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> {\n\n    @Override\n    public Key locate(ProtectedHeader\u003C?> header) { \u002F\u002F both JwsHeader and JweHeader extend ProtectedHeader\n\n        \u002F\u002Finspect the header, lookup and return the verification key\n        String keyId = header.getKeyId(); \u002F\u002For any other parameter that you need to inspect\n\n        Key key = lookupKey(keyId); \u002F\u002Fimplement 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>` 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?>)` method\nin favor of two respective `locate(JwsHeader)` and `locate(JweHeader)` methods:\n\n[,java]\n----\npublic class MyKeyLocator extends LocatorAdapter\u003CKey> {\n\n    @Override\n    public Key locate(JwsHeader header) {\n        String keyId = header.getKeyId(); \u002F\u002For any other parameter that you need to inspect\n        return lookupSignatureVerificationKey(keyId); \u002F\u002Fimplement me\n    }\n\n    @Override\n    public Key locate(JweHeader header) {\n        String keyId = header.getKeyId(); \u002F\u002For any other parameter\u002F\u002F that you need to inspect\n        return lookupDecryptionKey(keyId); \u002F\u002Fimplement 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?>)`), 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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fjava\u002Fjavase\u002F17\u002Fsecurity\u002Fhowtoimplaprovider.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:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fjava\u002Fjavase\u002F17\u002Fdocs\u002Fapi\u002Fjava.base\u002Fjava\u002Fsecurity\u002FSecurity.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?> header) {\n\n    PrivateKey \u002F* or SecretKey *\u002F key = findKey(header); \u002F\u002F implement me\n\n    Provider keySpecificProvider = findKeyProvider(key); \u002F\u002F implement me\n    if (keySpecificProvider != null) {\n        \u002F\u002F Ensure the key-specific provider (e.g. for PKCS11 or HSM) will be used\n        \u002F\u002F during decryption with the KeyAlgorithm in the JWE 'alg' header\n        return Keys.builder(key).provider(keySpecificProvider).build();\n    }\n\n    \u002F\u002F otherwise default provider is fine:\n    return key;\n}\n----\n\n+++\u003Ca name=\"jwt-read-claims\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-read-claims\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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\")\u002F* etc... *\u002F.build().parse(s);\n} catch (InvalidClaimException ice) {\n    \u002F\u002F 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\")\u002F* etc... *\u002F.build().parse(s);\n} catch(MissingClaimException mce) {\n    \u002F\u002F the parsed JWT did not have the sub claim\n} catch(IncorrectClaimException ice) {\n    \u002F\u002F 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\")\u002F* etc... *\u002F.build().parse(s);\n} catch(InvalidClaimException ice) {\n    \u002F\u002F 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\u002For JavaDoc for a full list of the various `require`* methods you may use\nfor claims assertions.\n\n+++\u003Ca name=\"jwt-read-clock\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-read-clock\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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; \u002F\u002F3 minutes\n\nJwts.parser()\n\n    .clockSkewSeconds(seconds) \u002F\u002F \u003C----\n\n    \u002F\u002F ... 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\">++++++\u003C\u002Fa>++++++\u003Ca name=\"jws-read-clock-custom\">++++++\u003C\u002Fa>+++\n\u002F\u002F 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) \u002F\u002F... 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\">++++++\u003C\u002Fa>+++\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>> section below to see how to decompress JWTs during parsing.\n\n+++\u003Ca name=\"jws\">++++++\u003C\u002Fa>+++\n\n== Signed JWTs\n\nThe JWT specification provides for the ability to\nhttps:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDigital_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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518#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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518#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\">++++++\u003C\u002Fa>+++\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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518#section-3.3[3.3] and https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518#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 >= 2048 bits.\n\n+++\u003Ca name=\"jws-key-ecdsa\">++++++\u003C\u002Fa>+++\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:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7518#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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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\">++++++\u003C\u002Fa>+++\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(); \u002F\u002For 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>>, 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\">++++++\u003C\u002Fa>+++\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(); \u002F\u002For 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\u002Fverify 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>> section to see how to enable BouncyCastle.  All other algorithms are\nnatively supported by the JDK.\n====\n\n+++\u003Ca name=\"jws-create\">++++++\u003C\u002Fa>+++\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() \u002F\u002F (1)\n\n    .subject(\"Bob\")         \u002F\u002F (2)\n\n    .signWith(key)          \u002F\u002F (3) \u003C---\n\n    .compact();             \u002F\u002F (4)\n----\n\n+++\u003Ca name=\"jws-create-key\">++++++\u003C\u002Fa>+++\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   \u002F\u002F ... etc ...\n\n   .signWith(key) \u002F\u002F \u003C---\n\n   .compact();\n----\n\nFo","JJWT 是一个用于 Java 和 Android 的 JSON Web Token (JWT) 库。它提供了创建和验证 JWT 以及 JSON Web Keys (JWK) 的功能，完全基于 JOSE 工作组的 RFC 规范实现。JJWT 支持 Java 7 及以上版本，并且在 Android 平台上也能正常工作。该库具有自动的安全最佳实践和断言、易于学习和使用的 API 以及流畅的接口设计，非常适合 IDE 自动补全，从而加快开发速度。适用于需要安全地传输信息的应用场景，如身份验证和授权等。",2,"2026-06-11 02:58:21","top_language"]