{"id":13631910,"url":"https://github.com/jedisct1/rust-jwt-simple","last_synced_at":"2025-05-14T13:06:36.444Z","repository":{"id":37996178,"uuid":"291130821","full_name":"jedisct1/rust-jwt-simple","owner":"jedisct1","description":"A secure, standard-conformant, easy to use JWT implementation for Rust.","archived":false,"fork":false,"pushed_at":"2025-05-07T12:30:30.000Z","size":318,"stargazers_count":250,"open_issues_count":0,"forks_count":60,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-07T13:34:59.591Z","etag":null,"topics":["api","auth0","authentication","crypto","json","jsonwebtokens","jws","jwt","okta","rust","simple","tokens","web"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/jwt-simple","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jedisct1.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,"zenodo":null}},"created_at":"2020-08-28T19:34:24.000Z","updated_at":"2025-05-07T12:30:35.000Z","dependencies_parsed_at":"2023-02-10T09:16:08.113Z","dependency_job_id":"de479e65-a1e3-4ff1-9532-fe3710b5e882","html_url":"https://github.com/jedisct1/rust-jwt-simple","commit_stats":{"total_commits":249,"total_committers":13,"mean_commits":"19.153846153846153","dds":0.05622489959839361,"last_synced_commit":"ee0e608ccc64bf8768c1ac71a8ef16d021a02968"},"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Frust-jwt-simple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Frust-jwt-simple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Frust-jwt-simple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Frust-jwt-simple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jedisct1","download_url":"https://codeload.github.com/jedisct1/rust-jwt-simple/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254149953,"owners_count":22022851,"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":["api","auth0","authentication","crypto","json","jsonwebtokens","jws","jwt","okta","rust","simple","tokens","web"],"created_at":"2024-08-01T22:02:43.667Z","updated_at":"2025-05-14T13:06:31.430Z","avatar_url":"https://github.com/jedisct1.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"[![GitHub CI](https://github.com/jedisct1/rust-jwt-simple/workflows/Rust/badge.svg)](https://github.com/jedisct1/rust-jwt-simple/actions)\n[![Docs.rs](https://docs.rs/jwt-simple/badge.svg)](https://docs.rs/jwt-simple/)\n[![crates.io](https://img.shields.io/crates/v/jwt-simple.svg)](https://crates.io/crates/jwt-simple)\n\n\u003c!-- @import \"[TOC]\" {cmd=\"toc\" depthFrom=1 depthTo=6 orderedList=false} --\u003e\n\n\u003c!-- code_chunk_output --\u003e\n\n- [JWT-Simple](#jwt-simple)\n  - [Usage](#usage)\n  - [Authentication (symmetric, `HS*` JWT algorithms) example](#authentication-symmetric-hs-jwt-algorithms-example)\n    - [Keys and tokens creation](#keys-and-tokens-creation)\n    - [Token verification](#token-verification)\n  - [Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example](#signatures-asymmetric-rs-ps-es-and-eddsa-algorithms-example)\n    - [Key pairs and tokens creation](#key-pairs-and-tokens-creation)\n      - [ES256](#es256)\n      - [ES384](#es384)\n  - [Advanced usage](#advanced-usage)\n    - [Custom claims](#custom-claims)\n    - [Peeking at metadata before verification](#peeking-at-metadata-before-verification)\n    - [Creating and attaching key identifiers](#creating-and-attaching-key-identifiers)\n    - [Mitigations against replay attacks](#mitigations-against-replay-attacks)\n    - [CWT (CBOR) support](#cwt-cbor-support)\n  - [Working around compilation issues with the `boring` crate](#working-around-compilation-issues-with-the-boring-crate)\n  - [Usage in Web browsers](#usage-in-web-browsers)\n  - [Why yet another JWT crate](#why-yet-another-jwt-crate)\n\n\u003c!-- /code_chunk_output --\u003e\n\n# JWT-Simple\n\nA new JWT (JSON Web Tokens) implementation for Rust that focuses on simplicity, while avoiding common JWT security pitfalls.\n\n`jwt-simple` is unopinionated and supports all commonly deployed authentication and signature algorithms:\n\n| JWT algorithm name | Description                           |\n| ------------------ | ------------------------------------- |\n| `HS256`            | HMAC-SHA-256                          |\n| `HS384`            | HMAC-SHA-384                          |\n| `HS512`            | HMAC-SHA-512                          |\n| `BLAKE2B`          | BLAKE2B-256                           |\n| `RS256`            | RSA with PKCS#1v1.5 padding / SHA-256 |\n| `RS384`            | RSA with PKCS#1v1.5 padding / SHA-384 |\n| `RS512`            | RSA with PKCS#1v1.5 padding / SHA-512 |\n| `PS256`            | RSA with PSS padding / SHA-256        |\n| `PS384`            | RSA with PSS padding / SHA-384        |\n| `PS512`            | RSA with PSS padding / SHA-512        |\n| `ES256`            | ECDSA over p256 / SHA-256             |\n| `ES384`            | ECDSA over p384 / SHA-384             |\n| `ES256K`           | ECDSA over secp256k1 / SHA-256        |\n| `EdDSA`            | Ed25519                               |\n\n`jwt-simple` can be compiled out of the box to WebAssembly/WASI. It is fully compatible with Fastly _Compute_ service.\n\nImportant: JWT's purpose is to verify that data has been created by a party knowing a secret key. It does not provide any kind of confidentiality: JWT data is simply encoded as BASE64, and is not encrypted.\n\n## Usage\n\n`cargo.toml`:\n\n```toml\n[dependencies]\njwt-simple = \"0.12\"\n```\n\nRust:\n\n```rust\nuse jwt_simple::prelude::*;\n```\n\nErrors are returned as `jwt_simple::Error` values (alias for the `Error` type of the `thiserror` crate).\n\n## Authentication (symmetric, `HS*` JWT algorithms) example\n\nAuthentication schemes use the same key for creating and verifying tokens. In other words, both parties need to ultimately trust each other, or else the verifier could also create arbitrary tokens.\n\n### Keys and tokens creation\n\nKey creation:\n\n```rust\nuse jwt_simple::prelude::*;\n\n// create a new key for the `HS256` JWT algorithm\nlet key = HS256Key::generate();\n```\n\nA key can be exported as bytes with `key.to_bytes()`, and restored with `HS256Key::from_bytes()`.\n\nToken creation:\n\n```rust\n/// create claims valid for 2 hours\nlet claims = Claims::create(Duration::from_hours(2));\nlet token = key.authenticate(claims)?;\n```\n\n-\u003e Done!\n\n### Token verification\n\n```rust\nlet claims = key.verify_token::\u003cNoCustomClaims\u003e(\u0026token, None)?;\n```\n\n-\u003e Done! No additional steps required.\n\nKey expiration, start time, authentication tags, etc. are automatically verified. The function fails with `JWTError::InvalidAuthenticationTag` if the authentication tag is invalid for the given key.\n\nThe full set of claims can be inspected in the `claims` object if necessary. `NoCustomClaims` means that only the standard set of claims is used by the application, but application-defined claims can also be supported.\n\nExtra verification steps can optionally be enabled via the `ValidationOptions` structure:\n\n```rust\nlet mut options = VerificationOptions::default();\n// Accept tokens that will only be valid in the future\noptions.accept_future = true;\n// Accept tokens even if they have expired up to 15 minutes after the deadline,\n// and/or they will be valid within 15 minutes.\n// Note that 15 minutes is the default, since it is very common for clocks to be slightly off.\noptions.time_tolerance = Some(Duration::from_mins(15));\n// Reject tokens if they were issued more than 1 hour ago\noptions.max_validity = Some(Duration::from_hours(1));\n// Reject tokens if they don't include an issuer from that set\noptions.allowed_issuers = Some(HashSet::from_strings(\u0026[\"example app\"]));\n\n// see the documentation for the full list of available options\n\nlet claims = key.verify_token::\u003cNoCustomClaims\u003e(\u0026token, Some(options))?;\n```\n\nNote that `allowed_issuers` and `allowed_audiences` are not strings, but sets of strings (using the `HashSet` type from the Rust standard library), as the application can allow multiple return values.\n\n## Signatures (asymmetric, `RS*`, `PS*`, `ES*` and `EdDSA` algorithms) example\n\nA signature requires a key pair: a secret key used to create tokens, and a public key, that can only verify them.\n\nAlways use a signature scheme if both parties do not ultimately trust each other, such as tokens exchanged between clients and API providers.\n\n### Key pairs and tokens creation\n\nKey creation:\n\n#### ES256\n\n```rust\nuse jwt_simple::prelude::*;\n\n// create a new key pair for the `ES256` JWT algorithm\nlet key_pair = ES256KeyPair::generate();\n\n// a public key can be extracted from a key pair:\nlet public_key = key_pair.public_key();\n```\n\n#### ES384\n\n```rust\nuse jwt_simple::prelude::*;\n\n// create a new key pair for the `ES384` JWT algorithm\nlet key_pair = ES384KeyPair::generate();\n\n// a public key can be extracted from a key pair:\nlet public_key = key_pair.public_key();\n```\n\nKeys can be exported as bytes for later reuse, and imported from bytes or, for RSA, from individual parameters, DER-encoded data or PEM-encoded data.\n\nRSA key pair creation, using OpenSSL and PEM importation of the secret key:\n\n```sh\nopenssl genrsa -out private.pem 2048\nopenssl rsa -in private.pem -outform PEM -pubout -out public.pem\n```\n\n```rust\nlet key_pair = RS384KeyPair::from_pem(private_pem_file_content)?;\nlet public_key = RS384PublicKey::from_pem(public_pem_file_content)?;\n```\n\nToken creation and verification work the same way as with `HS*` algorithms, except that tokens are created with a key pair, and verified using the corresponding public key.\n\nToken creation:\n\n```rust\n/// create claims valid for 2 hours\nlet claims = Claims::create(Duration::from_hours(2));\nlet token = key_pair.sign(claims)?;\n```\n\nToken verification:\n\n```rust\nlet claims = public_key.verify_token::\u003cNoCustomClaims\u003e(\u0026token, None)?;\n```\n\nAvailable verification options are identical to the ones used with symmetric algorithms.\n\n## Advanced usage\n\n### Custom claims\n\nClaim objects support all the standard claims by default, and they can be set directly or via convenient helpers:\n\n```rust\nlet claims = Claims::create(Duration::from_hours(2)).\n    with_issuer(\"Example issuer\").with_subject(\"Example subject\");\n```\n\nBut application-defined claims can also be defined. These simply have to be present in a serializable type (this requires the `serde` crate):\n\n```rust\n#[derive(Serialize, Deserialize)]\nstruct MyAdditionalData {\n   user_is_admin: bool,\n   user_country: String,\n}\nlet my_additional_data = MyAdditionalData {\n   user_is_admin: false,\n   user_country: \"FR\".to_string(),\n};\n```\n\nClaim creation with custom data:\n\n```rust\nlet claims = Claims::with_custom_claims(my_additional_data, Duration::from_secs(30));\n```\n\nClaim verification with custom data. Note the presence of the custom data type:\n\n```rust\nlet claims = public_key.verify_token::\u003cMyAdditionalData\u003e(\u0026token, None)?;\nlet user_is_admin = claims.custom.user_is_admin;\n```\n\n### Peeking at metadata before verification\n\nProperties such as the key identifier can be useful prior to tag or signature verification in order to pick the right key out of a set.\n\n```rust\nlet metadata = Token::decode_metadata(\u0026token)?;\nlet key_id = metadata.key_id();\nlet algorithm = metadata.algorithm();\n// all other standard properties are also accessible\n```\n\n**IMPORTANT:** neither the key ID nor the algorithm can be trusted. This is an unfixable design flaw of the JWT standard.\n\nAs a result, `algorithm` should be used only for debugging purposes, and never to select a key type.\nSimilarly, `key_id` should be used only to select a key in a set of keys made for the same algorithm.\n\nAt the bare minimum, verification using `HS*` must be prohibited if a signature scheme was originally used to create the token.\n\n### Creating and attaching key identifiers\n\nKey identifiers indicate to verifiers what public key (or shared key) should be used for verification.\nThey can be attached at any time to existing shared keys, key pairs and public keys:\n\n```rust\nlet public_key_with_id = public_key.with_key_id(\u0026\"unique key identifier\");\n```\n\nInstead of delegating this to applications, `jwt-simple` can also create such an identifier for an existing key:\n\n```rust\nlet key_id = public_key.create_key_id();\n```\n\nThis creates an text-encoded identifier for the key, attaches it, and returns it.\n\nIf an identifier has been attached to a shared key or a key pair, tokens created with them will include it.\n\n### Mitigations against replay attacks\n\n`jwt-simple` includes mechanisms to mitigate replay attacks:\n\n- Nonces can be created and attached to new tokens using the `create_nonce()` claim function. The verification procedure can later reject any token that doesn't include the expected nonce (`required_nonce` verification option).\n- The verification procedure can reject tokens created too long ago, no matter what their expiration date is. This prevents tokens from malicious (or compromised) signers from being used for too long.\n- The verification procedure can reject tokens created before a date. For a given user, the date of the last successful authentication can be stored in a database, and used later along with this option to reject older (replayed) tokens.\n\n### Salted keys\n\nSymmetric keys, such as the ones use with the `HS256`, `HS384`, `HS512` and `BLAKE2B` algorithms, are simple and fast, but have a major downside: signature and verification use the exact same key. Therefore, an adversary having access to the verifier key can forge arbitrary, valid tokens.\n\nSalted keys mitigate this issue the following way:\n\n- A random signer salt is created, and attached to the shared key. This salt is meant to be only known by the signer.\n- Another salt is computed from the signer salt, and is meant to be used for verification.\n- The verifier salt is used to verify the signer salt, which is included in tokens, in the `salt` JWT header.\n\nIf the verifier has access to tokens, it can forge arbitrary tokens. But given only the verification code and keys, this is impossible. This greatly improve the security of symmetric keys used for verification on 3rd party servers, such as CDNs.\n\nA salt binds to a key, and can be of any length. The `generate_with_salt()` function generates both a random symmetric key, and a 32-byte salt.\n\nExample usage:\n\n```rust\n/// Create a random key and a signer salt\nlet key = HS256Key::generate_with_salt();\nlet claims = Claims::create(Duration::from_secs(86400));\nlet token = key.authenticate(claims).unwrap();\n```\n\nA salt is a `Salt` enum, because it can be either a salt for signing, or a salt for verification.\nIt can be saved and restored:\n\n```rust\n/// Get the salt\nlet salt = key.salt();\n/// Attach an existing salt to a key\nkey.attach_salt(salt)?;\n```\n\nGiven a signer salt, the corresponding verifier salt can be computed:\n\n```rust\n/// Compute the verifier salt, given a signer salt\nlet verifier_salt = key.verifier_salt()?;\n```\n\nThe verifier salt doesn't have to be secret, and can even be hard-coded in the verification code.\n\nVerification:\n\n```rust\nlet verifier_salt = Salt::Verifier(verifier_salt_bytes);\nkey.attach_salt(verifier_salt)?;\nlet claims = key.verify_token::\u003cNoCustomClaims\u003e(\u0026token, None)?;\n```\n\n### CWT (CBOR) support\n\nThe development code includes a `cwt` cargo feature that enables experimental parsing and validation of CWT tokens.\n\nPlease note that CWT doesn't support custom claims. The required identifiers [haven't been standardized yet](https://www.iana.org/assignments/cwt/cwt.xhtml).\n\nAlso, the existing Rust crates for JSON and CBOR deserialization are not safe. An untrusted party can send a serialized object that requires a lot of memory and CPU to deserialize. Band-aids have been added for JSON, but with the current Rust tooling, it would be tricky to do for CBOR.\n\nAs a mitigation, we highly recommend rejecting tokens that would be too large in the context of your application. That can be done by with the `max_token_length` verification option.\n\n## Working around compilation issues with the `boring` crate\n\nAs a temporary workaround for portability issues with one of the dependencies (the `boring` crate), this library can be compiled to use only Rust implementations.\n\nIn order to do so, import the crate with `default-features=false, features=[\"pure-rust\"]` in your Cargo configuration.\n\nDo not do it unconditionally. This is only required for very specific setups and targets, and only until issues with the `boring` crate have been solved. The way to configure this in Cargo may also change in future versions.\n\nStatic builds targeting the `musl` library don't require that workaround. Just use [`cargo-zigbuild`](https://github.com/rust-cross/cargo-zigbuild) to build your project.\n\n## Usage in Web browsers\n\nThe `wasm32-freestanding` target (still sometimes called `wasm32-unknown-unknown` in Rust) is supported (as in \"it compiles\").\n\nHowever, using a native JavaScript implementation is highly recommended instead. There are high-quality JWT implementations in JavaScript, leveraging the WebCrypto API, that provide better performance and security guarantees than a WebAssembly module.\n\n## Why yet another JWT crate\n\nThis crate is not an endorsement of JWT. JWT is [an awful design](https://tools.ietf.org/html/rfc8725), and one of the many examples that \"but this is a standard\" doesn't necessarily mean that it is good.\n\nI would highly recommend [PASETO](https://github.com/paragonie/paseto) or [Biscuit](https://github.com/CleverCloud/biscuit) instead if you control both token creation and verification.\n\nHowever, JWT is still widely used in the industry, and remains absolutely mandatory to communicate with popular APIs.\n\nThis crate was designed to:\n\n- Be simple to use, even to people who are new to Rust\n- Avoid common JWT API pitfalls\n- Support features widely in use. I'd love to limit the algorithm choices to Ed25519, but other methods are required to connect to existing APIs, so just provide them (with the exception of the `None` signature method for obvious reasons).\n- Minimize code complexity and external dependencies\n- Automatically perform common tasks to prevent misuse. Signature verification and claims validation happen automatically instead of relying on applications.\n- Still allow power users to access everything JWT tokens include if they really need to\n- Work out of the box in a WebAssembly environment, so that it can be used in function-as-a-service platforms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Frust-jwt-simple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjedisct1%2Frust-jwt-simple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Frust-jwt-simple/lists"}