{"id":13822383,"url":"https://github.com/spruceid/ssi","last_synced_at":"2025-05-14T19:10:10.400Z","repository":{"id":37051424,"uuid":"285008103","full_name":"spruceid/ssi","owner":"spruceid","description":"Core library for decentralized identity.","archived":false,"fork":false,"pushed_at":"2025-05-13T10:55:18.000Z","size":3708,"stargazers_count":210,"open_issues_count":109,"forks_count":65,"subscribers_count":34,"default_branch":"main","last_synced_at":"2025-05-13T11:27:59.555Z","etag":null,"topics":["identity","jsonld","ssi","vc","vp"],"latest_commit_sha":null,"homepage":"https://spruceid.dev","language":"Rust","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/spruceid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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-04T14:40:34.000Z","updated_at":"2025-05-07T04:49:35.000Z","dependencies_parsed_at":"2023-09-23T04:05:32.265Z","dependency_job_id":"c4fd5381-bd1a-4766-a4ba-3f56c6bae81a","html_url":"https://github.com/spruceid/ssi","commit_stats":{"total_commits":570,"total_committers":32,"mean_commits":17.8125,"dds":"0.33508771929824566","last_synced_commit":"6afb73df1ec889ae869f722bea401a360d2da47c"},"previous_names":[],"tags_count":187,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spruceid%2Fssi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spruceid%2Fssi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spruceid%2Fssi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spruceid%2Fssi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spruceid","download_url":"https://codeload.github.com/spruceid/ssi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253934575,"owners_count":21986818,"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":["identity","jsonld","ssi","vc","vp"],"created_at":"2024-08-04T08:01:58.086Z","updated_at":"2025-05-14T19:10:08.090Z","avatar_url":"https://github.com/spruceid.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"[![](https://img.shields.io/github/actions/workflow/status/spruceid/ssi/build.yml?branch=main)](https://github.com/spruceid/ssi/actions?query=workflow%3Aci+branch%3Amain)\n[![](https://img.shields.io/badge/Rust-v1.66.0-orange)](https://www.rust-lang.org/)\n[![](https://img.shields.io/badge/License-Apache--2.0-green)](https://github.com/spruceid/didkit/blob/main/LICENSE)\n[![](https://img.shields.io/twitter/follow/spruceid?label=Follow\u0026style=social)](https://twitter.com/spruceid)\n\n# SSI\n\n\u003c!-- cargo-rdme start --\u003e\n\nThe SSI library provides a simple and modular API to sign and verify claims\nexchanged between applications using\n[Decentralized Identifiers (DIDs)][dids]. SSI is embedded in the\ncross-platform [`didkit`][didkit] library as a core dependency.\n\nThis library supports the two main families of verifiable claims:\n- [JSON Web Tokens (JWT)][jwt] where claims are encoded into JSON and\n  secured using [JSON Web Signatures][jws]; and\n- [W3C's Verifiable Credentials (VCs)][vc-data-model], a\n  [Linked-Data][linked-data]-based model where claims (VCs) can be\n  interpreted as RDF datasets. VC supports multiple signature formats\n  provided by SSI:\n  - VC over JWT ([JWT-VC][jwt-vc]), a restricted form of JWT following the\n    VC data model; or\n  - [Data Integrity][data-integrity], encoding the claims and their proof\n    in the same JSON-LD document using a wide variety of\n    [*cryptographic suites*][cryptosuite].\n\n[dids]: \u003chttps://www.w3.org/TR/did-core/\u003e\n[didkit]: \u003chttps://github.com/spruceid/didkit\u003e\n[vc-data-model]: \u003chttps://www.w3.org/TR/vc-data-model/\u003e\n[linked-data]: \u003chttps://www.w3.org/DesignIssues/LinkedData.html\u003e\n[jwt]: \u003chttps://www.rfc-editor.org/rfc/rfc7519\u003e\n[jws]: \u003chttps://www.rfc-editor.org/rfc/rfc7515\u003e\n[jwt-vc]: \u003chttps://www.w3.org/TR/vc-data-model/#json-web-token\u003e\n[data-integrity]: \u003chttps://www.w3.org/TR/vc-data-integrity/\u003e\n[cryptosuite]: \u003chttps://www.w3.org/TR/vc-data-integrity/#dfn-cryptosuite\u003e\n\n## Basic Usage\n\nSSI provides various functions to parse, verify, create and sign various\nkind of claims. This section shows how to use these functions in combination\nwith JSON Web Signatures (or Tokens) and Verifiable Credentials.\n\n### Verification\n\nThe simplest type of claim to load and verify is probably JSON Web\nSignatures (JWSs), often use to encode JSON Web Tokens (JWTs). To represent\nsuch claims SSI provides the `JwsBuf` type representing a JWS\nin compact textual form. One can load a JWS using [`new`] and verify\nit using [`verify`].\n\n[`new`]: claims::JwsBuf::new\n[`verify`]: claims::JwsSlice::verify\n\n```rust\nuse ssi::prelude::*;\n\n// Load a JWT from the file system.\nlet jwt = JwsBuf::new(\n  std::fs::read_to_string(\"examples/files/claims.jwt\")\n  .expect(\"unable to load JWT\")\n).expect(\"invalid JWS\");\n\n// Setup a verification method resolver, in charge of retrieving the\n// public key used to sign the JWT.\n// Here we use the example `ExampleDIDResolver` resolver, enabled with the\n// `example` feature.\nlet vm_resolver = ExampleDIDResolver::default().into_vm_resolver::\u003cAnyJwkMethod\u003e();\n\n// Setup the verification parameters.\nlet params = VerificationParameters::from_resolver(vm_resolver);\n\n// Verify the JWT.\nassert!(jwt.verify(\u0026params).await.expect(\"verification failed\").is_ok())\n```\n\n#### Verifiable Credentials\n\nVerifiable Credential are much more complex as they require interpreting\nthe input claims and proofs, such as Data-Integrity proofs as Linked-Data\nusing JSON-LD. This operation is highly configurable. SSI provide\nfunctions exposing various levels of implementation details that you can\ntweak as needed. The simplest of them is [`any_credential_from_json_str`]\nthat will simply load a VC from a string, assuming it is signed using\nany Data-Integrity proof supported by SSI.\n\n[`any_credential_from_json_str`]: claims::vc::v1::data_integrity::any_credential_from_json_str\n\n```rust\nuse ssi::prelude::*;\n\nlet vc = ssi::claims::vc::v1::data_integrity::any_credential_from_json_str(\n  \u0026std::fs::read_to_string(\"examples/files/vc.jsonld\")\n  .expect(\"unable to load VC\")\n).expect(\"invalid VC\");\n\n// Setup a verification method resolver, in charge of retrieving the\n// public key used to sign the JWT.\nlet vm_resolver = ExampleDIDResolver::default().into_vm_resolver();\n\n// Setup the verification parameters.\nlet params = VerificationParameters::from_resolver(vm_resolver);\n\nassert!(vc.verify(\u0026params).await.expect(\"verification failed\").is_ok());\n```\n\n### Signature \u0026 Custom Claims\n\nIn the previous section we have seen how to load and verify arbitrary\nclaims. This section shows how to create and sign custom claims.\nWith SSI, any Rust type can serve as claims as long as it complies to\ncertain conditions such as implementing serialization/deserialization\nfunctions using [`serde`](https://crates.io/crates/serde).\nDon't forget to enable the `derive` feature for `serde`.\n\nIn the following example, we create a custom type `MyClaims` and sign it\nas a JWT.\n\n```rust\nuse serde::{Serialize, Deserialize};\nuse ssi::prelude::*;\n\n// Defines the shape of our custom claims.\n#[derive(Serialize, Deserialize)]\npub struct MyClaims {\n  name: String,\n  email: String\n}\n\n// Create JWT claims from our custom (\"private\") claims.\nlet claims = JWTClaims::from_private_claims(MyClaims {\n  name: \"John Smith\".to_owned(),\n  email: \"john.smith@example.org\".to_owned()\n});\n\n// Create a random signing key, and turn its public part into a DID URL.\nlet mut key = JWK::generate_p256(); // requires the `p256` feature.\nlet did = DIDJWK::generate_url(\u0026key.to_public());\nkey.key_id = Some(did.into());\n\n// Sign the claims.\nlet jwt = claims.sign(\u0026key).await.expect(\"signature failed\");\n\n// Create a verification method resolver, which will be in charge of\n// decoding the DID back into a public key.\nlet vm_resolver = DIDJWK.into_vm_resolver::\u003cAnyJwkMethod\u003e();\n\n// Setup the verification parameters.\nlet params = VerificationParameters::from_resolver(vm_resolver);\n\n// Verify the JWT.\nassert!(jwt.verify(\u0026params).await.expect(\"verification failed\").is_ok());\n\n// Print the JWT.\nprintln!(\"{jwt}\")\n```\n\n#### Verifiable Credential\n\nWe can use a similar technique to sign a VC with custom claims.\nThe [`SpecializedJsonCredential`] type provides a customizable\nimplementation of the VC data-model 1.1 where you can set the credential type\nyourself.\n\n[`SpecializedJsonCredential`]: claims::vc::v1::SpecializedJsonCredential\n\n```rust\nuse static_iref::uri;\nuse serde::{Serialize, Deserialize};\nuse ssi::claims::vc::syntax::NonEmptyVec;\nuse ssi::prelude::*;\n\n// Defines the shape of our custom claims.\n#[derive(Serialize, Deserialize)]\npub struct MyCredentialSubject {\n  #[serde(rename = \"https://example.org/#name\")]\n  name: String,\n\n  #[serde(rename = \"https://example.org/#email\")]\n  email: String\n}\n\nlet credential = ssi::claims::vc::v1::JsonCredential::\u003cMyCredentialSubject\u003e::new(\n  Some(uri!(\"https://example.org/#CredentialId\").to_owned()), // id\n  uri!(\"https://example.org/#Issuer\").to_owned().into(), // issuer\n  DateTime::now().into(), // issuance date\n  NonEmptyVec::new(MyCredentialSubject {\n    name: \"John Smith\".to_owned(),\n    email: \"john.smith@example.org\".to_owned()\n  })\n);\n\n// Create a random signing key, and turn its public part into a DID URL.\nlet key = JWK::generate_p256(); // requires the `p256` feature.\nlet did = DIDJWK::generate_url(\u0026key.to_public());\n\n// Create a verification method resolver, which will be in charge of\n// decoding the DID back into a public key.\nlet vm_resolver = DIDJWK.into_vm_resolver();\n\n// Create a signer from the secret key.\n// Here we use the simple `SingleSecretSigner` signer type which always uses\n// the same provided secret key to sign messages.\nlet signer = SingleSecretSigner::new(key.clone()).into_local();\n\n// Turn the DID URL into a verification method reference.\nlet verification_method = did.into_iri().into();\n\n// Automatically pick a suitable Data-Integrity signature suite for our key.\nlet cryptosuite = AnySuite::pick(\u0026key, Some(\u0026verification_method))\n  .expect(\"could not find appropriate cryptosuite\");\n\nlet vc = cryptosuite.sign(\n  credential,\n  \u0026vm_resolver,\n  \u0026signer,\n  ProofOptions::from_method(verification_method)\n).await.expect(\"signature failed\");\n```\n\nIt is critical that custom claims can be interpreted as Linked-Data. In\nthe above example this is done by specifying a serialization URL for each\nfield of `MyCredentialSubject`. This can also be done by creating a custom\nJSON-LD context and embed it to `credential` using either\n[`SpecializedJsonCredential`]'s [`context`] field or leveraging its context type\nparameter.\n\n[`context`]: claims::vc::v1::SpecializedJsonCredential::context\n\n## Data-Models\n\nThe examples above are using the VC data-model 1.1, but you ssi also has support for:\n- [`VC data-model 2.0`]\n- [`A wrapper type to accept both`]\n\n[`VC data-model 2.0`]: claims::vc::v2\n[`A wrapper type to accept both`]: claims::vc::syntax::AnySpecializedJsonCredential\n\n## Features\n\n\u003c!-- cargo-rdme end --\u003e\n\n## Security Audits\n\nssi has undergone the following security reviews:\n- [March 14th, 2022 - Trail of Bits](https://github.com/trailofbits/publications/blob/master/reviews/SpruceID.pdf) | [Summary of Findings](https://blog.spruceid.com/spruce-completes-first-security-audit-from-trail-of-bits/)\n\n## Testing\n\nTesting SSI requires the RDF canonicalization test suite, which is embedded as\na git submodule.\n\n```sh\n$ git submodule update --init\n$ cargo test --workspace\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspruceid%2Fssi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspruceid%2Fssi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspruceid%2Fssi/lists"}