This repository houses the internal Bitwarden SDKs. We also provide a public Secrets Manager SDK.
The password manager SDK is not intended for public use and is not supported by Bitwarden at this stage. It is solely intended to centralize the business logic and to provide a single source of truth for the internal applications. As the SDK evolves into a more stable and feature complete state we will re-evaluate the possibility of publishing stable bindings for the public. The password manager interface is unstable and will change without warning.
Interested in contributing in a big way? Consider joining our team! We're hiring for many positions. Please take a look at our Careers page to see what opportunities are currently open as well as what it's like to work at Bitwarden.
cargo buildTo build, you will need the following in your PATH:
- Python
- Clang
- We recommend installing this via the Visual Studio Build Tools
Please refer to our Contributing Docs for getting started instructions and architectural documentation.
You can also browse the latest published documentation:
- docs.rs for the public SDK.
- Or for developers of the SDK, view the internal API documentation which includes private items.
The project is structured as a monorepo using cargo workspaces. Some of the more noteworthy crates are:
bitwarden-api-api: Auto-generated API bindings for the API server.bitwarden-api-identity: Auto-generated API bindings for the Identity server.bitwarden-core: The core functionality consumed by the other crates.bitwarden-crypto: Crypto library.bitwarden-wasm-internal: WASM bindings for the internal SDK.bitwarden-uniffi: Mobile bindings for swift and kotlin using UniFFI.
We auto-generate the server bindings using openapi-generator, which creates Rust bindings from the server OpenAPI specifications. These bindings are regularly updated to ensure they stay in sync with the server.
The bindings are exposed as multiple crates, one for each backend service:
bitwarden-api-api: For theApiservice that contains most of the server side functionality.bitwarden-api-identity: For theIdentityservice that is used for authentication.
When performing any API calls the goal is to use the generated bindings as much as possible. This
ensures any changes to the server are accurately reflected in the SDK. The generated bindings are
stateless, and always expects to be provided a Configuration instance. The SDK exposes these under
the get_api_configurations function on the Client struct.
You should not expose the request and response models of the auto-generated bindings and should instead define and use your own models. This ensures the server request / response models are decoupled from the SDK models and allows for easier changes in the future without breaking backwards compatibility.
We recommend using either the From or TryFrom conversion traits depending on if the conversion
requires error handling or not. Below are two examples of how this can be done:
# use bitwarden_crypto::EncString;
# use serde::{Serialize, Deserialize};
# use serde_repr::{Serialize_repr, Deserialize_repr};
#
# #[derive(Serialize, Deserialize, Debug, Clone)]
# struct LoginUri {
# pub uri: Option<EncString>,
# pub r#match: Option<UriMatchType>,
# pub uri_checksum: Option<EncString>,
# }
#
# #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, PartialEq)]
# #[repr(u8)]
# pub enum UriMatchType {
# Domain = 0,
# Host = 1,
# StartsWith = 2,
# Exact = 3,
# RegularExpression = 4,
# Never = 5,
# }
#
# #[derive(Debug)]
# struct VaultParseError;
#
impl TryFrom<bitwarden_api_api::models::CipherLoginUriModel> for LoginUri {
type Error = VaultParseError;
fn try_from(uri: bitwarden_api_api::models::CipherLoginUriModel) -> Result<Self, Self::Error> {
Ok(Self {
uri: EncString::try_from_optional(uri.uri)
.map_err(|_| VaultParseError)?,
r#match: uri.r#match.map(|m| m.into()),
uri_checksum: EncString::try_from_optional(uri.uri_checksum)
.map_err(|_| VaultParseError)?,
})
}
}
impl From<bitwarden_api_api::models::UriMatchType> for UriMatchType {
fn from(value: bitwarden_api_api::models::UriMatchType) -> Self {
match value {
bitwarden_api_api::models::UriMatchType::Domain => Self::Domain,
bitwarden_api_api::models::UriMatchType::Host => Self::Host,
bitwarden_api_api::models::UriMatchType::StartsWith => Self::StartsWith,
bitwarden_api_api::models::UriMatchType::Exact => Self::Exact,
bitwarden_api_api::models::UriMatchType::RegularExpression => Self::RegularExpression,
bitwarden_api_api::models::UriMatchType::Never => Self::Never,
}
}
}When the API exposed by the server changes, new bindings will need to be generated to reflect this change for consumption in the SDK. Examples of such changes include adding new fields to server request / response models, removing fields from models, or changing types of models.
A GitHub workflow exists to
update the API bindings.
This workflow should always be used to merge any binding changes to main, to ensure that there are
not conflicts with the auto-generated bindings in the future. Binding changes should not be
included as a part of the PR to consume them.
There are two ways to run the workflow:
- Manually run the
Update API Bindingsworkflow in thesdk-internalrepo. - Wait for an automatic binding update to run, which is scheduled every 2 weeks.
Both of these will generate a PR that will require approval from any teams whose owned code is affected by the binding updates.
A suggested workflow for incorporating server API changes into the SDK would be:
- Make changes in
serverrepo to expose the new API. - Merge
serverchanges tomain. - Trigger the
Update API Bindingsworkflow insdk-internalto open a pull request with the updated API bindings. - Review and merge that pull request to
sdk-internalmainbranch. - Pull in
sdk-internalmaininto your feature branch for SDK work. - Consume new API models in SDK code.
[!IMPORTANT] Use the workflow to make any merged binding changes. Running the scripts below can be helpful during local development, but please ensure that any changes to the bindings in
bitwarden-api-apiandbitwarden-api-identityare not checked into any pull request.
In order to update the bindings locally, we first need to build the internal Swagger documentation. This code should not be directly modified. Instead use the instructions below to generate Swagger documents and use these to generate the OpenApi bindings.
The first step is to generate the Swagger documents from the root of the server repository.
pwsh ./dev/generate_openapi_files.ps1To generate a new version of the bindings, run the following script from the root of the SDK
project. This requires a Java Runtime Environment, and also assumes the repositories server and
sdk-internal have the same parent directory.
./support/build-api.shThis project uses customized templates that live in the support/openapi-templates directory. These
templates resolve some outstanding issues we've experienced with the Rust generator. But we strive
towards modifying the templates as little as possible to ease future upgrades.
:::note
If you don't have the nightly toolchain installed, the build-api.sh script will install it for
you.
:::
This project recommends the use of certain developer tools and includes configurations for them to make developers' lives easier. The use of these tools is optional, and they might require a separate installation step.
The list of developer tools is:
Visual Studio Code: We provide a recommended extension list which should show under theExtensionstab when opening this project with the editor. We also offer a few launch settings and tasks to build and run the SDKbacon: This is a CLI background code checker. We provide a configuration file with some of the most common tasks to run (check,clippy,test,doc- runbacon -lto see them all). This tool needs to be installed separately by runningcargo install bacon --locked.nexttest: This is a new and faster test runner, capable of running tests in parallel and with a much nicer output compared tocargo test. This tool needs to be installed separately by runningcargo install cargo-nextest --locked. It can be manually run usingcargo nextest run --all-features
This repository uses various tools to check formatting and linting before it's merged. It's recommended to run the checks before submitting a PR.
Please see the lint.yml file, for example, installation commands and versions. Here are the cli tools we use:
- Nightly cargo fmt and cargo udeps
- rust clippy
- cargo dylint
- cargo sort
- prettier
To verify if changes need to be made, here are examples for the above tools:
export RUSTFLAGS="-D warnings"
cargo +nightly fmt --check
cargo +nightly udeps --workspace --all-features
cargo clippy --all-features --all-targets
cargo dylint --all -- --all-features --all-targets
cargo sort --workspace --grouped --check
npm run lint
Code contributions are welcome! Please commit any pull requests against the main branch. Learn
more about how to contribute by reading the
Contributing Guidelines. Check out the
Contributing Documentation for how to get started with your
first contribution.
Security audits and feedback are welcome. Please open an issue or email us privately if the report
is sensitive in nature. You can read our security policy in the SECURITY.md file.
We also run a program on HackerOne.
No grant of any rights in the trademarks, service marks, or logos of Bitwarden is made (except as may be necessary to comply with the notice requirements as applicable), and use of any Bitwarden trademarks must comply with Bitwarden Trademark Guidelines.