{"id":21034449,"url":"https://github.com/zkemail/noir-jwt","last_synced_at":"2026-03-05T23:42:03.871Z","repository":{"id":262211854,"uuid":"886540711","full_name":"zkemail/noir-jwt","owner":"zkemail","description":"Noir library to verify JWT tokens, and prove claims.","archived":false,"fork":false,"pushed_at":"2025-03-13T13:24:09.000Z","size":460,"stargazers_count":19,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-13T14:28:01.427Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Noir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zkemail.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":"2024-11-11T06:50:07.000Z","updated_at":"2025-03-13T13:23:48.000Z","dependencies_parsed_at":"2024-11-11T08:20:24.125Z","dependency_job_id":"79ed140e-813d-48ae-80f6-0a812edf060b","html_url":"https://github.com/zkemail/noir-jwt","commit_stats":null,"previous_names":["saleel/noir-jwt","zkemail/noir-jwt"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkemail%2Fnoir-jwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkemail%2Fnoir-jwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkemail%2Fnoir-jwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zkemail%2Fnoir-jwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zkemail","download_url":"https://codeload.github.com/zkemail/noir-jwt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243475370,"owners_count":20296713,"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":[],"created_at":"2024-11-19T13:04:40.509Z","updated_at":"2026-03-05T23:41:58.844Z","avatar_url":"https://github.com/zkemail.png","language":"Noir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Noir JWT Verifier\n\n[Noir](https://noir-lang.org/) library to verify JWT tokens and prove claims. Currently only supports RS256 with 2048 bit keys.\n\n- Supports arbitrary sized JWTs.\n- Supports partial SHA hashing on the signed data to save constraints.\n- Can extract and verify claims of string, number, and boolean types efficiently.\n\n### How it works\n\nYou can learn more about JWT [here](https://jwt.io/introduction). But in short, JWT is a data structure that contains three parts:\n- Header: contains metadata about the token (JSON object with algorithm and type of token)\n- Payload: contains the claims (JSON key-value pairs)\n- Signature: RSA signature of the header and payload (assuming RS256 algorithm)\n\nJWT token is a string represented as `base64(header).base64(payload).base64(signature)`.\n\nThis noir library takes the signed data (which is `base64(header).base64(payload)`),  signature and the public key and verifies the signature (RSA-SHA256 verification).\n\nThere are utility methods to extract or verify claims from the payload, which is powered by the [string_search](https://github.com/noir-lang/noir_string_search) lib.\n\n\n## Installation\n\nIn your Nargo.toml file, add `jwt` as a dependency with the version you want to install:\n\n```toml\n[dependencies]\njwt = { tag = \"v0.4.3\", git = \"https://github.com/zkemail/noir-jwt\" }\n```\n\n## Usage\n\nAssuming you installed the latest version, you can use it in your Noir program like this:\n\n```nr\nuse jwt::JWT;\n\nglobal MAX_DATA_LENGTH: u32 = 900; // max length of signed data (headerb64 + \".\" + payloadb64)\nglobal MAX_NONCE_LENGTH: u32 = 32; // we are verifying `nonce` claim\n\nfn main(\n    data: BoundedVec\u003cu8, MAX_DATA_LENGTH\u003e,\n    base64_decode_offset: u32,\n    pubkey_modulus_limbs: pub [Field; 18],\n    redc_params_limbs: [Field; 18],\n    signature_limbs: [Field; 18],\n    expected_nonce: pub BoundedVec\u003cu8, MAX_NONCE_LENGTH\u003e\n) {\n    let jwt = JWT::init(\n        data,\n        base64_decode_offset,\n        pubkey_modulus_limbs,\n        redc_params_limbs,\n        signature_limbs,\n    );\n\n    jwt.verify();\n\n    // Verify `iss` claim value is \"test\"\n    jwt.assert_claim_string(\"iss\".as_bytes(), BoundedVec::\u003cu8, 4\u003e::from_array(\"test\".as_bytes()));\n}\n```\n\n#### With partial hash\n\n```nr\nuse jwt::JWT;\n\nglobal MAX_PARTIAL_DATA_LENGTH: u32 = 640; // Max length of the remaining data after partial hash\nglobal MAX_NONCE_LENGTH: u32 = 32;\n\nfn main(\n    partial_data: BoundedVec\u003cu8, MAX_PARTIAL_DATA_LENGTH\u003e,\n    partial_hash: [u32; 8],\n    full_data_length: u32,\n    base64_decode_offset: u32,\n    pubkey_modulus_limbs: pub [Field; 18],\n    redc_params_limbs: [Field; 18],\n    signature_limbs: [Field; 18],\n    nonce: pub BoundedVec\u003cu8, MAX_NONCE_LENGTH\u003e,\n) {\n    let jwt = JWT::init_with_partial_hash(\n        partial_data,\n        partial_hash,\n        full_data_length,\n        base64_decode_offset,\n        pubkey_modulus_limbs,\n        redc_params_limbs,\n        signature_limbs,\n    );\n\n    jwt.verify();\n\n    // Validate key value pair in payload JSON\n    jwt.assert_claim_string(\"nonce\".as_bytes(), nonce);\n}\n```\n\n## Input parameters\n\nHere is an explanation of the input parameters used in the circuit. Note that you can **use the JS SDK to generate these inputs**.\n\n- `data` is the signed data (headerb64 + \".\" + payloadb64)\n- When using partial SHA:\n    - `partial_data` is the data after the partial SHA.\n    - `partial_hash` is the partial hash of the data before the partial SHA [8 limbs of 32 bits each]\n    - `full_data_length` is the length of the full signed data (before partial SHA).\n- `pubkey_modulus_limbs`, `redc_params_limbs`, `signature_limbs` are the limbs of the RSA public key, redc params (this is required for bignum lib), and signature respectively.\n- `base64_decode_offset` is the index in `data` from which the circuit will try to decode the base64\n    - We only need to decode the payload (or a portion of it), as the claims we want to extract are in the payload.\n    - Normally, you can set `base64_decode_offset` to be the start index of payload data (index after first `.` in the JWT string)\n    - Or, any multiple of 4 (as base64 decodes chunks of 4) from the start of the payload if you want to skip the first few bytes of the payload. This can be used to optimize some constraints if the claims you want to verify are usually in the middle or towards the end of the payload.\n    - When using partial SHA, this should be 1, 2, or 3 to make the data after partial hash base64 decode-able (a valid base64). This should be the number of bytes that needs to be sliced from the data_remaining_after_partial_hash to make it a valid base64.\n\n\n## Methods available\n\n- `get_claim_string` - extracts a string claim from the payload and returns it as a `BoundedVec\u003cu8, MAX_VALUE_LENGTH\u003e`\n    ```nr\n    let claim: BoundedVec\u003cu8, MAX_VALUE_LENGTH\u003e = jwt.get_claim_string(\"email\".as_bytes());\n    ```\n\n- `assert_claim_string` - verifies that the claim is present in the payload and is a valid base64 encoded string\n    ```nr\n    jwt.assert_claim_string(\"nonce\".as_bytes(), nonce);\n    ```\n- `get_claim_number` - extracts a number claim from the payload and returns it as a `u64`\n    ```nr\n    let claim: u64 = jwt.get_claim_number(\"nonce\".as_bytes());\n    ```\n\n- `assert_claim_number` - verifies that the claim is present in the payload and is a valid number\n    ```nr\n    jwt.assert_claim_number(\"nonce\".as_bytes(), nonce);\n    ```\n\n- `get_claim_bool` - extracts a boolean claim from the payload and returns it as a `bool`\n    ```nr\n    let claim: bool = jwt.get_claim_bool(\"nonce\".as_bytes());\n    ```\n\n- `assert_claim_bool` - verifies that the claim is present in the payload and is a valid boolean\n    ```nr\n    jwt.assert_claim_bool(\"nonce\".as_bytes(), nonce);\n    ```\n\n\u003e Please note that the keys of the claims need to be known at compile time.\n\u003e This library doesn't support runtime JSON keys.\n\n## Input generation from JS\n\nA JS SDK is included in the repo that can help you with generating inputs required for the JWT circuit. Since this is only a library, you would need to combine it with other input used in your application circuit.\n\nInstall the dependency\n```\nnpm install noir-jwt\n```\n\n#### Usage\n```js\nconst { generateInputs } = require(\"noir-jwt\");\n\nconst inputs = generateInputs({\n  jwt,\n  pubkey,\n  maxSignedDataLength,\n  shaPrecomputeTillKeys,\n});\n```\nwhere:\n- `jwt` is the JWT token to process (string)\n- `pubkey` is the public key to verify the signature in `JsonWebKey` format\n- `maxSignedDataLength` is the maximum length of signed data (with or without partial hash). This should be same as `MAX_DATA_LENGTH` configured in your circuit.\n- `shaPrecomputeTillKeys` (optional) is the claim key(s) in the payload until which SHA should be precomputed. You can specify the claims you are extracting in the circuit, and the JS SDK will precompute SHA up to the first claim.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzkemail%2Fnoir-jwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzkemail%2Fnoir-jwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzkemail%2Fnoir-jwt/lists"}