{"id":13409041,"url":"https://github.com/dvsekhvalnov/jose-jwt","last_synced_at":"2025-05-13T16:06:47.523Z","repository":{"id":13912722,"uuid":"16611778","full_name":"dvsekhvalnov/jose-jwt","owner":"dvsekhvalnov","description":"Ultimate Javascript Object Signing and Encryption (JOSE), JSON Web Token (JWT) and Json Web Keys (JWK) Implementation for .NET and .NET Core","archived":false,"fork":false,"pushed_at":"2025-01-23T16:19:52.000Z","size":36412,"stargazers_count":966,"open_issues_count":38,"forks_count":185,"subscribers_count":44,"default_branch":"master","last_synced_at":"2025-04-09T22:06:56.394Z","etag":null,"topics":["encryption","federation","fips","jose","json","jwa","jwe","jwk","jws","jwt","jwt-authentication","jwt-token","netcore","oauth2","oidc","openid","openidconnect","security","signature"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dvsekhvalnov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-02-07T10:44:03.000Z","updated_at":"2025-04-09T08:28:02.000Z","dependencies_parsed_at":"2024-04-01T10:29:44.649Z","dependency_job_id":"9d72ce8f-affd-402e-8d88-13eceef7f7df","html_url":"https://github.com/dvsekhvalnov/jose-jwt","commit_stats":{"total_commits":522,"total_committers":34,"mean_commits":"15.352941176470589","dds":0.5517241379310345,"last_synced_commit":"44d2a08b2ba4329df4445b9dab302743f345684f"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvsekhvalnov%2Fjose-jwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvsekhvalnov%2Fjose-jwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvsekhvalnov%2Fjose-jwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dvsekhvalnov%2Fjose-jwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dvsekhvalnov","download_url":"https://codeload.github.com/dvsekhvalnov/jose-jwt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250513380,"owners_count":21443200,"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":["encryption","federation","fips","jose","json","jwa","jwe","jwk","jws","jwt","jwt-authentication","jwt-token","netcore","oauth2","oidc","openid","openidconnect","security","signature"],"created_at":"2024-07-30T20:00:57.507Z","updated_at":"2025-04-23T20:44:08.252Z","avatar_url":"https://github.com/dvsekhvalnov.png","language":"C#","funding_links":[],"categories":["Frameworks, Libraries and Tools","JWT Libraries","C# #","Security","框架, 库和工具","Libraries"],"sub_categories":["Security","C#","安全",".Net"],"readme":"# Ultimate Javascript Object Signing and Encryption (JOSE), JSON Web Token (JWT), JSON Web Encryption (JWE) and JSON Web Keys (JWK) Implementation for .NET and .NET Core\r\n\r\nMinimallistic zero-dependency library for generating, decoding and encryption [JSON Web Tokens](http://tools.ietf.org/html/draft-jones-json-web-token-10). Supports full suite\r\nof [JSON Web Algorithms](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31) and [Json Web Keys](https://datatracker.ietf.org/doc/html/rfc7517). JSON parsing agnostic, can plug any desired JSON processing library.\r\nExtensively tested for compatibility with [jose.4.j](https://bitbucket.org/b_c/jose4j/wiki/Home), [Nimbus-JOSE-JWT](https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home) and [json-jwt](https://github.com/nov/json-jwt) libraries.\r\nJWE JSON Serialization cross-tested with [JWCrypto](https://github.com/latchset/jwcrypto/).\r\n\r\n## FIPS compliance ##\r\nLibrary is fully FIPS compliant since v2.1\r\n\r\n## Which version?\r\n- v5.1.1 Maintenence release, improved memory allocation for deflated tokens (see https://github.com/dvsekhvalnov/jose-jwt/issues/258, https://github.com/dvsekhvalnov/jose-jwt/issues/257)\r\n\r\n- v5.1 support for experimental algorithms RSA-OAEP-384, RSA-OAEP-512 and forced strict AES-GCM to avoid trancated tags (see https://github.com/dotnet/runtime/issues/71366)\r\n\r\n- v5.0 brings Linux, OSX and FreeBSD compatibility for [ECDH encryption](#ecdh-es-and-ecdh-es-with-aes-key-wrap-key-management-family-of-algorithms) as long as managed `ECDsa` keys support. Fixes cross compatibility issues with encryption over NIST P-384, P-521 curves. And introduces new [security fixes and controls](#customizing-compression).\r\n\r\n- v4.1 added additional capabilities to manage runtime avaliable alg suite, see [Customizing library for security](#customizing-library-for-security). And also introduced default max limits for `PBKDF2` (`PBES2-*`) max iterations according to [OWASP PBKDF2 Recomendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2).\r\n\r\n- v4.0 introduced Json Web Key (JWK), [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517) support. Latest stable. All new features will most likely appear based on given version.\r\n\r\n- v3.2 dropped `Newtonsoft.Json` support in favor of `System.Text.Json` on `netstandard2.1`\r\n\r\n- v3.1 introduced JWE JSON Serialization defined in [RFC 7516](https://tools.ietf.org/html/rfc7516)\r\n\r\n- v3.0 and above additionally targets `netstandard2.1` to leverage better .net crypto support on *\\*nix* systems and enable more supported algorithms.\r\n\r\n- v2.1 and above added extra features support for .NET461+ and coming with 3 version of binaries (`NET4`, `NET461` and `netstandard1.4`).\r\n\r\n- v2.0 and above is .NET Core compatible and aimed to support both .NET framework (`NET40`) and .NET Core (`netstandard1.4`) runtimes.\r\n\r\n- v1.9 is built against .NET framework only and should be compatible with `NET40` and above. The version is not actively maintained anymore except critical bug fixes.\r\n\r\n- WinRT compatible version (Windows 8.1 and Windows Phone 8.1) is avaliable as standalone project here: [jose-rt](https://github.com/dvsekhvalnov/jose-rt).\r\n\r\n- PCLCrypto based experimental project living up here: [jose-pcl](https://github.com/dvsekhvalnov/jose-pcl).\r\n\r\n## Important upgrade notes\r\n\u003e :warning: **v4 -\u003e v5**:\r\n\u003e - JWK EC keys now bridges to `ECDsa` by default instead of `CngKey` on .net 4.7.2+ and netstandard2.1+\r\n\u003e - `Jwk.ToJson()` / `Jwk.FromJson()` now defaults to `JWT.DefaultSettings.JsonMapper` if not provided explicitly.\r\n\u003e - Deflate decompression is limited to 250Kb by default. Check out [customization section](#customizing-compression) if need more.\r\n\r\n\r\n\u003e :warning: **v3.0 -\u003e v3.1 stricter argument validation extraHeaders argument**\r\n\u003e\r\n\u003e In 3.1 and above an attempt to override `enc` or `alg` header values in `extraHeaders` will throw `ArgumentException`.\r\n\r\n\u003e :warning: **v2 -\u003e v3 update public sdk changes**\r\n\u003e\r\n\u003e Moved:\r\n\u003e - `Security.Cryptography.EccKey` to `Jose.keys.EccKey`\r\n\u003e - `Security.Cryptography.RsaKey` to `Jose.keys.RsaKey`\r\n\r\n## OS cross compatibility\r\n| .Net version | Windows | Linux | Mac OS | FreeBSD v14 |\r\n| --- | :---: | :---: | :---: | :---: |\r\n| netcoreapp2.1 | ✅ | ✅ |    |   |\r\n| netcoreapp3.1 | ✅ | ✅ | ✅ |   |\r\n| net 8.0       | ✅ | ✅ | ✅ | ✅ |\r\n| net 5.0       | ✅ | ✅ | ✅ |    |\r\n| net 4.7       | ✅ |   |    |    |\r\n| net 4.6       | ✅ |   |    |    |\r\n| net 4.0       | ✅ |   |    |    |\r\n\r\n## Foreword\r\nOriginally forked from https://github.com/johnsheehan/jwt . Almost re-written from scratch to support JWT encryption capabilities and unified interface for encoding/decoding/encryption\r\nand other features.\r\nMoved to separate project in February 2014.\r\n\r\nAES Key Wrap implementation ideas and test data from http://www.cryptofreak.org/projects/rfc3394/ by Jay Miller\r\n\r\n## Supported JWA algorithms\r\n\r\n### CLR\r\n\r\n**Signing**\r\n- HMAC signatures with HS256, HS384 and HS512.\r\n- ECDSA signatures with ES256, ES384 and ES512.\r\n- RSASSA-PKCS1-V1_5 signatures with RS256, RS384 and RS512.\r\n- RSASSA-PSS signatures (probabilistic signature scheme with appendix) with PS256, PS384 and PS512.\r\n- NONE (unprotected) plain text algorithm without integrity protection\r\n\r\n**Encryption**\r\n- RSAES OAEP 256, 384, 512 (using SHA-256, 384, 512 and MGF1 with SHA-256, 384, 512) encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- RSAES OAEP (using SHA-1 and MGF1 with SHA-1) encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- RSAES-PKCS1-V1_5 encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- Direct symmetric key encryption with pre-shared key A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM and A256GCM\r\n- A128KW, A192KW, A256KW encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- A128GCMKW, A192GCMKW, A256GCMKW encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- ECDH-ES\u003csup\u003e\\*\u003c/sup\u003e with A128CBC-HS256, A128GCM, A192GCM, A256GCM\r\n- ECDH-ES+A128KW\u003csup\u003e\\*\u003c/sup\u003e, ECDH-ES+A192KW\u003csup\u003e\\*\u003c/sup\u003e, ECDH-ES+A256KW\u003csup\u003e\\*\u003c/sup\u003e with A128CBC-HS256, A128GCM, A192GCM, A256GCM\r\n- PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n\r\n**Compression**\r\n\r\n- DEFLATE compression\r\n\r\n### CORECLR\r\n\r\n**Signing**\r\n- HMAC signatures with HS256, HS384 and HS512.\r\n- ECDSA signatures with ES256, ES384 and ES512.\r\n- RSASSA-PKCS1-V1_5 signatures with RS256, RS384 and RS512.\r\n- NONE (unprotected) plain text algorithm without integrity protection\r\n\r\n**Encryption**\r\n- RSAES OAEP 256, 384, 512 (using SHA-256, 384, 512 and MGF1 with SHA-256, 384, 512) encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- RSAES OAEP (using SHA-1 and MGF1 with SHA-1) encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- RSAES-PKCS1-V1_5 encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- Direct symmetric key encryption with pre-shared key A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM and A256GCM\r\n- A128KW, A192KW, A256KW encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- A128GCMKW, A192GCMKW, A256GCMKW encryption with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW with A128CBC-HS256, A192CBC-HS384, A256CBC-HS512, A128GCM, A192GCM, A256GCM\r\n- ECDH-ES\u003csup\u003e\\*\u003c/sup\u003e with A128CBC-HS256, A128GCM, A192GCM, A256GCM\r\n- ECDH-ES+A128KW\u003csup\u003e\\*\u003c/sup\u003e, ECDH-ES+A192KW\u003csup\u003e\\*\u003c/sup\u003e, ECDH-ES+A256KW\u003csup\u003e\\*\u003c/sup\u003e with A128CBC-HS256, A128GCM, A192GCM, A256GCM\r\n\r\n**Compression**\r\n\r\n- DEFLATE compression\r\n\r\n## Json Web Key (JWK)\r\n\r\n- RSA, EC, Oct keys\r\n- X509 Chains, SHA1 \u0026 SHA2 thumbprints\r\n\r\n\r\n\r\n##### Notes:\r\n* Types returned by crytographic methods MAY be different on Windows and Linux. e.g. GetRSAPrivateKey() on X509Certificate2 on Windows returns RsaCng and OpenSslRsa on *nix.\r\n* It appears that Microsoft CNG implementation of BCryptSecretAgreement/NCryptSecretAgreement contains a bug for calculating Elliptic Curve Diffie-Hellman secret agreement\r\non keys higher than 256 bit (P-384 and P-521 NIST curves correspondingly). At least produced secret agreements do not match any other implementation in different languages. Starting version 5 we **not recommending** usage of `CngKey` keys with ECDH-ES family due to cross compatibility with other libraries.\r\nPlease switch to use `ECDsa`, `ECDiffieHellman` or `JWK` instead, which are **cross compatible** on all curves and operating systems.\r\n\r\n## Installation\r\n### NuGet\r\nhttps://www.nuget.org/packages/jose-jwt/\r\n\r\n`Install-Package jose-jwt`\r\n\r\n### Manual\r\nGrab source and compile yourself:\r\n  1. `dotnet restore`\r\n  1. `dotnet pack -c Release`\r\n\r\n## Usage\r\n### Creating Plaintext (unprotected) Tokens\r\n\r\n```C#\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nstring token = Jose.JWT.Encode(payload, null, JwsAlgorithm.none);\r\n```\r\n\r\n**Warning:** When using a `class` as the data structure of the payload, always use nullable data types for its properties. [details](#potential-security-risk)\r\n\r\n### Creating signed Tokens\r\n#### HS-\\* family\r\nHS256, HS384, HS512 signatures require `byte[]` array key or `Jwk` key of type `oct` of corresponding length\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring token=Jose.JWT.Encode(payload, secretKey, JwsAlgorithm.HS256);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nJwk key = new Jwk(new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234});\r\n\r\nstring token=Jose.JWT.Encode(payload, key, JwsAlgorithm.HS256);\r\n```\r\n\r\n#### RS-\\* and PS-\\* family\r\n**NET40-NET45**:\r\n\r\nRS256, RS384, RS512 and PS256, PS384, PS512 signatures require `RSACryptoServiceProvider` (usually private) key of corresponding length. CSP need to be forced to use Microsoft Enhanced RSA and AES Cryptographic Provider.\r\nWhich usually can be done be re-importing RSAParameters. See http://clrsecurity.codeplex.com/discussions/243156 for details.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar privateKey=new X509Certificate2(\"my-key.p12\", \"password\", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);\r\n```\r\n\r\n**NETCORE**:\r\nRS256, RS384, RS512 and PS256, PS384, PS512 signatures require `RSA` (usually private) or `Jwk` key of type `RSA` of corresponding length.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar privateKey=new X509Certificate2(\"my-key.p12\", \"password\").GetRSAPrivateKey();\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nJwk privateKey = new Jwk(\r\n    e: \"AQAB\",\r\n    n: \"qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q\",\r\n    p: \"0qaOkT174vRG3E_67gU3lgOgoT6L3pVHuu7wfrIEoxycPa5_mZVG54SgvQUofGUYEGjR0lavUAjClw9tOzcODHX8RAxkuDntAFntBxgRM-IzAy8QzeRl_cbhgVjBTAhBcxg-3VySv5GdxFyrQaIo8Oy_PPI1L4EFKZHmicBd3ts\",\r\n    q: \"zJPqCDKqaJH9TAGfzt6b4aNt9fpirEcdpAF1bCedFfQmUZM0LG3rMtOAIhjEXgADt5GB8ZNK3BQl8BJyMmKs57oKmbVcODERCtPqjECXXsxH-az9nzxatPvcb7imFW8OlWslwr4IIRKdEjzEYs4syQJz7k2ktqOpYI5_UfYnw1s\",\r\n    d: \"lJhwb0pKlB2ivyDFO6thajotClrMA3nxIiSkIUbvVr-TToFtha36gyF6w6e6YNXQXs4HhMRy1_b-nRQDk8G4_f5urd_q-pOn5u4KfmqN3Xw-lYD3ddi9qF0NLeTVUNVFASeP0FFqbPYfdNwD-LyvwjhtT_ggMOAw3mYvU5cBfz6-3uPdhl3CwQFCTgwOud_BA9p2MPMUHG82wMK_sNO1I0TYpjm7TnwNBwiKbMf-i5CKnuohgoYrEDYLeMg3f32eBljlCFNYaoCtT-mr1Ze0OTJND04vbfLotV-BBKulIpbOOSeVpKG7gJxZHmv7in7PE5_WzaxKFVoHW3wR6v_GzQ\",\r\n    dp: \"KTWmTGmf092AA1euOmRQ5IsfIIxQ5qGDn-FgsRh4acSOGE8L7WrTrTU4EOJyciuA0qz-50xIDbs4_j5pWx1BJVTrnhBin9vNLrVo9mtR6jmFS0ko226kOUpwEVLgtdQjobWLjtiuaMW-_Iw4gKWNptxZ6T1lBD8UWHaPiEFW2-M\",\r\n    dq: \"Jn0lqMkvemENEMG1eUw0c601wPOMoPD4SKTlnKWPTlQS6YISbNF5UKSuFLwoJa9HA8BifDrD-Mfpo1M1HPmnoilEWUrfwMqqdCkOlbiJQhKY8AZ16QGH50kDXhmVVa8BRWdVQWBTUzWXS5kXMaeskVzextTgymPcOAhXN-ph7MU\",\r\n    qi: \"sRAPigJpl8S_vsf1zhJTrHM97xRwuB26R6Tm-J8sKRPb7p5xxNlmOBBFvWmWxdto8dBElNlydSZan373yBLxzW-bZgVp-B2RKT1B3WhTYW_Vo5DLhWi84XMncJxH7avtxtF9yksaeKe0e2n3J6TTan53mDg4KF8U0OEO2ciqO9g\"\r\n);\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);\r\n\r\n```\r\n**NET461 and above**:\r\nAccepts `RSACryptoServiceProvider`, `RSA` or `Jwk` types of keys (see above).\r\n\r\n\r\n#### ES-\\*  family\r\n**NET40-NET45**:\r\nES256, ES384, ES512 ECDSA signatures requires `CngKey` (usually private) elliptic curve key of corresponding length. Normally existing `CngKey` loaded via `CngKey.Open(..)` method from Key Storage Provider.\r\nBut if you want to use raw key material (x,y) and d, jose-jwt provides convenient helper `EccKey.New(x,y,d)`.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\nbyte[] d = { 42, 148, 231, 48, 225, 196, 166, 201, 23, 190, 229, 199, 20, 39, 226, 70, 209, 148, 29, 70, 125, 14, 174, 66, 9, 198, 80, 251, 95, 107, 98, 206 };\r\n\r\nvar privateKey=EccKey.New(x, y, d);\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.ES256);\r\n```\r\n\r\n**NETCORE**:\r\nES256, ES384, ES512 ECDSA signatures can accept either `CngKey`(see above), `ECDsa` (usually private)  or `Jwk` of type `EC` elliptic curve key of corresponding length.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar privateKey=new X509Certificate2(\"ecc-key.p12\", \"password\").GetECDsaPrivateKey();\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.ES256);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar privateKey = new Jwk(\r\n    crv: \"P-256\",\r\n    x: \"BHId3zoDv6pDgOUh8rKdloUZ0YumRTcaVDCppUPoYgk\",\r\n    y: \"g3QIDhaWEksYtZ9OWjNHn9a6-i_P9o5_NrdISP0VWDU\",\r\n    d: \"KpTnMOHEpskXvuXHFCfiRtGUHUZ9Dq5CCcZQ-19rYs4\"\r\n);\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.ES256);\r\n```\r\n\r\n**NET461 and above**:\r\nAccepts `CngKey`, `ECDsa` and `Jwk` types of keys (see above).\r\n\r\n\r\n### Creating encrypted Tokens\r\n#### RSA-\\* key management family of algorithms\r\n\r\n**NET40-NET45**:\r\n\r\nRSA-OAEP-256, RSA-OAEP-384, RSA-OAEP-512, RSA-OAEP and RSA1_5 key management requires `RSACryptoServiceProvider` (usually public) key of corresponding length.\r\n\r\n```C#\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar publicKey=new X509Certificate2(\"my-key.p12\", \"password\").PublicKey.Key as RSACryptoServiceProvider;\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM);\r\n```\r\n\r\n**NETCORE:**\r\nRSA-OAEP-256, RSA-OAEP-384, RSA-OAEP-512, RSA-OAEP and RSA1_5 key management requires `RSA` (usually public) or `Jwk` key of type `RSA` of corresponding length.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar publicKey=new X509Certificate2(\"my-key.p12\", \"password\").GetRSAPublicKey();\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nJwk publicKey = new Jwk(\"AQAB\", \"qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q\");\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM);\r\n```\r\n\r\n**NET461**:\r\nAccepts `RSACryptoServiceProvider`, `RSA`, `Jwk` (see above) and `CngKey` types of keys.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nCngKey publicKey = CngKey.Open(\"connectionKeyId\", CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey));\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM);\r\n```\r\n\r\n#### DIR direct pre-shared symmetric key family of algorithms\r\nDirect key management with pre-shared symmetric keys requires `byte[]` array or `Jwk` of type `oct` key of corresponding length\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.DIR, JweEncryption.A128CBC_HS256);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new Jwk(new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234});\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.DIR, JweEncryption.A128CBC_HS256);\r\n```\r\n\r\n#### AES Key Wrap key management family of algorithms\r\nAES128KW, AES192KW and AES256KW key management requires `byte[]` array or `Jwk` of type `oct` key of corresponding length\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new Jwk(new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234});\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512);\r\n```\r\n\r\n#### AES GCM Key Wrap key management family of algorithms\r\nAES128GCMKW, AES192GCMKW and AES256GCMKW key management requires `byte[]` array or `Jwk` of type `oct` key of corresponding length\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar secretKey = new Jwk(new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234});\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512);\r\n```\r\n\r\n#### ECDH-ES and ECDH-ES with AES Key Wrap key management family of algorithms\r\n**NET40-NET46 (windows only)**:\r\nECDH-ES and ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW key management requires `CngKey` (usually public) or `Jwk` of type `EC` elliptic curve key of corresponding length.\r\n\r\nNormally existing `CngKey` can be loaded via `CngKey.Open(..)` method from Key Storage Provider.\r\nBut if you want to use raw key material (x,y) and d, jose-jwt provides convenient helper `EccKey.New(x,y,usage:CngKeyUsages.KeyAgreement)` or use `Jwk` instead.\r\n\r\n`Jwk` keys will use transparent bridging to `CngKey` under the hood.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\n\r\nvar publicKey=EccKey.New(x, y, usage:CngKeyUsages.KeyAgreement);\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.ECDH_ES, JweEncryption.A256GCM);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar publicKey = new Jwk(\r\n    crv: \"P-256\",\r\n    x: \"BHId3zoDv6pDgOUh8rKdloUZ0YumRTcaVDCppUPoYgk\",\r\n    y: \"g3QIDhaWEksYtZ9OWjNHn9a6-i_P9o5_NrdISP0VWDU\"\r\n);\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.ECDH_ES, JweEncryption.A256GCM);\r\n```\r\n\r\n**NET472 or NETCORE (all OS)**:\r\nAccepts either `CngKey`, `Jwk` of type EC (see above) or additionally `ECDsa` and `ECDiffieHellman` as a key.\r\n\r\n`Jwk` keys will use transparent bridging to `ECDiffieHellman` under the hood.\r\n\r\n`jose-jwt` provides convenient helper `EcdhKey.New(x,y,usage:CngKeyUsages.KeyAgreement)` if one want to to constuct `ECDiffieHellman` using raw key material (x,y) and d.\r\n\r\n`ECDsa` keys usually loaded from files.\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nECDsa publicKey = new X509Certificate2(\"ecc384.p12\", \"\u003cpassword\u003e\").GetECDsaPublicKey();\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.ECDH_ES_A192KW, JweEncryption.A192GCM);\r\n```\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\n\r\nECDiffieHellman publicKey=EcdhKey.New(x, y, usage:CngKeyUsages.KeyAgreement);\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.ECDH_ES_A128KW, JweEncryption.A128GCM);\r\n```\r\n\r\n\r\n#### PBES2 using HMAC SHA with AES Key Wrap key management family of algorithms\r\nPBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW key management requires `string` passphrase to derive key from\r\n\r\n``` cs\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nstring token = Jose.JWT.Encode(payload, \"top secret\", JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512);\r\n```\r\n\r\nIteration counts can be controlled by setting `p2c` header value:\r\n```c#\r\nvar headers = new Dictionary\u003cstring, object\u003e\r\n{\r\n    { \"p2c\", 10000 }\r\n};\r\n\r\nstring token = Jose.JWT.Encode(payload, \"top secret\", JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512, extraHeaders: headers);\r\n```\r\n\r\nPlease see [Adding extra headers](#adding-extra-headers) for additional details.\r\n\r\n\r\n#### Optional compressing payload before encrypting\r\nOptional DEFLATE compression is supported\r\n\r\n```C#\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar publicKey=new X509Certificate2(\"my-key.p12\", \"password\").PublicKey.Key as RSACryptoServiceProvider;\r\n\r\nstring token = Jose.JWT.Encode(payload, publicKey, JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256, JweCompression.DEF);\r\n```\r\n\r\n### Verifying and Decoding Tokens\r\n#### What methods to use?\r\nHistorically `jose-jwt` provided single family of `Decode()` methods that handles both signed and encrypted tokens with uniform interface, but as a number of confusion attacks on JWT libraries increased over last years, starting v5 library additionally provides dedicated methods `Verify()` and `Encrypt()` that are limited in scope to verifying signatures and decrypting tokens accordingly. See [Strict Validation](#strict-validation) and [Confusion Attacks](#confusion-attacks-and-how-to-nail-them) sections for more information.\r\n\r\nDecoding json web tokens is fully symmetric to creating signed or encrypted tokens:\r\n\r\n**HS256, HS384, HS512** signatures, **A128KW, A192KW, A256KW**, **A128GCMKW, A192GCMKW, A256GCMKW** and **DIR** key management algorithms expects `byte[]` array or `Jwk` of type `oct` key\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Fmz3PLVfv-ySl4IJ.LMZpXMDoBIll5yuEs81Bws2-iUUaBSpucJPL-GtDKXkPhFpJmES2T136Vd8xzvp-3JW-fvpRZtlhluqGHjywPctol71Zuz9uFQjuejIU4axA_XiAy-BadbRUm1-25FRT30WtrrxKltSkulmIS5N-Nsi_zmCz5xicB1ZnzneRXGaXY4B444_IHxGBIS_wdurPAN0OEGw4xIi2DAD1Ikc99a90L7rUZfbHNg_iTBr-OshZqDbR6C5KhmMgk5KqDJEN8Ik-Yw.Jbk8ZmO901fqECYVPKOAzg\";\r\n\r\nbyte[] secretKey=new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring json = Jose.JWT.Decode(token, secretKey);\r\n\r\n// starting v5 can also\r\nstring json=Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Fmz3PLVfv-ySl4IJ.LMZpXMDoBIll5yuEs81Bws2-iUUaBSpucJPL-GtDKXkPhFpJmES2T136Vd8xzvp-3JW-fvpRZtlhluqGHjywPctol71Zuz9uFQjuejIU4axA_XiAy-BadbRUm1-25FRT30WtrrxKltSkulmIS5N-Nsi_zmCz5xicB1ZnzneRXGaXY4B444_IHxGBIS_wdurPAN0OEGw4xIi2DAD1Ikc99a90L7rUZfbHNg_iTBr-OshZqDbR6C5KhmMgk5KqDJEN8Ik-Yw.Jbk8ZmO901fqECYVPKOAzg\";\r\n\r\nbyte[] secretKey=new Jwk(new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234});\r\n\r\nstring json = Jose.JWT.Decode(token, secretKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n**RS256, RS384, RS512**, **PS256, PS384, PS512** signatures and **RSA-OAEP-256**, **RSA-OAEP-384**, **RSA-OAEP-512**, **RSA-OAEP, RSA1_5** key management algorithms expects\r\n\r\n**NET40-NET45**: `RSACryptoServiceProvider` as a key, public/private is asymmetric to encoding:\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.bx_4TL7gh14IeM3EClP3iVfY9pbT81pflXd1lEZOVPJR6PaewRFXWmiJcaqH9fcU9IjGGQ19BS-UPtpErenL5kw7KORFgIBm4hObCYxLoAadMy8A-qQeOWyjnxbE0mbQIdoFI4nGK5qWTEQUWZCMwosvyeHLqEZDzr9CNLAAFTujvsZJJ7NLTkA0cTUzz64b57uSvMTaOK6j7Ap9ZaAgF2uaqBdZ1NzqofLeU4XYCG8pWc5Qd-Ri_1KsksjaDHk12ZU4vKIJWJ-puEnpXBLoHuko92BnN8_LXx4sfDdK7wRiXk0LU_iwoT5zb1ro7KaM0hcfidWoz95vfhPhACIsXQ.YcVAPLJ061gvPpVB-zMm4A.PveUBLejLzMjA4tViHTRXbYnxMHFu8W2ECwj9b6sF2u2azi0TbxxMhs65j-t3qm-8EKBJM7LKIlkAtQ1XBeZl4zuTeMFxsQ0VShQfwlN2r8dPFgUzb4f_MzBuFFYfP5hBs-jugm89l2ZTj8oAOOSpAlC7uTmwha3dNaDOzlJniqAl_729q5EvSjaYXMtaET9wSTNSDfMUVFcMERbB50VOhc134JDUVPTuriD0rd4tQm8Do8obFKtFeZ5l3jT73-f1tPZwZ6CmFVxUMh6gSdY5A.tR8bNx9WErquthpWZBeMaw\";\r\n\r\nvar privateKey=new X509Certificate2(\"my-key.p12\", \"password\", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;\r\n\r\nstring json = Jose.JWT.Decode(token,privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n**NETCORE**: `RSA` or `Jwk` of type `RSA` as a key, public/private is asymmetric to encoding:\r\n``` cs\r\nstring token = \"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.bx_4TL7gh14IeM3EClP3iVfY9pbT81pflXd1lEZOVPJR6PaewRFXWmiJcaqH9fcU9IjGGQ19BS-UPtpErenL5kw7KORFgIBm4hObCYxLoAadMy8A-qQeOWyjnxbE0mbQIdoFI4nGK5qWTEQUWZCMwosvyeHLqEZDzr9CNLAAFTujvsZJJ7NLTkA0cTUzz64b57uSvMTaOK6j7Ap9ZaAgF2uaqBdZ1NzqofLeU4XYCG8pWc5Qd-Ri_1KsksjaDHk12ZU4vKIJWJ-puEnpXBLoHuko92BnN8_LXx4sfDdK7wRiXk0LU_iwoT5zb1ro7KaM0hcfidWoz95vfhPhACIsXQ.YcVAPLJ061gvPpVB-zMm4A.PveUBLejLzMjA4tViHTRXbYnxMHFu8W2ECwj9b6sF2u2azi0TbxxMhs65j-t3qm-8EKBJM7LKIlkAtQ1XBeZl4zuTeMFxsQ0VShQfwlN2r8dPFgUzb4f_MzBuFFYfP5hBs-jugm89l2ZTj8oAOOSpAlC7uTmwha3dNaDOzlJniqAl_729q5EvSjaYXMtaET9wSTNSDfMUVFcMERbB50VOhc134JDUVPTuriD0rd4tQm8Do8obFKtFeZ5l3jT73-f1tPZwZ6CmFVxUMh6gSdY5A.tR8bNx9WErquthpWZBeMaw\";\r\n\r\nvar privateKey=new X509Certificate2(\"my-key.p12\", \"password\").GetRSAPrivateKey();\r\n\r\nstring json = Jose.JWT.Decode(token,privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.bx_4TL7gh14IeM3EClP3iVfY9pbT81pflXd1lEZOVPJR6PaewRFXWmiJcaqH9fcU9IjGGQ19BS-UPtpErenL5kw7KORFgIBm4hObCYxLoAadMy8A-qQeOWyjnxbE0mbQIdoFI4nGK5qWTEQUWZCMwosvyeHLqEZDzr9CNLAAFTujvsZJJ7NLTkA0cTUzz64b57uSvMTaOK6j7Ap9ZaAgF2uaqBdZ1NzqofLeU4XYCG8pWc5Qd-Ri_1KsksjaDHk12ZU4vKIJWJ-puEnpXBLoHuko92BnN8_LXx4sfDdK7wRiXk0LU_iwoT5zb1ro7KaM0hcfidWoz95vfhPhACIsXQ.YcVAPLJ061gvPpVB-zMm4A.PveUBLejLzMjA4tViHTRXbYnxMHFu8W2ECwj9b6sF2u2azi0TbxxMhs65j-t3qm-8EKBJM7LKIlkAtQ1XBeZl4zuTeMFxsQ0VShQfwlN2r8dPFgUzb4f_MzBuFFYfP5hBs-jugm89l2ZTj8oAOOSpAlC7uTmwha3dNaDOzlJniqAl_729q5EvSjaYXMtaET9wSTNSDfMUVFcMERbB50VOhc134JDUVPTuriD0rd4tQm8Do8obFKtFeZ5l3jT73-f1tPZwZ6CmFVxUMh6gSdY5A.tR8bNx9WErquthpWZBeMaw\";\r\n\r\nJwk privateKey = new Jwk(\r\n    e: \"AQAB\",\r\n    n: \"qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q\",\r\n    p: \"0qaOkT174vRG3E_67gU3lgOgoT6L3pVHuu7wfrIEoxycPa5_mZVG54SgvQUofGUYEGjR0lavUAjClw9tOzcODHX8RAxkuDntAFntBxgRM-IzAy8QzeRl_cbhgVjBTAhBcxg-3VySv5GdxFyrQaIo8Oy_PPI1L4EFKZHmicBd3ts\",\r\n    q: \"zJPqCDKqaJH9TAGfzt6b4aNt9fpirEcdpAF1bCedFfQmUZM0LG3rMtOAIhjEXgADt5GB8ZNK3BQl8BJyMmKs57oKmbVcODERCtPqjECXXsxH-az9nzxatPvcb7imFW8OlWslwr4IIRKdEjzEYs4syQJz7k2ktqOpYI5_UfYnw1s\",\r\n    d: \"lJhwb0pKlB2ivyDFO6thajotClrMA3nxIiSkIUbvVr-TToFtha36gyF6w6e6YNXQXs4HhMRy1_b-nRQDk8G4_f5urd_q-pOn5u4KfmqN3Xw-lYD3ddi9qF0NLeTVUNVFASeP0FFqbPYfdNwD-LyvwjhtT_ggMOAw3mYvU5cBfz6-3uPdhl3CwQFCTgwOud_BA9p2MPMUHG82wMK_sNO1I0TYpjm7TnwNBwiKbMf-i5CKnuohgoYrEDYLeMg3f32eBljlCFNYaoCtT-mr1Ze0OTJND04vbfLotV-BBKulIpbOOSeVpKG7gJxZHmv7in7PE5_WzaxKFVoHW3wR6v_GzQ\",\r\n    dp: \"KTWmTGmf092AA1euOmRQ5IsfIIxQ5qGDn-FgsRh4acSOGE8L7WrTrTU4EOJyciuA0qz-50xIDbs4_j5pWx1BJVTrnhBin9vNLrVo9mtR6jmFS0ko226kOUpwEVLgtdQjobWLjtiuaMW-_Iw4gKWNptxZ6T1lBD8UWHaPiEFW2-M\",\r\n    dq: \"Jn0lqMkvemENEMG1eUw0c601wPOMoPD4SKTlnKWPTlQS6YISbNF5UKSuFLwoJa9HA8BifDrD-Mfpo1M1HPmnoilEWUrfwMqqdCkOlbiJQhKY8AZ16QGH50kDXhmVVa8BRWdVQWBTUzWXS5kXMaeskVzextTgymPcOAhXN-ph7MU\",\r\n    qi: \"sRAPigJpl8S_vsf1zhJTrHM97xRwuB26R6Tm-J8sKRPb7p5xxNlmOBBFvWmWxdto8dBElNlydSZan373yBLxzW-bZgVp-B2RKT1B3WhTYW_Vo5DLhWi84XMncJxH7avtxtF9yksaeKe0e2n3J6TTan53mDg4KF8U0OEO2ciqO9g\"\r\n);\r\n\r\nstring json = Jose.JWT.Decode(token,privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n**NET461**: `RSACryptoServiceProvider`, `RSA`, `Jwk` of type `RSA` (see above) or `CngKey` types of keys, public/private is asymmetric to encoding.\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.bx_4TL7gh14IeM3EClP3iVfY9pbT81pflXd1lEZOVPJR6PaewRFXWmiJcaqH9fcU9IjGGQ19BS-UPtpErenL5kw7KORFgIBm4hObCYxLoAadMy8A-qQeOWyjnxbE0mbQIdoFI4nGK5qWTEQUWZCMwosvyeHLqEZDzr9CNLAAFTujvsZJJ7NLTkA0cTUzz64b57uSvMTaOK6j7Ap9ZaAgF2uaqBdZ1NzqofLeU4XYCG8pWc5Qd-Ri_1KsksjaDHk12ZU4vKIJWJ-puEnpXBLoHuko92BnN8_LXx4sfDdK7wRiXk0LU_iwoT5zb1ro7KaM0hcfidWoz95vfhPhACIsXQ.YcVAPLJ061gvPpVB-zMm4A.PveUBLejLzMjA4tViHTRXbYnxMHFu8W2ECwj9b6sF2u2azi0TbxxMhs65j-t3qm-8EKBJM7LKIlkAtQ1XBeZl4zuTeMFxsQ0VShQfwlN2r8dPFgUzb4f_MzBuFFYfP5hBs-jugm89l2ZTj8oAOOSpAlC7uTmwha3dNaDOzlJniqAl_729q5EvSjaYXMtaET9wSTNSDfMUVFcMERbB50VOhc134JDUVPTuriD0rd4tQm8Do8obFKtFeZ5l3jT73-f1tPZwZ6CmFVxUMh6gSdY5A.tR8bNx9WErquthpWZBeMaw\";\r\n\r\nCngKey privateKey = CngKey.Open(\"decryptionKeyId\", CngProvider.MicrosoftSoftwareKeyStorageProvider, CngKeyOpenOptions.MachineKey));\r\n\r\nstring json = Jose.JWT.Decode(token,privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n**ES256, ES284, ES512** signatures expects\r\n\r\n**NET40-NET45**: `CngKey` as a key, public/private is asymmetric to encoding. If `EccKey.New(...)` wrapper is used, make\r\nsure correct `usage:` value is set. Should be `CngKeyUsages.Signing` for ES-* signatures (default value, can be ommited).\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.EVnmDMlz-oi05AQzts-R3aqWvaBlwVZddWkmaaHyMx5Phb2NSLgyI0kccpgjjAyo1S5KCB3LIMPfmxCX_obMKA\";\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\n\r\nvar publicKey=EccKey.New(x, y);\r\n\r\nstring json = Jose.JWT.Decode(token, publicKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Verify(token, secretKey);\r\n```\r\n\r\n**NETCORE**: can accept either `CngKey` (see above), `ECDsa` or `Jwk` of type `EC` as a key, public/private is asymmetric to encoding.\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.EVnmDMlz-oi05AQzts-R3aqWvaBlwVZddWkmaaHyMx5Phb2NSLgyI0kccpgjjAyo1S5KCB3LIMPfmxCX_obMKA\";\r\n\r\nvar publicKey=new X509Certificate2(\"ecc-key.p12\", \"password\").GetECDsaPublicKey();\r\n\r\nstring token=Jose.JWT.Decode(token, publicKey, JwsAlgorithm.ES256);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Verify(token, secretKey);\r\n```\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.EVnmDMlz-oi05AQzts-R3aqWvaBlwVZddWkmaaHyMx5Phb2NSLgyI0kccpgjjAyo1S5KCB3LIMPfmxCX_obMKA\";\r\n\r\nvar publicKey = new Jwk(\r\n    crv: \"P-256\",\r\n    x: \"BHId3zoDv6pDgOUh8rKdloUZ0YumRTcaVDCppUPoYgk\",\r\n    y: \"g3QIDhaWEksYtZ9OWjNHn9a6-i_P9o5_NrdISP0VWDU\"\r\n);\r\n\r\nstring token=Jose.JWT.Decode(token, publicKey, JwsAlgorithm.ES256);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Verify(token, secretKey);\r\n```\r\n\r\n**NET461**: accepts `CngKey`, `ECDsa` or `Jwk` of type `EC` types of keys (see examples above), public/private is asymmetric to encoding.\r\n\r\n\r\n**ECDH-ES** and **ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW** key management algorithms expects\r\n\r\n**NET40-NET46 (windows only)**:  `CngKey` or `Jwk` of type `EC` as a key, public/private is asymmetric to encoding. If `EccKey.New(...)` wrapper is used, make\r\nsure correct `usage:` value is set. Should be `CngKeyUsages.KeyAgreement` for ECDH-ES.\r\n\r\n`Jwk` keys will use transparent bridging to `CngKey` under the hood.\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJPbDdqSWk4SDFpRTFrcnZRTmFQeGp5LXEtY3pQME40RVdPM1I3NTg0aEdVIiwieSI6Ik1kU2V1OVNudWtwOWxLZGU5clVuYmp4a3ozbV9kTWpqQXc5NFd3Q0xaa3MiLCJjcnYiOiJQLTI1NiJ9fQ..E4XwpWZ2kO-Vg0xb.lP5LWPlabtmzS-m2EPGhlPGgllLNhI5OF2nAbbV9tVvtCckKpt358IQNRk-W8-JNL9SsLdWmVUMplrw-GO-KA2qwxEeh_8-muYCw3qfdhVVhLnOF-kL4mW9a00Xls_6nIZponGrqpHCwRQM5aSr365kqTNpfOnXgJTKG2459nqv8n4oSfmwV2iRUBlXEgTO-1Tvrq9doDwZCCHj__JKvbuPfyRBp5T7d-QJio0XRF1TO4QY36GtKMXWR264lS7g-T1xxtA.vFevA9zsyOnNA5RZanKqHA\";\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\nbyte[] d = { 42, 148, 231, 48, 225, 196, 166, 201, 23, 190, 229, 199, 20, 39, 226, 70, 209, 148, 29, 70, 125, 14, 174, 66, 9, 198, 80, 251, 95, 107, 98, 206 };\r\n\r\nvar privateKey=EccKey.New(x, y, d, CngKeyUsages.KeyAgreement);\r\n\r\nstring json = Jose.JWT.Decode(token, privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJPbDdqSWk4SDFpRTFrcnZRTmFQeGp5LXEtY3pQME40RVdPM1I3NTg0aEdVIiwieSI6Ik1kU2V1OVNudWtwOWxLZGU5clVuYmp4a3ozbV9kTWpqQXc5NFd3Q0xaa3MiLCJjcnYiOiJQLTI1NiJ9fQ..E4XwpWZ2kO-Vg0xb.lP5LWPlabtmzS-m2EPGhlPGgllLNhI5OF2nAbbV9tVvtCckKpt358IQNRk-W8-JNL9SsLdWmVUMplrw-GO-KA2qwxEeh_8-muYCw3qfdhVVhLnOF-kL4mW9a00Xls_6nIZponGrqpHCwRQM5aSr365kqTNpfOnXgJTKG2459nqv8n4oSfmwV2iRUBlXEgTO-1Tvrq9doDwZCCHj__JKvbuPfyRBp5T7d-QJio0XRF1TO4QY36GtKMXWR264lS7g-T1xxtA.vFevA9zsyOnNA5RZanKqHA\";\r\n\r\nvar privateKey = new Jwk(\r\n        crv: \"P-256\",\r\n        x: \"BHId3zoDv6pDgOUh8rKdloUZ0YumRTcaVDCppUPoYgk\",\r\n        y: \"g3QIDhaWEksYtZ9OWjNHn9a6-i_P9o5_NrdISP0VWDU\",\r\n        d: \"KpTnMOHEpskXvuXHFCfiRtGUHUZ9Dq5CCcZQ-19rYs4\"\r\n);\r\n\r\nstring json = Jose.JWT.Decode(token, privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n**NET472 or NETCORE (all OS)**:\r\nAccepts either `CngKey`, `Jwk` of type EC (see above) or additionally `ECDsa` and `ECDiffieHellman` as a key.\r\n\r\n`Jwk` keys will use transparent bridging to `ECDiffieHellman` under the hood.\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJPbDdqSWk4SDFpRTFrcnZRTmFQeGp5LXEtY3pQME40RVdPM1I3NTg0aEdVIiwieSI6Ik1kU2V1OVNudWtwOWxLZGU5clVuYmp4a3ozbV9kTWpqQXc5NFd3Q0xaa3MiLCJjcnYiOiJQLTI1NiJ9fQ..E4XwpWZ2kO-Vg0xb.lP5LWPlabtmzS-m2EPGhlPGgllLNhI5OF2nAbbV9tVvtCckKpt358IQNRk-W8-JNL9SsLdWmVUMplrw-GO-KA2qwxEeh_8-muYCw3qfdhVVhLnOF-kL4mW9a00Xls_6nIZponGrqpHCwRQM5aSr365kqTNpfOnXgJTKG2459nqv8n4oSfmwV2iRUBlXEgTO-1Tvrq9doDwZCCHj__JKvbuPfyRBp5T7d-QJio0XRF1TO4QY36GtKMXWR264lS7g-T1xxtA.vFevA9zsyOnNA5RZanKqHA\";\r\n\r\nECDsa privateKey = new X509Certificate2(\"ecc256.p12\", \"\u003cpassword\u003e\").GetECDsaPrivateKey();\r\n\r\nstring token = Jose.JWT.Decode(token, privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n``` cs\r\nstring token = \"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJPbDdqSWk4SDFpRTFrcnZRTmFQeGp5LXEtY3pQME40RVdPM1I3NTg0aEdVIiwieSI6Ik1kU2V1OVNudWtwOWxLZGU5clVuYmp4a3ozbV9kTWpqQXc5NFd3Q0xaa3MiLCJjcnYiOiJQLTI1NiJ9fQ..E4XwpWZ2kO-Vg0xb.lP5LWPlabtmzS-m2EPGhlPGgllLNhI5OF2nAbbV9tVvtCckKpt358IQNRk-W8-JNL9SsLdWmVUMplrw-GO-KA2qwxEeh_8-muYCw3qfdhVVhLnOF-kL4mW9a00Xls_6nIZponGrqpHCwRQM5aSr365kqTNpfOnXgJTKG2459nqv8n4oSfmwV2iRUBlXEgTO-1Tvrq9doDwZCCHj__JKvbuPfyRBp5T7d-QJio0XRF1TO4QY36GtKMXWR264lS7g-T1xxtA.vFevA9zsyOnNA5RZanKqHA\";\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\nbyte[] d = { 42, 148, 231, 48, 225, 196, 166, 201, 23, 190, 229, 199, 20, 39, 226, 70, 209, 148, 29, 70, 125, 14, 174, 66, 9, 198, 80, 251, 95, 107, 98, 206 };\r\n\r\nvar privateKey=EcdhKey.New(x, y, d, CngKeyUsages.KeyAgreement);\r\n\r\nstring json = Jose.JWT.Decode(token, privateKey);\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n\r\n**PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW** key management algorithms expects `string` passpharase as a key\r\n\r\n```C#\r\nstring token = \"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwicDJjIjo4MTkyLCJwMnMiOiJiMFlFVmxMemtaNW9UUjBMIn0.dhPAhJ9kmaEbP-02VtEoPOF2QSEYM5085V6zYt1U1qIlVNRcHTGDgQ.4QAAq0dVQT41dQKDG7dhRA.H9MgJmesbU1ow6GCa0lEMwv8A_sHvgaWKkaMcdoj_z6O8LaMSgquxA-G85R_5hEILnHUnFllNJ48oJY7VmAJw0BQW73dMnn58u161S6Ftq7Mjxxq7bcksWvFTVtG5RsqqYSol5BZz5xm8Fcj-y5BMYMvrsCyQhYdeGEHkAvwzRdvZ8pGMsU2XPzl6GqxGjjuRh2vApAeNrj6MwKuD-k6AR0MH46EiNkVCmMkd2w8CNAXjJe9z97zky93xbxlOLozaC3NBRO2Q4bmdGdRg5y4Ew.xNqRi0ouQd7uo5UrPraedg\";\r\n\r\nstring json = Jose.JWT.Decode(token, \"top secret\");\r\n\r\n// starting v5 can also\r\nstring json = Jose.JWT.Decrypt(token, secretKey);\r\n```\r\n\r\n### JWE JSON Serialization support (RFC 7516)\r\nAs of version v3.1 `jose-jwt` library provides full support for json serialized encrypted content.\r\n\r\n#### Decoding json serialized encrypted content\r\n\r\n`JweToken Jose.JWE.Decrypt(token, key)` - can be used to decrypt JSON serialized token.\r\n\r\nSee [Verifying and Decoding Tokens](#verifying-and-decoding-tokens) section for information about different key types usage.\r\n\r\nThe function returns object of type `JweToken` with following properties:\r\n* `PlaintextBytes` - byte array with decrypted content, only when decryption successfully performed\r\n* `Plaintext` - decrypted content as string, only when decryption successfully performed\r\n* `Recipient` - effective recipient that was used to decrypt token, only when decryption was successfully performed\r\n* `Aad` - additional authentication data\r\n* `Iv` - initialization vector\r\n* `Ciphertext` - ciphertext (encrypted content)\r\n* `AuthTag` - authenication tag\r\n* `UnprotectedHeader` - shared unprotected headers (key-value pairs)\r\n* `ProtectedHeaderBytes` - shared signature protected headers, binary blob\r\n* `Recipients` - list of `JweRecipient` objects as specified in token\r\n\r\n`JweRecipient` object supports following properties:\r\n* `Alg` - Key encryption algorithm\r\n* `Header` - Per recipient set of headers\r\n* `JoseHeader` - effective headers for given recipient, calculated as union of shared headers and per-recipient headers, only when decryption successfully performed via `Jose.JWE.Decrypt()` or `Jose.JWE.Headers()` was called.\r\n\r\n\r\n``` cs\r\nstring token = @\"\r\n{\r\n\t\"\"aad\"\": \"\"ZXlKaGJHY2lPaUpCTVRJNFMxY2lMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySW4w\"\",\r\n\t\"\"ciphertext\"\": \"\"02VvoX1sUsmFi2ZpIbTI8g\"\",\r\n\t\"\"encrypted_key\"\": \"\"kH4te-O3DNZoDlxeDnBXM9CNx2d5IgVGO-cVMmqTRW_ws0EG_RKDQ7FLLztMM83z2s-pSNSZtFf3bx9Aky8XOzhIYCIU7XvmiQ0pp5z1FRdrwO-RxEOJfb2hAjD-hE5lCJkkY722QGs4IrUQ5N5Atc9h9-0vDcg-gksFIuaLMeRQj3LxivhwJO-QWFd6sG0FY6fBCwS1X6zsrZo-m9DNvrB6FhMpkLPBDOlCNnjKf1_Mz_jAuXIwnVUhoq59m8tvxQY1Fyngiug6zSnM207-0BTXzuCTnPgPAwGWGDLO7o0ttPT6RI_tLvYE6AuOynsqsHDaecyIkJ26dif3iRmkeg\"\",\r\n\t\"\"header\"\": {\r\n\t\t\"\"alg\"\": \"\"RSA-OAEP-256\"\",\r\n\t\t\"\"kid\"\": \"\"Ex-p1KJFz8hQE1S76SzkhHcaObCKoDPrtAPJdWuTcTc\"\"\r\n\t},\r\n\t\"\"iv\"\": \"\"E1BAiqIeAH_0eInT59zb8w\"\",\r\n\t\"\"protected\"\": \"\"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidHlwIjoiSldFIn0\"\",\r\n\t\"\"tag\"\": \"\"yYBiajF5oMtyK3mRVQyPnlJL25hXW8Ct8ZMcFK5ehDY\"\"\r\n}\";\r\n\r\n// Use key type approporiate for your recipient\r\nvar key = LoadPrivateRsaKey();\r\n\r\n// decrypt JSON serialized token\r\nJweToken jwe = Jose.JWE.Decrypt(token, key);\r\n\r\n// generic form to access decrypted content as blob\r\nbyte[] binaryContent = jwe.PlaintextBytes;\r\n\r\n// convinient helper to get decrypted content as string\r\nstring content = jwe.Plaintext;\r\n\r\n// effective recipient information that was used for decryption\r\nJweRecipient recipient = jwe.Recipient;\r\n\r\n// accessing effective headers\r\nstring keyId = recipient.JoseHeaders[\"kid\"];\r\n```\r\n\r\n#### Encrypting using JSON serialization\r\n`string Jose.JWE.Encrypt(plaintext, recipients, encryption, add, serialization, compression, extraProtectedHeaders, unprotectedHeaders, settings)` - can be used to encrypt string content and produce JSON serialized token.\r\n\r\nAlternate version to encrypt binary content is also available `string Jose.JWE.EncryptBytes()`.\r\n\r\nWhere:\r\n* `plaintext` - content (payload) to be encrypted\r\n* `recipients` - one or more recipients information\r\n* `encryption` - encryption to be used\r\n* `add` - optional, Additional Authentication Data\r\n* `serialization` - optional, `Json` is default, final token encoding\r\n* `compression` - optional, compression algorithm\r\n* `extraProtectedHeaders` - optional, additional key-value pairs to include into protected header\r\n* `unprotectedHeaders` - optional, key-value pairs to include into unprotected header\r\n\r\nSee [Creating encrypted Tokens](#creating-encrypted-tokens) section for information about different key types usage.\r\n\r\n``` cs\r\nvar payload = \"Hello JWE !\";\r\nvar blob = new byte[] { 72, 101, 108, 108, 111, 32, 74, 87, 69, 32, 33 };\r\nvar preSharedKey = LoadKey();\r\n\r\n// generate JSON encoded token\r\nstring token_1 = JWE.Encrypt(payload, new[] { new JweRecipient(JweAlgorithm.A256KW, preSharedKey) }, JweEncryption.A256GCM);\r\n\r\n// encrypt binary\r\nstring token_2 = JWE.EncryptBytes(payload, new[] { new JweRecipient(JweAlgorithm.A256KW, preSharedKey) }, JweEncryption.A256GCM);\r\n\r\n// can opt-in for Compact encoded tokens with same interface\r\nstring token_3 = JWE.Encrypt(payload, new[] { new JweRecipient(JweAlgorithm.A256KW, preSharedKey), mode: SerializationMode.Compact }, JweEncryption.A256GCM);\r\n```\r\n\r\nEncrypt for multiple recipients at once:\r\n``` cs\r\nvar payload = \"Hello World !\";\r\nJweRecipient r1 = new JweRecipient(JweAlgorithm.PBES2_HS256_A128KW, \"secret\");\r\nJweRecipient r2 = new JweRecipient(JweAlgorithm.ECDH_ES_A128KW, ECPublicKey());\r\nJweRecipient r3 = new JweRecipient(JweAlgorithm.RSA_OAEP_256, RsaPublicKey());\r\n\r\nstring token = JWE.Encrypt(payload, new[] { r1, r2, r3 }, JweEncryption.A256GCM);\r\n```\r\n\r\nProvide additional authentication data and unprotected shared headers:\r\n\r\n``` cs\r\nvar payload = \"Hello World !\";\r\n\r\n// additional authenticatin data\r\nvar aad = new byte[] { 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 66, 77, 84, 73, 52, 83, 49, 99, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105, 74, 66, 77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85, 50, 73, 110, 48 };\r\n\r\n// shared unprotected headers\r\nvar unprotected = new Dictionary\u003cstring, object\u003e\r\n{\r\n    { \"jku\", \"https://server.example.com/keys.jwks\" }\r\n};\r\n\r\nvar preSharedKey = LoadKey();\r\n\r\nstring token = JWE.Encrypt(payload, new[] { r }, JweEncryption.A256GCM, aad, unprotectedHeaders: unprotected);\r\n\r\n```\r\n\r\n### Working with Json Web Keys (JWKs)\r\nAs of v4.0.0 library provides full-blown support for Json Web Keys (aka [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)), including parsing, contructing and bridging the gap with different .NET key types to be used in all signing and encryption algorithms.\r\n\r\nSee [Creating encrypted Tokens](#creating-encrypted-tokens), [Creating signed Tokens](#creating-signed-tokens) and [Verifying and Decoding Tokens](#verifying-and-decoding-tokens) for details on using JWK with different Json Web Tokens algorithms.\r\n\r\nMost of JWK support will work on `.NET 4.6.1` and `.NET Core 2.0`. But some key bridging requires `.NET 4.7.2` or `NETSTANDARD 2.1` and above.\r\n\r\nThe two core classes are:\r\n\r\n* `Jwk` - object model for Json Web Key\r\n* `JwkSet` - object model Json Web Key Set\r\n\r\n### Reading JWK\r\nBoth classes offers set of static methods to read or write model from JSON string or dictionary object respectively.\r\n* `Jwk.FromJson(string, IJsonMapper), JwkSet.FromJson(string, IJsonMapper)` - parses json and constructs object model from it\r\n* `Jwk.FromDictionary(IDictionary\u003cstring, object\u003e), JwkSet.FromDictionary(IDictionary\u003cstring, object\u003e)` - constructs object model from dictionary\r\n* `Jwk.ToJson(IJsonMapper), JwkSet.ToJson(IJsonMapper)` - searializes model to json\r\n* `Jwk.ToDictionary(), JwkSet.ToDictionary()` - writes model as dictionary\r\n\r\nSee [Examples](#examples) for usage details.\r\n\r\n### Constructing JWK\r\nModel object can be constructed normal way via setting approporiate properties or calling collection methods, there are also set of convinient constructors:\r\n\r\n``` cs\r\n// Oct key\r\nJwk octKey = new Jwk(new byte[] { 25, 172, 32, 130, 225, 114, 26, 181, 138, 106, 254, 192, 95, 133, 74, 82 });\r\n\r\n// RSA key\r\nJwk rsaKey = new Jwk(\r\n    e: \"AQAB\",\r\n    n: \"qFZv0pea_jn5Mo4qEUmStuhlulso8n1inXbEotd_zTrQp9K0RK0hf7t0K4BjKVhaiqIam4tVVQvkmYeBeYr1MmnO_0N97dMBz_7fmvyv0hgHaBdQ5mR5u3LTlHo8tjRE7-GzZmGs6jMcyj7HbXobDPQJZpqNy6JjliDVXxW8nWJDetxGBlqmTj1E1fr2RCsZLreDOPSDIedG1upz9RraShsIDzeefOcKibcAaKeeVI3rkAU8_mOauLSXv37hlk0h6sStJb3qZQXyOUkVkjXIkhvNu_ve0v7LiLT4G_OxYGzpOQcCnimKdojzNP6GtVDaMPh-QkSJE32UCos9R3wI2Q\",\r\n    p: \"0qaOkT174vRG3E_67gU3lgOgoT6L3pVHuu7wfrIEoxycPa5_mZVG54SgvQUofGUYEGjR0lavUAjClw9tOzcODHX8RAxkuDntAFntBxgRM-IzAy8QzeRl_cbhgVjBTAhBcxg-3VySv5GdxFyrQaIo8Oy_PPI1L4EFKZHmicBd3ts\",\r\n    q: \"zJPqCDKqaJH9TAGfzt6b4aNt9fpirEcdpAF1bCedFfQmUZM0LG3rMtOAIhjEXgADt5GB8ZNK3BQl8BJyMmKs57oKmbVcODERCtPqjECXXsxH-az9nzxatPvcb7imFW8OlWslwr4IIRKdEjzEYs4syQJz7k2ktqOpYI5_UfYnw1s\",\r\n    d: \"lJhwb0pKlB2ivyDFO6thajotClrMA3nxIiSkIUbvVr-TToFtha36gyF6w6e6YNXQXs4HhMRy1_b-nRQDk8G4_f5urd_q-pOn5u4KfmqN3Xw-lYD3ddi9qF0NLeTVUNVFASeP0FFqbPYfdNwD-LyvwjhtT_ggMOAw3mYvU5cBfz6-3uPdhl3CwQFCTgwOud_BA9p2MPMUHG82wMK_sNO1I0TYpjm7TnwNBwiKbMf-i5CKnuohgoYrEDYLeMg3f32eBljlCFNYaoCtT-mr1Ze0OTJND04vbfLotV-BBKulIpbOOSeVpKG7gJxZHmv7in7PE5_WzaxKFVoHW3wR6v_GzQ\",\r\n    dp: \"KTWmTGmf092AA1euOmRQ5IsfIIxQ5qGDn-FgsRh4acSOGE8L7WrTrTU4EOJyciuA0qz-50xIDbs4_j5pWx1BJVTrnhBin9vNLrVo9mtR6jmFS0ko226kOUpwEVLgtdQjobWLjtiuaMW-_Iw4gKWNptxZ6T1lBD8UWHaPiEFW2-M\",\r\n    dq: \"Jn0lqMkvemENEMG1eUw0c601wPOMoPD4SKTlnKWPTlQS6YISbNF5UKSuFLwoJa9HA8BifDrD-Mfpo1M1HPmnoilEWUrfwMqqdCkOlbiJQhKY8AZ16QGH50kDXhmVVa8BRWdVQWBTUzWXS5kXMaeskVzextTgymPcOAhXN-ph7MU\",\r\n    qi: \"sRAPigJpl8S_vsf1zhJTrHM97xRwuB26R6Tm-J8sKRPb7p5xxNlmOBBFvWmWxdto8dBElNlydSZan373yBLxzW-bZgVp-B2RKT1B3WhTYW_Vo5DLhWi84XMncJxH7avtxtF9yksaeKe0e2n3J6TTan53mDg4KF8U0OEO2ciqO9g\"\r\n);\r\n\r\n// EC key\r\nJwk eccKey = new Jwk(\r\n    crv: \"P-256\",\r\n    x: \"BHId3zoDv6pDgOUh8rKdloUZ0YumRTcaVDCppUPoYgk\",\r\n    y: \"g3QIDhaWEksYtZ9OWjNHn9a6-i_P9o5_NrdISP0VWDU\",\r\n    d: \"KpTnMOHEpskXvuXHFCfiRtGUHUZ9Dq5CCcZQ-19rYs4\"\r\n);\r\n\r\n// Key sets\r\nJwkSet keySet = new JwkSet(octKey, rsaKey);\r\nkeySet.Add(eccKey);\r\n```\r\n\r\n### Converting between JWK and .NET key types\r\nLibrary provides two way bridging with different .NET key types.\r\nOne can construct `Jwk` from underlying `ECDsa`, `RSA` or `CngKey` (elliptic keys only)\r\n\r\n``` cs\r\n// Cng keys\r\nCngKey eccCngKey = CngKey.Open(...);\r\nJwk jwk = new Jwk(eccCngKey, isPrivate: false); //or 'true' by defaut\r\n\r\n// RSA keys\r\nRSA rsaKey=new X509Certificate2(\"my-key.p12\", \"password\").GetRSAPublicKey();\r\nJwk jwk = new Jwk(rsaKey, isPrivate: false); //or 'true' by defaut\r\n\r\n// ECDsa keys\r\nECDsa ecdsaKey = new X509Certificate2(\"ecc521.p12\", \"password\").GetECDsaPublicKey();\r\nJwk jwk = new Jwk(ecdsaKey, isPrivate: false); //or 'true' by defaut\r\n```\r\n\r\nor convert `Jwk` key to corresponding `ECDsa`, `RSA` or `CngKey` (elliptic keys only)\r\n\r\n``` cs\r\n// Returns ephemeral exportable CngKey, handle is cached for subsequent calls\r\nCngKey cngKey = jwk.CngKey(usage: CngKeyUsages.KeyAgreement); // or 'CngKeyUsages.Signing' by default\r\n\r\n// Returns backing ECDsa key, constructs new on demand, cached for subsequent calls\r\nECDsa ecdaKey = jwk.ECDsaKey();\r\n\r\n// Returns backing RSA key, constructs new on demand, cached for subsequent calls\r\nRSA rsaKey = jwk.RsaKey();\r\n```\r\n\r\n### Working with certificate chains\r\nDirect interface with `X509Certificate2` class is provided when working with chains in JWK:\r\n\r\n``` cs\r\nX509Certificate2 root = new X509Certificate2(\"root.p12\");\r\nX509Certificate2 intermidiary = new X509Certificate2(\"inter.p12\");\r\nX509Certificate2 signing = new X509Certificate2(\"signing.p12\");\r\n\r\nJwk key = new Jwk();\r\n\r\n// set chain at once\r\nkey.SetX509Chain(new List\u003cX509Certificate2\u003e{ root, intermidiary });\r\n\r\n// or add one by one\r\nkey.Add(signing);\r\n\r\n// Read chain from key as list of certificates\r\nList\u003cX509Certificate2\u003e test = key.GetX509Chain();\r\n```\r\n\r\nHelpers to set SHA-1 and SHA-256 thumbprints:\r\n``` cs\r\nX509Certificate2 signing = new X509Certificate2(\"signing.p12\");\r\n\r\nJwk key = new Jwk();\r\n\r\n// Calculate and set certificate SHA-1 thumbprint\r\nkey.SetX5T(signing);\r\n\r\n// Calculate and set certificate SHA-256 thumbprint\r\nkey.SetX5TSha256(signing);\r\n```\r\n\r\n### Extra params\r\nIn addition to named params from [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517) library allows to include any custom key value params to the key objects:\r\n\r\n``` cs\r\nJwk key = new Jwk();\r\n\r\n// add custom params\r\nkey.OtherParams = new Dictionary\u003cstring, object\u003e();\r\nkey.OtherParams[\"s\"] = \"2WCTcJZ1Rvd_CJuJripQ1w\";\r\nkey.OtherParams[\"c\"] = 4096;\r\n\r\n// or read them from the key same way\r\nstring s = (string)key.OtherParams[\"s\"];\r\n```\r\n\r\n### Searching JwkSet with Linq\r\n`JwkSet` is Linq compatible and it is preffered way to locate keys of interest within collection:\r\n\r\n``` cs\r\nJwkSet keySet = new JwkSet(....);\r\n\r\nIEnumerable\u003cJwk\u003e rsaKeys =\r\n    from key in keySet\r\n    where key.Alg == \"enc\" \u0026\u0026 key.Kty == Jwk.KeyTypes.RSA\r\n    select key;\r\n```\r\n\r\n### Examples\r\n1. Decrypt symmetric JWK of Oct type from payload and use it for further signing:\r\n\r\n``` cs\r\n    string token = \"eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMmMiOjgxOTIsInAycyI6Inp3eUF0TElqTXpQM01pQ0giLCJlbmMiOiJBMjU2R0NNIn0.4geBbNNUErAkSiNmUVL23tnH3Jah0B0QkvhAaEcHeUgxRGKmWvkOjg.CCNy7C1HOH-qq5Lo.Uzi9FZ_b8bHenXF7h-D63gZCASdvLA7WqnKRSXwsr7G94SnB5bHiZrUT.l6D2hJSoFPpnXPXLyOloxg\";\r\n\r\n    // Decrypt symmetric key in payload with PBES2\r\n    Jwk key = Jose.JWT.Decode\u003cJwk\u003e(token, \"secret\");\r\n\r\n    // And use it to sign new messages\r\n    string signed = JWT.Encode(@\"{\"\"hello\"\": \"\"world\"\"}\", key, JwsAlgorithm.HS512);\r\n```\r\n\r\n2. Use Jwk from token header for verification\r\n``` cs\r\nstring token = \"eyJhbGciOiJSUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsIm4iOiJxRlp2MHBlYV9qbjVNbzRxRVVtU3R1aGx1bHNvOG4xaW5YYkVvdGRfelRyUXA5SzBSSzBoZjd0MEs0QmpLVmhhaXFJYW00dFZWUXZrbVllQmVZcjFNbW5PXzBOOTdkTUJ6XzdmbXZ5djBoZ0hhQmRRNW1SNXUzTFRsSG84dGpSRTctR3pabUdzNmpNY3lqN0hiWG9iRFBRSlpwcU55NkpqbGlEVlh4VzhuV0pEZXR4R0JscW1UajFFMWZyMlJDc1pMcmVET1BTREllZEcxdXB6OVJyYVNoc0lEemVlZk9jS2liY0FhS2VlVkkzcmtBVThfbU9hdUxTWHYzN2hsazBoNnNTdEpiM3FaUVh5T1VrVmtqWElraHZOdV92ZTB2N0xpTFQ0R19PeFlHenBPUWNDbmltS2RvanpOUDZHdFZEYU1QaC1Ra1NKRTMyVUNvczlSM3dJMlEifX0.eyJoZWxsbyI6ICJ3b3JsZCJ9.BX7lG2iQvYM7vO_DTsPPWbuTTpBP9dsDmEITd_Ofq9Ds8ucWrDVUjlMHBXUCfgTuoHHfeNtFE7sfuLxd0RseEY2Q4OnoFyJC_Gc63DwhrEvzY09i_sTTskc5rfQK9s32K595WjIceWnJh6s03dVEPmBWl_xwihV56LRzy4m8c15d1ZMlNByjpLibPGSVoJT4ae64Ux25hhbEageO-6gsTaYH9zofP3WGUzGf5PGq6nBtmrlQgyPhTkxzB1DUUBx0cA5IpnzQLwEDljKrgKRGn86TUrQc5dlIIKETZcTCnF2-CXq3oiqF81oEkFxfcW2yX5H0kmZmY_dQkKs1JR65yA\";\r\n\r\n// Grab 'jwk' header\r\nvar headers = Jose.JWT.Headers(token);\r\n\r\n// And turn it into key\r\nJwk publicKey = Jwk.FromDictionary(\r\n    (IDictionary\u003cstring, object\u003e)headers[\"jwk\"]\r\n);\r\n\r\n// ATTENTION: always ensure this is the key you know and expect from partner\r\n// EnsureKnownKey(publicKey);\r\n\r\n// Use it to decode payload and verify signature\r\nstring payload = Jose.JWT.Decode(token, publicKey);\r\n```\r\n\r\n3. Fetching key set from jwks endpoint and locating verification one by thumbprint:\r\n\r\n``` cs\r\nHttpClient client = new HttpClient()\r\n\r\n// Grab public keys from partner endpoint\r\nstring keys = await client.GetStringAsync(\"https://acme.com/.well-known/jwks.json\");\r\n\r\nJwkSet jwks = JwkSet.FromJson(keys, JWT.DefaultSettings.JsonMapper);\r\n\r\n// Get hint from token headers\r\nvar headers = Jose.JWT.Headers(token);\r\n\r\n// Find matching public key by thumbprint\r\nJwk pubKey = (\r\n    from key in jwks\r\n    where key.Alg == Jwk.KeyUsage.Signature \u0026\u0026\r\n            key.KeyOps != null \u0026\u0026 key.KeyOps.Contains(Jwk.KeyOperations.Verify) \u0026\u0026\r\n            key.Kty == Jwk.KeyTypes.RSA \u0026\u0026\r\n            key.X5T == (string)headers[\"x5t\"]\r\n    select key\r\n).First();\r\n\r\n// Finally verify token\r\nvar payload = Jose.JWT.Decode(token, pubKey);\r\n```\r\n\r\n\r\n## Additional utilities\r\n\r\n### Unencoded and detached content (aka [RFC 7797](https://tools.ietf.org/html/rfc7797))\r\nAs of v2.5.0 library support `b64` header to control payload decoding and encoding and optional content detaching.\r\n\r\nEncoding can be controlled with optional `JwtOptions` parameter, that support:\r\n* `DetachPayload` - whether we'd like to omit payload part in token produced (`false` by default)\r\n* `EncodePayload` - whether to apply base64url encoding to payload part (`true` by default)\r\n\r\nOptions can be mixed in any combinations. To match RFC 7797:\r\n\r\n```C#\r\nstring token = Jose.JWT.Encode(json, secretKey, JwsAlgorithm.HS256, options: new JwtOptions { DetachPayload = true, EncodePayload = false});\r\n```\r\nor just skip payload for instance:\r\n\r\n```C#\r\nstring token = Jose.JWT.Encode(json, secretKey, JwsAlgorithm.HS256, options: new JwtOptions { DetachPayload = true });\r\n```\r\n\r\nDecoding automatically respect `b64` header if present. In case of detached payload one can provide optional `payload` param:\r\n\r\n```C#\r\nstring token = \"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJSUzI1NiJ9..iyormYw6b0zKjx4K-fpeZO8xrLghkeUFMb2l4alz03CRLVdlXkdeKVG7N5lBbS-kXB4-8hH1ELFA5fUJzN2QYR6ZZIWjDF77HYTw7lsyjTJDNABjBFn-BIXlWatjNdgtRi2BZg2q_Wos87ZQT6Sl-h5hvxsFEsR0kGPMQ4Fjp-sxOyfnls8jAlziqmkpN-K6I3tK2vCLCQgnaN9sYrsIcrzuEA30YeXsgUe3m44yxLCXczXWKE3kgGiZ0MRpVvKOZt4B2DZLcRmNArhxjhWWd1nKZvv8c7kN0TqOjcNEUGWzwDs4ikCSz1aYKaLPXgjzpKnzbajUM117F3aCAaWH9g\";\r\n\r\n// will echo provided payload back as return value, for consistency\r\nstring json = Jose.JWT.Decode(token, PubKey(), payload: @\"{\"\"hello\"\": \"\"world\"\"}\");\r\n\r\n// as of v5 can also be used with Verify:\r\nstring json = Jose.JWT.Verify(token, PubKey(), payload: @\"{\"\"hello\"\": \"\"world\"\"}\");\r\n```\r\n\r\nalso works with binary payloads:\r\n\r\n```C#\r\nstring token = \"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJSUzI1NiJ9..ToCewDcERVLuqImwDkOd9iSxvTC8vzh-HrhuohOIjWMrGpTZi2FdzVN4Ll3fb2Iz3s_hj-Lno_c6m_7VcmOHfRLC9sPjSu2q9dbNkKo8Zc2FQmsCBdQi06XGAEJZW2M9380pxoYKiJ51a4EbGl4Ag7lX3hXeTPYRMVifacgdlpg2SYZzDPZQbWvibgtXFsBsIqPd-8i6ucE2eMdaNeWMLsHv-b5s7uWn8hN2nMKHj000Qce5rSbpK58l2LNeWw4IR6wNOqSZfbeerMxq1u0p-ZKIQxP24MltaPjZtqMdD4AzjrP4UCEf7VaLSkSuNVSf6ZmLmE_OYgQuQe7adFdoPg\";\r\n\r\n// will echo provided payload back as return value, for consistency\r\nbyte[] payload = Jose.JWT.DecodeBytes(token, PubKey(), payload: BinaryPayload);\r\n```\r\n\r\n### Adding extra headers\r\njose-jwt allows to pass extra headers when encoding token to overide deafault values\u003csup\u003e\\*\u003c/sup\u003e. `extraHeaders:` named param can be used, it accepts `IDictionary\u003cstring, object\u003e` type.\r\njose-jwt is NOT allow to override `alg` and `enc` headers.\r\n\r\n```C#\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n     { \"sub\", \"mr.x@contoso.com\" },\r\n     { \"exp\", 1300819380 }\r\n};\r\n\r\nvar headers = new Dictionary\u003cstring, object\u003e()\r\n{\r\n     { \"typ\", \"JWT\" },\r\n     { \"cty\", \"JWT\" },\r\n     { \"keyid\", \"111-222-333\"}\r\n};\r\n\r\nvar secretKey = new byte[]{164,60,194,0,161,189,41,38,130,89,141,164,45,170,159,209,69,137,243,216,191,131,47,250,32,107,231,117,37,158,225,234};\r\n\r\nstring token = Jose.JWT.Encode(payload, secretKey, JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512, extraHeaders: headers);\r\n```\r\n\r\n```C#\r\nvar payload = new Dictionary\u003cstring, object\u003e()\r\n{\r\n    { \"sub\", \"mr.x@contoso.com\" },\r\n    { \"exp\", 1300819380 }\r\n};\r\n\r\nvar headers = new Dictionary\u003cstring, object\u003e()\r\n{\r\n     { \"typ\", \"JWT\" },\r\n     { \"cty\", \"JWT\" },\r\n     { \"keyid\", \"111-222-333\"}\r\n};\r\n\r\nvar privateKey=new X509Certificate2(\"my-key.p12\", \"password\", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;\r\n\r\nstring token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256, extraHeaders: headers);\r\n```\r\n\r\n\\* For backwards compatibility signing uses pre-configured `typ: 'JWT'` header by default.\r\n\r\n### Two-phase validation\r\nIn some cases validation (decoding) key can be unknown prior to examining token content. For instance one can use different keys per token issuer or rely on headers information to determine which key to use,\r\ndo logging or other things.\r\n\r\njose-jwt provides helper methods to examine token content without performing actual integrity validation or decryption.\r\n\r\n`IDictionary\u003cstring, object\u003e Jose.JWT.Headers(String token)` to return header information as dictionary and `T Jose.JWT.Headers\u003cT\u003e(string token)` to return headers information as\r\nunmarshalled type.\r\n\r\n`string Jose.JWT.Payload(string token)` to return unparsed payload and `T Jose.JWT.Payload\u003cT\u003e(string token)` to return unmarshalled payload type. Those 2 methods works only with\r\nsigned tokens and will throw `JoseException` when applied on encrypted token.\r\n\r\nWith JWE JSON (RFC 7516) serialized tokens `JweToken JWE.Headers()` method can be used for same purpose.\r\nIt will parse JSON structure into `JweToken` object and pre-populate effective headers (`JweRecipient.JoseHeader` property, see [JWE](#decoding-json-serialized-encrypted-content)) per every recipient in token. But will not perform actual decryption or integrity verification.\r\n\r\n**Security warning: please note, you should NOT rely on infromation extracted by given helpers without performing token validation as second step.**\r\n\r\nBelow are couple examples on how two-phase validation can be implemented with jose-jwt:\r\n```C#\r\n//step 1a: get headers info\r\nvar headers = Jose.JWT.Headers(token);\r\n\r\n//step 1b: lookup validation key based on header info\r\nvar key = FindKey(headers[\"keyid\"]);\r\n\r\n//step 2: perform actual token validation\r\nvar payload = Jose.JWT.Decode(token, key);\r\n```\r\n\r\n```C#\r\n//step 1a: get payload as custom JwtToken object\r\nvar jwt = Jose.JWT.Payload\u003cJwtToken\u003e(token);\r\n\r\n//step 1b: lookup validation key based on issuer\r\nvar key = FindKeyByIssuer(jwt.Iss);\r\n\r\n//step 2: perform actual token validation\r\nvar payload = Jose.JWT.Decode\u003cJwtToken\u003e(token, key);\r\n```\r\n\r\n```C#\r\n// Validate token with a public RSA key published by the IDP as a list of JSON Web Keys (JWK)\r\n// step 0: you've read the keys from the jwks_uri URL found in http://\u003cIDP authority URL\u003e/.well-known/openid-configuration endpoint\r\nDictionary\u003cstring, ServiceStack.Text.JsonObject\u003e keys = GetKeysFromIdp();\r\n\r\n// step 1a: get headers info\r\nvar headers = Jose.JWT.Headers(token);\r\n\r\n// step 1b: lookup validation key based on header info\r\nvar jwk = keys[headers[\"keyid\"]];\r\n\r\n// step 1c: load the JWK data into an RSA key\r\nRSACryptoServiceProvider key = new RSACryptoServiceProvider();\r\nkey.ImportParameters(new RSAParameters\r\n{\r\n    Modulus = Base64Url.Decode(jwk[\"n\"]),\r\n    Exponent = Base64Url.Decode(jwk[\"e\"])\r\n});\r\n\r\n// step 2: perform actual token validation\r\nvar paylod = Jose.JWT.Decode(token, key);\r\n```\r\n\r\n```C#\r\n// Validate JWE JSON token with dynamic key\r\n\r\n// step 1a: parse token, extract public JWK set and keyid for some recipient\r\nvar parsed = JWE.Headers(token);\r\nvar keysUrl = parsed.UnprotectedHeader[\"jku\"];\r\nvar keyId = parsed.Recipients[0].Header[\"keyid\"];\r\n\r\n// step 1b: find/retrieve/ensure actual key for decryption\r\nvar key = FindKey(keysUrl, keyId);\r\n\r\n// step 2: perform actual token validation\r\nvar payload = JWE.Decrypt(token, key).Plaintext;\r\n```\r\n\r\n### Strict validation\r\nIt is possible to use strict validation before decoding a token. This means that you will specify which algorithm and possibly encryption type you are expecting to receive in the header. If the received header doesn't match with the types that you have specified an exception will be thrown and the parsing will be stopped.\r\n\r\nAdditionally starting v5 `jose-jwt` offering dedicated methods:\r\n- `JWT.Verify()`, `JWT.VerifyBytes()` - same as `JWT.Decode()` but works only with signed tokens, use when you want to explicitly restrict only to signing algs.\r\n- `JWT.Decrypt()`, `JWT.DecryptBytes()` - same as `JWT.Decode()` but works only with encrypted tokens, use when you want to explicitly restrict only to encryption algs.\r\n\r\nBoth can be additionally combined with strict validation.\r\n\r\n\r\nExample of how to strictly validate an encrypted token:\r\n```C#\r\nstring token = \"eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Fmz3PLVfv-ySl4IJ.LMZpXMDoBIll5yuEs81Bws2-iUUaBSpucJPL-GtDKXkPhFpJmES2T136Vd8xzvp-3JW-fvpRZtlhluqGHjywPctol71Zuz9uFQjuejIU4axA_XiAy-BadbRUm1-25FRT30WtrrxKltSkulmIS5N-Nsi_zmCz5xicB1ZnzneRXGaXY4B444_IHxGBIS_wdurPAN0OEGw4xIi2DAD1Ikc99a90L7rUZfbHNg_iTBr-OshZqDbR6C5KhmMgk5KqDJEN8Ik-Yw.Jbk8ZmO901fqECYVPKOAzg\";\r\n\r\nbyte[] secretKey = new byte[] { 164, 60, 194, 0, 161, 189, 41, 38, 130, 89, 141, 164, 45, 170, 159, 209, 69, 137, 243, 216, 191, 131, 47, 250, 32, 107, 231, 117, 37, 158, 225, 234 };\r\n\r\nstring json = Jose.JWT.Decode(token, secretKey, JweAlgorithm.DIR, JweEncryption.A256GCM);\r\n\r\n// starting v5 also applies to dedicated methods\r\nstring json = Jose.JWT.Decrypt(token, secretKey, JweAlgorithm.DIR, JweEncryption.A256GCM);\r\n```\r\n\r\nExample of how to strictly validate a signed token:\r\n```C#\r\nstring token = \"eyJhbGciOiJFUzI1NiIsImN0eSI6InRleHRcL3BsYWluIn0.eyJoZWxsbyI6ICJ3b3JsZCJ9.EVnmDMlz-oi05AQzts-R3aqWvaBlwVZddWkmaaHyMx5Phb2NSLgyI0kccpgjjAyo1S5KCB3LIMPfmxCX_obMKA\";\r\n\r\nbyte[] x = { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };\r\nbyte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };\r\n\r\nvar publicKey = EccKey.New(x, y);\r\n\r\nstring json = Jose.JWT.Decode(token, publicKey, JwsAlgorithm.ES256);\r\n\r\n// starting v5 also applies to dedicated methods\r\nstring json = Jose.JWT.Verify(token, secretKey, JwsAlgorithm.ES256);\r\n```\r\n\r\n### Working with binary payload\r\n\r\nIt is possible to encode and decode JOSE objects that have a payload consisting of arbitrary binary data. The methods that work with a binary payload have the Bytes suffix in the name to distinguish them in cases of potential ambiguity, e.g. `EncodeBytes()`.\r\n\r\nExample of working with signed binary payloads in JOSE objects:\r\n```C#\r\nvar payload = new byte[] { 1, 2, 3, 0, 255 };\r\nvar signingKey = Convert.FromBase64String(\"WbQs8GowdRX1zYCFi3/VuQ==\");\r\n\r\n// Encoding a token with a binary payload.\r\nvar token = Jose.JWT.EncodeBytes(payload, signingKey, Jose.JwsAlgorithm.HS256);\r\n\r\n// Reading the binary payload from a token (with signature verification).\r\nvar decoded = Jose.JWT.DecodeBytes(token, signingKey);\r\n\r\n// Starting v5: reading the binary payload from a token (with signature verification) with explicit method\r\nvar decoded = Jose.JWT.VerifyBytes(token, signingKey);\r\n\r\n// Starting v5: reading the binary payload from a token (with decryption) with explicit method\r\nvar decoded = Jose.JWT.DecryptBytes(token, signingKey);\r\n\r\n// Reading the binary payload from a token (without signature verification).\r\ndecoded = Jose.JWT.PayloadBytes(token);\r\n```\r\n\r\n### Parsing and mapping json to object model directly\r\njose-jwt library is agnostic about object model used to represent json payload as well as underlying framework used to serialize/parse json objects. Library provides convinient generic methods to work directly with your object model:\r\n\r\n```C#\r\nMyDomainObject obj=Jose.JWT.Decode\u003cMyDomainObject\u003e(token,secretKey); //will invoke configured IJsonMapper to perform parsing/mapping of content to MyDomainObject\r\n\r\nstring data=Jose.JWT.Encode(obj,secrectKey,JwsAlgorithm.HS256); //for object argument configured IJsonMapper will be invoked to serialize object to json string before encoding\r\n```\r\n\r\n#### Potential security risk\r\nWhile deserializing a token, if a field is not provided in token (may due to payload schema changes), the field will remain its default value. This is Newtonsoft.Json's behavior. This hehavior is quite dangerous, which could give attacker chances.\r\n\r\nSuppose the payload class is `Payload`.\r\n\r\n``` cs\r\nclass Payload\r\n{\r\n    public int UserId { get; set; }\r\n}\r\n```\r\n\r\nLater the `Payload` class is changed to:\r\n\r\n```cs\r\nclass Payload\r\n{\r\n    public int Id { get; set; } // UserId -\u003e Id\r\n}\r\n```\r\nNow, if the library deserializes a token issued before the change of `Payload` class, proterty `Id` is not provided in the token and will remain its default value `0`. The payload data will be: `{Id = 0}`.\r\n\r\nThe user will get someone else's identity (id: 0) .\r\n\r\nSo developers should always use [nullable data types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types) for payload class properties.\r\n\r\n## Settings\r\nAs of v2.3.0 settings can be configured either globally or on a per-call basis using a `JwtSettings` object.  The `JWT.DefaultSettings` object can be modified to change global settings, or a `JwtSettings` instance can be passed to any public method on `JWT` to override the global settings for particular method call.\r\nIt is possible to provide custom implementations of:\r\n- specific signing `JwtSettings.RegisterJws(alg, impl)`\r\n- encryption,      `JwtSettings.RegisterJwe(alg, impl)`\r\n- key management   `JwtSettings.RegisterJwa(alg, impl)`\r\n- or compression   `JwtSettings.RegisterCompression(alg, impl)`\r\n- json mapper      `JwtSettings.RegisterMapper(mapper)`\r\n\r\nas well as specify aliases when decoding tokens from 3rd party libraries that do not comply exactly to spec:\r\n- signing `JwtSettings.RegisterJwsAlias(header, alg)`\r\n- encryption `JwtSettings.RegisterJweAlias(header, alg)`\r\n- key management `JwtSettings.RegisterJwaAlias(header, alg)`\r\n- compression `JwtSettings.RegisterCompressionAlias(header, alg)`\r\n\r\n### Example of JWTSettings\r\n\r\n```C#\r\n// global setting\r\nJose.JWT.DefaultSettings.JsonMapper = new Jose.NewtonsoftMapper();\r\n\r\n\r\nJose.JWTSettings settings = new Jose.JwtSettings();\r\nsettings.JsonMapper = new Jose.JSSerializerMapper();\r\n\r\n// override global settings for this call\r\nJose.JWT.Decode(token, secretKey, settings: settings);\r\n\r\n//or simply\r\nJose.JWT.Decode(token, secretKey, settings: new JwtSettings().RegisterMapper(new Jose.JSSerializerMapper()));\r\n\r\n// as of v5\r\nJose.JWT.Verify(token, secretKey, settings: settings);\r\nJose.JWT.Decrypt(token, secretKey, settings: settings);\r\n```\r\n\r\n### Customizing json \u003c-\u003e object parsing \u0026 mapping\r\nThe library provides simple `Jose.IJsonMapper` interface to plug any json processing library or customize default behavior. The only requirement for mapping implementations\r\nis ability to correctly serialize/parse `IDictionary\u003cstring,object\u003e` type.\r\n\r\nThe default supplied `Jose.IJsonMapper` implementation is based on `System.Web.Script.Serialization.JavaScriptSerializer`.\r\n\r\n#### Example of Newtonsoft.Json mapper\r\n\r\n```C#\r\npublic class NewtonsoftMapper : IJsonMapper\r\n{\r\n    public string Serialize(object obj)\r\n    {\r\n         var settings = new JsonSerializerSettings\r\n         {\r\n         \tContractResolver = new DictionaryKeysResolver(),\r\n         \tNullValueHandling = NullValueHandling.Ignore,\r\n         };\r\n\r\n        return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);\r\n    }\r\n\r\n    public T Parse\u003cT\u003e(string json)\r\n    {\r\n        var settings = new JsonSerializerSettings\r\n        {\r\n            ContractResolver = new DictionaryKeysResolver(),\r\n            NullValueHandling = NullValueHandling.Ignore,\r\n        };\r\n\r\n        return JsonConvert.DeserializeObject\u003cT\u003e(json, settings);\r\n    }\r\n}\r\n\r\nJose.JWT.DefaultSettings.JsonMapper = new NewtonsoftMapper();\r\n```\r\n\r\n#### Example of ServiceStack mapper\r\n```C#\r\npublic class ServiceStackMapper : IJsonMapper\r\n{\r\n    public string Serialize(object obj)\r\n    {\r\n        return ServiceStack.Text.JsonSerializer.SerializeToString(obj);\r\n    }\r\n\r\n    public T Parse\u003cT\u003e(string json)\r\n    {\r\n        return ServiceStack.Text.JsonSerializer.DeserializeFromString\u003cT\u003e(json);\r\n    }\r\n}\r\n\r\nJose.JWT.DefaultSettings.JsonMapper = new ServiceStackMapper();\r\n```\r\n\r\n### Customizing algorithm implementations\r\nThe default implementations of any of the signing, encryption, key management, or compression algorithms can be overridden.\r\n\r\n#### Example of custom algorithm implementation\r\n```C#\r\npublic class CustomKeyManagement : IKeyManagement\r\n{\r\n    public byte[] Unwrap(byte[] encryptedCek, object key, int cekSizeBits, IDictionary\u003cstring, object\u003e header)\r\n    {\r\n        // implement custom key unwrapping (e.g. using Amazon KMS for instance)\r\n    }\r\n\r\n    public byte[][] WrapNewKey(int cekSizeBits, object key, IDictionary\u003cstring, object\u003e header)\r\n    {\r\n        // implement custom key wrapping (e.g. using Amazon KMS for instance)\r\n    }\r\n}\r\n\r\n...\r\n\r\n// set default RSA-OAEP key management to use custom implementation\r\nJose.JWT.DefaultSettings.RegisterJwa(JweAlgorithm.RSA_OAEP, new CustomKeyManagement());\r\n```\r\n\r\n### Providing aliases\r\nIt is possible to add any number of aliases when decoding for signing, encryption, key management, or compression algorithms. For example if you are\r\ndealing with tokens produced from 3rd party library which you have no control over and by mistake it is using `RSA_OAEP_256` header value instead\r\nof `RSA-OAEP-256` it is possible to register alias:\r\n\r\n```C#\r\n   Jose.JWT.Decode(token, key, settings: new JwtSettings().RegisterJwaAlias(\"RSA_OAEP_256\", JweAlgorithm.RSA_OAEP_256));\r\n```\r\n\r\nMultiple calls can be chained for more convinience:\r\n\r\n```C#\r\nJose.JWT.Decode(token, secretKey, settings: new JwtSettings()\r\n\t\t\t\t\t\t.RegisterMapper(customMapper)\r\n\t\t\t\t\t\t.RegisterJws(JwsAlgorithm.RS256, amazonKmsImpl)\r\n\t\t\t\t\t\t.RegisterJws(JwsAlgorithm.RS384, amazonKmsImpl)\r\n\t\t\t\t\t\t.RegisterJws(JwsAlgorithm.RS512, amazonKmsImpl)\r\n\t\t\t\t\t\t.RegisterJwa(JweAlgorithm.RSA_OAEP_256, hsmImpl)\r\n\t\t\t\t\t\t.RegisterJwe(JweEncryption.A128GCM, linuxGcmImpl)\r\n\t\t\t\t\t\t.RegisterJwaAlias(\"RSA_OAEP_256\", JweAlgorithm.RSA_OAEP_256)\r\n\t\t\t\t\t\t.RegisterCompression(JweCompression.DEF, hardwareAcceleratedDeflate)\r\n);\r\n```\r\n\r\n## Customizing library for security\r\nIn response to ever increasing attacks on various JWT implementations, `jose-jwt` as of version v4.1 and beyond introduced number of additional security controls to limit potential attack surface on services and projects using the library.\r\n\r\n### Deregister algorithm implementations\r\nOne can use following methods to deregister any signing, encryption, key management or compression algorithms from runtime suite, that is considered unsafe or simply not expected by service.\r\n\r\n - `JwtSettings.DeregisterJws(JwsAlgorithm alg)` - to remove signing algorithm\r\n - `JwtSettings.DeregisterJwa(JweAlgorithm alg))` - to remove key management algorithm\r\n - `JwtSettings.DeregisterJwe(JweEncryption alg)` - to remove signing algorithm\r\n - `JwtSettings.DeregisterCompression(JweCompression alg)` - to remove signing algorithm\r\n\r\n ```c#\r\n    JWT.DefaultSettings.DeregisterJws(JwsAlgorithm.none)\r\n                       .DeregisterJwe(JweAlgorithm.RSA1_5)\r\n                       .DeregisterJwe(JweAlgorithm.DIR)\r\n                       .DeregisterCompression(JweCompression.DEF);\r\n ```\r\n\r\n### Customizing compression\r\nThere were denial-of-service attacks reported on JWT libraries that supports deflate compression by constructing malicious payload that explodes in terms of RAM on decompression. See for details: https://github.com/dvsekhvalnov/jose-jwt/issues/237\r\n\r\nAs of v5 `jose-jwt` limits decompression buffer to 250Kb to limit memory consumption and additionaly provides a way to adjust the limit according to specific scenarios:\r\n\r\n``` cs\r\n    // Override compression alg with new limits (10Kb example)\r\n    Jose.JWT.DefaultSettings.RegisterCompression(JweCompression.DEF, new DeflateCompression(10 * 1024));\r\n```\r\n\r\n### Customizing PBKDF2\r\nAs it quite easy to abuse `PBES2` family of algorithms via forging header with extra large `p2c` values, `jose-jwt` library introduced iteration count limits in v4.1 to reduce runtime exposure.\r\n\r\nBy default, `maxIterations` is set according to [OWASP PBKDF2 Recomendations](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2)\r\n\r\n        PBES2-HS256+A128KW: 310000\r\n        PBES2-HS384+A192KW: 250000\r\n        PBES2-HS512+A256KW: 120000\r\n\r\n, while `minIterations` kept at `0` for backward compatibility.\r\n\r\nIf it is desired to implement different limits, it can be achieved via registering `Pbse2HmacShaKeyManagementWithAesKeyWrap` implementation with different parameters:\r\n\r\n```c#\r\n    Jose.JWT.DefaultSettings\r\n        // Pick your own min/max limits\r\n        .RegisterJwe(JweAlgorithm.PBES2_HS256_A128KW, new Pbse2HmacShaKeyManagementWithAesKeyWrap(128, new AesKeyWrapManagement(128), 310000, 310000));\r\n        .RegisterJwe(JweAlgorithm.PBES2_HS384_A192KW, new Pbse2HmacShaKeyManagementWithAesKeyWrap(192, new AesKeyWrapManagement(192), 250000, 250000));\r\n        .RegisterJwe(JweAlgorithm.PBES2_HS512_A256KW, new Pbse2HmacShaKeyManagementWithAesKeyWrap(256, new AesKeyWrapManagement(256), 120000, 120000));\r\n```\r\n\r\nIn case you can't upgrade to latest version, but would like to have protections against `PBES2` abuse, it is recommended to stick with [Two-phase validation](#two-phase-validation) precheck before decoding:\r\n\r\n```c#\r\n    IDictionary\u003cstring, object\u003e headers = Jose.JWT.Headers(token);\r\n\r\n    string alg = (string)headers[\"alg\"];\r\n    long p2c = Convert.ToInt32(headers[\"p2c\"]);\r\n\r\n    if(alg.StartsWith(\"PBES2-\") \u0026\u0026 p2c \u003e 310000)\r\n    {\r\n        // potentially can be forged/abused token\r\n    }\r\n    else\r\n    {\r\n        // continue with decoding routine\r\n        Jose.JWT.Decode(token, key);\r\n    }\r\n```\r\n\r\n### Confusion attacks and how to nail them\r\nThere are number of algorithm confusion attacks reported in general on different JWT libraries in recent years. Typically attacks exploits public keys published on server side (or obtained by other means) via forging bogus JWT tokens signed or encrypted with given public key but with tampered alg header to confuse server validation implementation (hence the attack name). For example take a look at https://github.com/dvsekhvalnov/jose-jwt/issues/236\r\n\r\nBy nature most of confusion attacks targeting specific usage of libraries rather then libraries itself, as library can't predict in what type of applications and conditions it will be used.\r\n\r\nHere are some design practices to consider in your applications to avoid confusion attacks with `jose-jwt`:\r\n\r\n1. Clearly separate your signing and encryption keys. **Do not allow** to use signing keys to decrypt tokens and vice versa.\r\n\r\n2. When you can, **be explicit** whether you working with signed or encrypted tokens. As of v5 library provides dedicated verification methods: `Verify()` and `Decrypt()`\r\n\r\n3. Use [Strict Validation](#strict-validation) and **assert algorithms** explicitly if possible.\r\n\r\n4. Always good idea to [deregister](#deregister-algorithm-implementations) algorithms you are **not planning to use** to limit attack surface.\r\n\r\n5. For highly dynamic environments consider [two-phase validation](#two-phase-validation) practice to implement more flexible protection measures.\r\n\r\n\r\n## More examples\r\nCheckout [UnitTests/TestSuite.cs](UnitTests/TestSuite.cs) for more examples.\r\n\r\n## Dealing with keys\r\nBelow is collection of links and approaches to nail down some common questions around key management:\r\n\r\n### RSACryptoServiceProvider\r\nWhen you dealing with `RSACryptoServiceProvider` you can face `Invalid algorithm specified` exception while performing signing or encryption operations. The reason usually is that underneath `RSACryptoServiceProvider` is not using Microsoft Enhanced RSA and AES Cryptographic Provider. There are several ways to fix that:\r\n\r\n1. re-import RSAParameters:\r\n\r\n  ```C#\r\n  public static RSACryptoServiceProvider FixCSP(RSACryptoServiceProvider key)\r\n  {\r\n      var privKey = key.PrivateKey;\r\n\r\n      RSACryptoServiceProvider newKey = new RSACryptoServiceProvider();\r\n      newKey.ImportParameters(privKey.ExportParameters(true));\r\n\r\n      return newKey;\r\n  }\r\n  ```\r\n\r\n  The limitation of this approach is that private key should be marked exportable. It is not recommended for production environments but can be handy for testing.\r\n\r\n1. Enforce correct CSP:\r\n  ```C#\r\n  public static RSACryptoServiceProvider FixCSP(RSACryptoServiceProvider key)\r\n  {\r\n      var privKey = key.PrivateKey;\r\n      var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;\r\n      var cspParams = new CspParameters(enhCsp.ProviderType, enhCsp.ProviderName, privKey.CspKeyContainerInfo.KeyContainerName);\r\n\r\n      return new RSACryptoServiceProvider(cspParams);\r\n  }\r\n  ```\r\n\r\n  For more details see: http://stackoverflow.com/questions/7444586/how-can-i-sign-a-file-using-rsa-and-sha256-with-net\r\n\r\n1. Actually use certificate which supports SHA-2, see http://hintdesk.com/c-how-to-fix-invalid-algorithm-specified-when-signing-with-sha256/ for details how to create one.\r\n\r\n### If you have only RSA private key\r\nE.g. if you don't have .p12 file where certificate is combined with private key that can be loaded via `X509Certificate2` but rather have\r\nonly private key:\r\n ```\r\n -----BEGIN RSA PRIVATE KEY-----\r\n ............................\r\n -----END RSA PRIVATE KEY-----\r\n ```\r\n\r\nThen take a look at: http://www.donaldsbaconbytes.com/2016/08/create-jwt-with-a-private-rsa-key/\r\n\r\n## Strong-Named assembly\r\n`jose-jwt` is not providing standalone strong-named assembly as of now. If you need one in your project, please take a look at https://github.com/dvsekhvalnov/jose-jwt/issues/5\r\n\r\nUsually people have success with https://github.com/brutaldev/StrongNameSigner\r\n\r\n## ASP.NET Core MVC JWT Authentication\r\n\r\n### Securing Controllers Using AuthorizeAttribute\r\n\r\nASP.NET Team provides [Microsoft.AspNetCore.Authentication.JwtBearer](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer/) that can be used to authorize web service routes using JWT Tokens created using JOSE-JWT that are passed via `Authorize: Bearer` HTTP header.\r\n\r\nIn `startup.cs`, you can add JWT Authorization middleware by passing options to the `services.AddAuthentication` extension method in `void Configure` method.\r\n\r\nBelow is the example for setting up the middleware using HS-\\* signed token:\r\n\r\n```csharp\r\nusing System;\r\nusing System.Text;\r\nusing Microsoft.IdentityModel.Tokens;\r\nusing Microsoft.AspNetCore.Builder;\r\n\r\n// The key length needs to be of sufficient length, or otherwise an error will occur.\r\nvar tokenSecretKey = Encoding.UTF8.GetBytes(Configuration[\"TokenSecretKey\"]);\r\n\r\nvar tokenValidationParameters = new TokenValidationParameters\r\n{\r\n    // Token signature will be verified using a private key.\r\n    ValidateIssuerSigningKey = true,\r\n    RequireSignedTokens = true,\r\n    IssuerSigningKey = new SymmetricSecurityKey(tokenSecretKey),\r\n\r\n    // Token will only be valid if contains \"accelist.com\" for \"iss\" claim.\r\n    ValidateIssuer = true,\r\n    ValidIssuer = \"accelist.com\",\r\n\r\n    // Token will only be valid if contains \"accelist.com\" for \"aud\" claim.\r\n    ValidateAudience = true,\r\n    ValidAudience = \"accelist.com\",\r\n\r\n    // Token will only be valid if not expired yet, with 5 minutes clock skew.\r\n    ValidateLifetime = true,\r\n    RequireExpirationTime = true,\r\n    ClockSkew = new TimeSpan(0, 5, 0),\r\n\r\n    ValidateActor = false,\r\n};\r\n\r\nservices.AddAuthentication(options =\u003e\r\n        {\r\n            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\r\n            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\r\n        }).AddJwtBearer(options =\u003e { options.TokenValidationParameters = tokenValidationParameters; });\r\n```\r\n\r\nAfter that, your Controllers or Actions can be secured by using `[Authorize]` attribute.\r\n\r\nIn addition, certain JWT reserved claims will be automatically be populated into `HttpContext.User` as the following Claim Type (from `System.Security.Claims` namespace):\r\n\r\n|JWT Claim Name|Data Type     |Claim Type                 |\r\n|--------------|--------------|---------------------------|\r\n|sub           |`string`      |`ClaimTypes.NameIdentifier`|\r\n|email         |`string`      |`ClaimTypes.Email`         |\r\n|unique_name   |`string`      |`ClaimTypes.Name`          |\r\n|roles         |`List\u003cstring\u003e`|`ClaimTypes.Role`          |\r\n\r\n*This list is anything but complete. There might be more claims that are transformed but not listed yet.*\r\n\r\nTherefore, you can use role-based authorization as well, for example: `[Authorize(Roles = \"Administrator\")]`\r\n\r\nIf you wish to do more than one type of authentication to separate routes, you should use `app.UseWhen`, for example:\r\n\r\n```csharp\r\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\r\n{\r\n    app.UseStaticFiles();\r\n    AuthenticateUI(app);\r\n    AuthenticateAPI(app);\r\n    app.UseMvc(routes =\u003e\r\n    {\r\n        routes.MapRoute(\r\n            name: \"default\",\r\n            template: \"{controller=Home}/{action=Index}/{id?}\");\r\n    });\r\n}\r\n\r\npublic void AuthenticateAPI(IApplicationBuilder app)\r\n{\r\n    // IsAPI method returns TRUE when a request route is started with \"/api\".\r\n    // For those routes, we'll use JWT Authorization:\r\n    app.UseWhen(context =\u003e IsAPI(context), builder =\u003e\r\n    {\r\n        builder.UseJwtBearerAuthentication(new JwtBearerOptions\r\n        {\r\n            AutomaticAuthenticate = true,\r\n            TokenValidationParameters = tokenValidationParameters,\r\n        });\r\n    });\r\n}\r\n\r\npublic void AuthenticateUI(IApplicationBuilder app)\r\n{\r\n    // For non-API routes, we'll use Cookie Authorization, as an example.\r\n    app.UseWhen(context =\u003e !IsAPI(context), builder =\u003e\r\n    {\r\n        builder.UseCookieAuthentication(new CookieAuthenticationOptions\r\n        {\r\n            AuthenticationScheme = \"Accelist_Identity\",\r\n            LoginPath = new PathString(\"/auth/login\"),\r\n            AutomaticAuthenticate = true,\r\n            AutomaticChallenge = true\r\n        });\r\n    });\r\n}\r\n```\r\n\r\n### Creating and Using a JWT Token\r\n\r\nWe can use an MVC web API to accept a request containing a user's credentials in exchange for a JWT token.\r\n\r\n```csharp\r\npublic class TokenRequest\r\n{\r\n    [Required]\r\n    public string Username { set; get; }\r\n\r\n    [Required]\r\n    public string Password { set; get; }\r\n}\r\n\r\n[Route(\"api/v1/token\")]\r\npublic class TokenApiController : Controller\r\n{\r\n    private readonly AuthService AuthService;\r\n\r\n    public TokenApiController(AuthService authService)\r\n    {\r\n        // AuthService is your own class that handles your application's authentication functions.\r\n        // AuthService is injected via Controller's constructor and registered At startup.cs\r\n        // Read more: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection\r\n        this.AuthService = authService;\r\n    }\r\n\r\n    [HttpPost]\r\n    public async Task\u003cIActionResult\u003e Post([FromBody]TokenRequest model)\r\n    {\r\n        if (ModelState.IsValid == false)\r\n        {\r\n            return BadRequest(\"Username and password must not be empty!\");\r\n        }\r\n\r\n        // Authenticates username and password to your SQL Server database, for example.\r\n        // If authentication is successful, return a user's claims.\r\n        var claims = await AuthService.TryLogin(model.Username, model.Password);\r\n        if (claims == null)\r\n        {\r\n            return BadRequest(\"Invalid username or password!\");\r\n        }\r\n\r\n        // As an example, AuthService.CreateToken can return Jose.JWT.Encode(claims, YourTokenSecretKey, Jose.JwsAlgorithm.HS256);\r\n        var token = AuthService.CreateToken(claims);\r\n        return Ok(token);\r\n    }\r\n}\r\n```\r\n\r\nTherefore, by sending a HTTP POST request containing `Username` and `Password` to that endpoint, you will receive a token that is signed by the server.\r\n\r\nExample for making a request from the client using JavaScript Promise using [AngularJS](https://angularjs.org/) [$http](https://docs.angularjs.org/api/ng/service/$http):\r\n\r\n```javascript\r\n$http.post(\"/api/v1/token\", {\r\n    username: \"foo\",\r\n    password: \"bar\"\r\n}).then(function(response) {\r\n    // Request successful.\r\n    MyToken = response.data;\r\n}, function(response) {\r\n    // Request failed! Do something with the response.\r\n});\r\n```\r\n\r\nThen later, you can use the obtained token for sending requests to secured routes by attaching it to the request header.\r\n\r\n```javascript\r\n$http.post(\"/api/v1/function\", {\r\n    foo: \"bar\"\r\n}, {\r\n    headers: {\r\n        Authorization: \"Bearer \" + MyToken\r\n    }\r\n}).then(function(response) {\r\n    // Request successful. Do something with the response.\r\n}, function(response) {\r\n    // Request failed! Do something with the response.\r\n});\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvsekhvalnov%2Fjose-jwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdvsekhvalnov%2Fjose-jwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdvsekhvalnov%2Fjose-jwt/lists"}