This repository houses the internal Bitwarden SDKs. We also provide a public Secrets Manager SDK.
[!WARNING]
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.
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.Clone the repository:
bash
git clone https://github.com/bitwarden/sdk-internal.git
cd sdk-internal
Install the dependencies:
bash
npm ci
Run the following command:
cargo build
For Windows on ARM, you will need the following in your PATH:
Integrating the SDK into client applications for local development requires two steps:
sdk-internal with bindings specific to the client application, andThe instructions are different depending on the client that will be consuming the SDK.
[!NOTE]
These instructions assume a directory structure similar to:
text sdk-internal/ clients/ ios/ android/If your repository directory structure differs you will need to adjust the commands accordingly.
Build the SDK to expose WASM bindings, which will be consumed by our web clients, by following the
instructions in
crates/bitwarden-wasm-internal.
After completing these instructions, you'll have built an SDK artifact that includes either OSS-licensed code, or both OSS- and commercially-licensed code, based on your choice of build script. See Licensing for details on why we have multiple packages and determine which one(s) you need to build.
The web clients use NPM to install sdk-internal as a dependency. NPM offers a dedicated command
[link][npm-link] which can be used to temporarily replace the packages with a locally-built
version.
When building the web sdk-internal artifacts, you had the option to build the OSS or the
commercially-licensed version. You will need to adjust your npm link command according to which
one you built, and which one you intend to make available to the client application for your local
development.
| Desired client build | Build script you ran | SDK artifact built | Link command | Result |
|---|---|---|---|---|
| OSS | ./build.sh |
Artifact with OSS-licensed code | npm link ../sdk-internal/crates/bitwarden-wasm-internal/npm |
SDK with OSS-licensed code linked to clients |
| Commercial (Bitwarden license) | ./build.sh && ./build.sh -b |
Artifact with both OSS and commercially-licensed code | npm link ../sdk-internal/crates/bitwarden-wasm-internal/npm ../sdk-internal/crates/bitwarden-wasm-internal/bitwarden_license/npm |
SDK with both OSS and commercially-licensed code linked to clients |
Running npm link will restore any previously linked packages, so only the paths in the last run
command will be linked. When doing commercial development, always link both packages (as shown
above) so that changes to OSS types are also reflected in the client — linking only the
commercially-licensed package will leave OSS types stale.
[!WARNING]
Running
npm ciornpm installwill replace the linked packages with the published version.
Build the SDK to expose Kotlin bindings through UniFFI, which will be consumed by our Android mobile
app. Follow the instructions in
crates/bitwarden-uniffi/kotlin.
bash
../sdk-internal/crates/bitwarden-uniffi/kotlin/publish-local.sh
localSdk=true in the user.properties file.Build the SDK to expose iOS bindings through UniFFI, which will be consumed by our iOS mobile app.
Follow the instructions in
crates/bitwarden-uniffi/swift.
Run the bootstrap script with the LOCAL_SDK environment variable set to true in order to use the
local SDK build:
LOCAL_SDK=true ./Scripts/bootstrap.sh
[!WARNING]
BREAKING CHANGES When a pull request is opened to merge changes from
sdk-internalintomain, a Breaking Change Detection workflow will run and comment on the PR if breaking changes are detected on any clients. If your PR includes breaking changes you must be prepared to address them as soon as they merge with a corresponding PR in the client application repository. If not, any subsequentsdk-internalintegrations into clients will be blocked, as those other teams will not know how best to resolve the breaking API contracts that you introduced.
In addition to
linking to local builds during
development, you will need to be able to integrate your sdk-internal changes into published
artifacts, so that the client applications can be tested and published with the requisite SDK
changes included.
The process for doing so varies based on the client, as the method by which the sdk-internal
package is consumed differs.
For our web clients, the sdk-internal packages for our OSS- and commercially-licensed SDK versions
with their WebAssembly bindings is published to npm at:
These npm packages are referenced as
dependencies in our clients repo.
See Licensing for details on why we have multiple packages.
Every commit to main in sdk-internal will trigger a
publish
of these packages, with versions structured as follows:
{SemanticVersion}-main.{actionRunNumber}
For example:
0.1.0-main.470
[!TIP]
To see what version is published to
npmfor a given publish action, you can check the Summary of the publish action in Github.
When you have completed development of changes in sdk-internal and need to consume them in the
client application, you will need to update the npm dependency in your feature branch to reference
the new SDK version:
sdk-internal pull request. This will trigger a publish of the latest changes to npm.Update the versions of the sdk-internal dependencies in clients to reference this version.
You can do this either:
By updating to the latest version using npm install @bitwarden/sdk-internal@latest and
npm install @bitwarden/commercial-sdk-internal@latest, or
By referencing the specific published version, using
npm install @bitwarden/sdk-internal@{version} and
npm install @bitwarden/commercial-sdk-internal@{version}.
Open a clients pull request to merge the client application changes that include this new
sdk-internal version.
The iOS and Android applications use an automated, reactive approach to integrating sdk-internal
changes into their repositories.
When you need to integrate sdk-internal changes into the iOS or Android applications, you should
use the automatically-generated pull requests for each repository:
| Client | SDK workflow | Client workflow |
|---|---|---|
| Android | https://github.com/bitwarden/sdk-internal/blob/main/.github/workflows/build-android.yml | https://github.com/bitwarden/android/actions/workflows/sdlc-sdk-update.yml |
| iOS | https://github.com/bitwarden/sdk-internal/blob/main/.github/workflows/build-swift.yml | https://github.com/bitwarden/ios/actions/workflows/sdlc-sdk-update.yml |
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 the Api service that contains
most of the server side functionality.bitwarden-api-identity: For the Identity service
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:
```rust
impl TryFrom 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 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,
$ claude mcp add sdk-internal \
-- python -m otcore.mcp_server <graph>