Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:OpenHands OpenHands SaasSecretsStore

From Leeroopedia
Revision as of 11:43, 16 February 2026 by Admin (talk | contribs) (Auto-imported from implementations/OpenHands_OpenHands_SaasSecretsStore.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Knowledge Sources
Domains Storage, Security, Secrets_Management
Last Updated 2026-02-11 21:00 GMT

Overview

Encrypted secrets store for user custom secrets with Fernet symmetric encryption and organization scoping, provided by the OpenHands enterprise storage layer.

Description

SaasSecretsStore manages user-defined custom secrets (such as API keys and tokens for external services) with transparent encryption at rest. All secret values are encrypted using Fernet symmetric encryption before being persisted to the database and decrypted on read.

The store is scoped to an organization, meaning secrets are isolated per-org and users can only access secrets within their organization. The _fernet() method initializes and caches the Fernet cipher using a key derived from the application configuration.

The store() method uses a delete-and-replace pattern: it first deletes all existing secrets for the user within the org, then inserts the new set. This atomic replacement avoids partial-update scenarios and ensures the stored secrets always reflect the user's most recent complete set.

The internal _encrypt_kwargs() and _decrypt_kwargs() methods handle the transformation of secret values between plaintext (in application memory) and encrypted (in the database) representations.

Usage

Use SaasSecretsStore to manage user custom secrets in the SaaS settings UI. Call load() to retrieve and decrypt a user's secrets for display or injection into runtime environments. Call store() to persist an updated set of secrets, replacing any previously stored values.

Code Reference

Source Location

Signature

class SaasSecretsStore:
    def __init__(self, session: Session, org_id: str, config: AppConfig):
        ...

    def load(self, user_id: str) -> dict:
        """Loads and decrypts all secrets for the given user within the org."""
        ...

    def store(self, user_id: str, secrets: dict) -> None:
        """Deletes existing secrets and replaces with the new set (delete-and-replace)."""
        ...

    def _decrypt_kwargs(self, encrypted_data: bytes) -> dict:
        """Decrypts Fernet-encrypted bytes back to a dictionary."""
        ...

    def _encrypt_kwargs(self, data: dict) -> bytes:
        """Encrypts a dictionary to Fernet-encrypted bytes."""
        ...

    def _fernet(self) -> Fernet:
        """Returns a cached Fernet cipher instance derived from the app config key."""
        ...

Import

from enterprise.storage.saas_secrets_store import SaasSecretsStore

I/O Contract

Inputs

Constructor

Name Type Required Description
session Session Yes SQLAlchemy database session for executing queries
org_id str Yes Organization ID that scopes the secrets
config AppConfig Yes Application configuration containing the Fernet encryption key

load()

Name Type Required Description
user_id str Yes The user whose secrets to load and decrypt

store()

Name Type Required Description
user_id str Yes The user whose secrets to replace
secrets dict Yes Dictionary of secret name-value pairs to encrypt and store

Outputs

Method Return Type Description
load() dict Dictionary of decrypted secret name-value pairs for the user
store() None Deletes all existing secrets and inserts the new encrypted set
_decrypt_kwargs() dict Plaintext dictionary from encrypted bytes
_encrypt_kwargs() bytes Fernet-encrypted bytes from a plaintext dictionary
_fernet() Fernet Cached Fernet cipher instance

Usage Examples

Loading and Storing Secrets

from enterprise.storage.saas_secrets_store import SaasSecretsStore

secrets_store = SaasSecretsStore(
    session=db_session,
    org_id="org-123",
    config=app_config
)

# Load existing secrets for a user
user_secrets = secrets_store.load(user_id="user-456")
# Returns: {"GITHUB_TOKEN": "ghp_xxx", "SLACK_WEBHOOK": "https://hooks.slack.com/..."}

# Store updated secrets (replaces all existing secrets)
secrets_store.store(
    user_id="user-456",
    secrets={
        "GITHUB_TOKEN": "ghp_new_token",
        "SLACK_WEBHOOK": "https://hooks.slack.com/new-url",
        "CUSTOM_API_KEY": "sk-new-key"
    }
)

Delete-and-Replace Behavior

# If a user previously had 3 secrets and stores 2 new ones,
# the old 3 are deleted and only the new 2 remain:
secrets_store.store(
    user_id="user-456",
    secrets={
        "GITHUB_TOKEN": "ghp_updated",
        "NEW_SECRET": "new_value"
        # SLACK_WEBHOOK and CUSTOM_API_KEY are removed
    }
)

# Subsequent load returns only the 2 new secrets:
result = secrets_store.load(user_id="user-456")
# Returns: {"GITHUB_TOKEN": "ghp_updated", "NEW_SECRET": "new_value"}

Related Pages

Related Implementations

Environment

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment