All pages
Powered by GitBook
1 of 13

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

KSM Developer SDKs

Sample code and SDK integration instructions for Keeper Secrets Manager

Overview

The Keeper Secrets Manager SDKs are purpose-built to provide extremely simple, fast and efficient access to Secrets Management functionality from all popular languages.

Secrets Manager SDKs

  • Python

  • Java / Kotlin

  • JavaScript

  • .Net

  • Go

  • Ruby

  • Rust

  • PowerShell

Authentication

The Secrets Manager SDK authenticates to the Keeper Vault using either the One Time Access Token or using the generated keys within the local configuration file. To generate one or more One Time Access Tokens from the Commander CLI use the secrets-manager client add command.

My Vault> secrets-manager client add --app MyApplication --unlock-ip

After a config file has been initialized, the One-Time Access Token should be removed from code

This initialization code will create a JSON configuration file with the following keys:

Key

Description

hostname

The destination host where your Enterprise tenant is located:

  • keepersecurity.com

  • keepersecurity.eu

  • keepersecurity.com.au

  • keepersecurity.jp

  • keepersecurity.ca

  • govcloud.keepersecurity.us

clientID

The hashed clientKey where clientKey is the Unique Client Device Identifier

privateKey

Client Device Private Key

serverPublicKeyId

Keeper Infrastructure's Public Key ID

appKey

Application Private Key

appOwnerPublicKey

Application Owner's Public Key

The following is an example of a generated configuration file:

ksm-config.json
{
  "hostname": "keepersecurity.com",
  "clientId": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "privateKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "serverPublicKeyId": "10",
  "appKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "appOwnerPublicKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

For more information on configuration files, see the Config File documentation.

Configuration File Protection

Keeper provides several options for the secure encryption and storage of the KSM configuration file using popular cloud services:

  • AWS KMS

  • Azure Key Vault

  • Entrust HSM

  • Google Cloud Key Management

  • Oracle Key Vault


Script Integration

Keeper Secrets Manager CLI provides a wrapper function that executes any arbitrary system call and replaces environmental variables with values from the Keeper Vault.

Secrets Manager CLI Exec Command

Vault and Admin SDKs

For higher level functionality at the Vault and Administrative level, please see the Vault SDKs page which contains links to various development tools.

Vault SDKs

Vault SDKs

Full Vault SDKs for integration and automation

If you are looking for SDK capabilities beyond secrets management, Keeper provides other SDKs that can perform vault and administrative functionality.

Python Commander SDK

The Keeper Commander SDKs for Python provide programmatic access to the platform, enabling secure management of credentials, secrets, and enterprise resources at scale.

https://github.com/Keeper-Security/keeper-sdk-python

Python Commander CLI

The Keeper Commander CLI is an implementation using Python that interfaces with the Keeper vault and Keeper administrative functions. The source code is available below:

https://github.com/keeper-Security/commander

.Net Vault SDK

We also created a .Net based Commander tool with a developer SDK for basic vault access and administrative functions:

https://github.com/Keeper-Security/keeper-sdk-dotnet

PowerShell CLI

Keeper's PowerShell command-line tool ("PowerCommander") provides basic vault access and administrative functions in PowerShell scripts.

https://github.com/Keeper-Security/keeper-sdk-dotnet/tree/release/PowerCommander For more advanced command line capabilities, please refer to the Python-based Commander CLI.

GoLang SDK

The Keeper GoLang SDK is used specifically in our Terraform provider.

https://github.com/Keeper-Security/keeper-sdk-golang

PowerShell

PowerShell docs for Keeper Secrets Manager

Features

  • Retrieve secrets from the Keeper Vault to use in PowerShell

  • Integrate Keeper vault with PowerShell Secrets Manager

  • Update secret values in the Keeper Vault from PowerShell

  • Get files from the Keeper vault

Please refer to the documented in the Integrations section:

Keeper PowerShell module
Go to PowerShell Plugin

Python SDK

Detailed Python SDK docs for Keeper Secrets Manager

Download and Installation

Install with PIP

pip3 install -U keeper-secrets-manager-core

Source Code

Find the Python source code in the GitHub repository

Using the SDK

Initialize

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

SecretsManager(token, config)
# Using token, only to generate a config (for later usage),
# requires at least one access operation to bind the token
#get_secrets(uids=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)
# Using token only to generate the config 
# requires at least one access operation to bind the token
#secrets_manager.get_secrets(uids=None)

Parameter

Required

Description

Type

token

Yes

One Time Access Token

String

config

Yes

Storage Configuration

KeyValueStorage

Retrieve Secrets

get_secrets(uids=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get all records
all_secrets = secrets_manager.get_secrets()

# print out all records
for secret in all_secrets:
    print(secret.dict)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by record UID
secret = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# print out secret
print(secret.dict)

Parameter

Type

Required

Default

Description

uids

String[]

Optional

None

Record UIDs to fetch

Response

Type: Record[]

All Keeper records, or records with the given UIDs

Retrieve Values From a Secret

Retrieve a Password

This shortcut gets the password of a secret once that secret has been retrieved from Keeper Secrets Manager.

secret.field('password', single=True)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by record UID
secret = secrets_manager.get_secrets(['<RECORD UID>'])[0]

# get password from record
my_secret_password = secret.field('password', single=True)

Retrieve Standard Fields

secret.field(field_type, single=False, value=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by record UID
secret = secrets_manager.get_secrets(['<RECORD UID>'])[0]

# get login field from the secret
my_secret_login = secret.field("login", single=True)

Parameter

Type

Required

Default

Description

field_type

String

Yes

Field type to get

single

boolean

Optional

False

Return only the first value

value

String or String[]

Optional

None

If passed, set the value of the field to the given value

Field types are based on the Keeper . For a detailed list of available fields based on the Keeper Record Type, see the record-type-info command in Keeper Commander.

Retrieve Custom Fields

secret.custom_field(label, field_type=None, single=False, value=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by UID
secret = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# Get a standard template field
password = secret.field('password', single=True)

# Get a custom field, e.g. API Key
api_key = secret.custom_field('API Key', single=True)

Parameter

Type

Required

Default

Description

label

String

Yes

Label of the custom field

field_type

String

Yes

Field type to get

single

boolean

Optional

False

Return only the first value

value

String or String[]

Optional

None

If passed, set the value of the field to the given value

Custom fields are any field that is not part of the record type definition, but can be added by users.

It is possible for multiple fields of the same custom type to appear on a single record, to differentiate these fields, the field label is required.

Response

Type: String or String[]

the value or values of the field. Will be a single value only if the single=True option is passed.

Retrieve Secrets by Title

# get all matching records
get_secrets_by_title(record_title)

# get only the first matching record
get_secret_by_title(record_title)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    config=FileKeyValueStorage('ksm-config.json'))

# get the first secret matching the record title
secret = secrets_manager.get_secret_by_title("My Credentials")

# get all secrets matching the record title
secrets = secrets_manager.get_secrets_by_title("My Credentials")
Parameter
Type
Required
Description

record_title

String

Yes

Record title to search for

Retrieve Values using Keeper Notation

get_notation(query)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific standard field with Keeper Notation
password = secrets_manager.get_notation('EG6KdJaaLG7esRZbMnfbFA/field/password')[0]

# get a specific custom field with Keeper Notation
custom_field_value = secrets_manager.get_notation('EG6KdJaaLG7esRZbMnfbFA/custom_field/my_field')

See Keeper Notation documentation to learn about Keeper Notation format and capabilities

Parameter

Type

Required

Default

Description

query

String

Yes

Keeper Notation query for getting a value from a specified field

Returns

Type: string or string[]

The value of the queried field

Retrieve a TOTP Code

get_totp_code(url)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage
from keeper_secrets_manager_core.utils import get_totp_code

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get TOTP url value from a record
url = record.get_standard_field_value('oneTimeCode', True)

# get code from TOTP url
totp = get_totp_code(url)
print(totp.code)

Parameter

Type

Required

Default

Description

url

String

Yes

TOTP Url

Update a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Save Changes to a Secret

save(record: KeeperRecord)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by UID
secret_to_update = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# update a field value
secret_to_update.field('login', 'new login')

# update non-field values
secret_to_update.title = "New Title"
secret_to_update.dict["notes"] = "New Notes"
secret_to_update._update()

# save updated secret
secrets_manager.save(secret_to_update)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
     config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by UID
secret = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# rotate password on the record
secret.field('password', 'new password')
# start a transaction
secrets_manager.save(secret, 'rotation')
# rotate password on remote host
success = rotate_remote_ssh_password('new password')
# complete the transaction - commit or rollback
secrets_manager.complete_transaction(secret.uid, rollback=not success)

record

KeeperRecord

Yes

Storage and query configuration

Set field values using the field method. For a detailed list of available fields based on the Keeper Record Type, see the record-type-info command in Keeper Commander. Some fields have multiple values, in these cases the value can be set to a list.

Update a Standard Field Value

secret.field(field_type, single=False, value=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by record UID
secret = secrets_manager.get_secrets(['<RECORD UID>'])[0]

# update login
secret.field("login", single=True, "My New Login")

# save secret
secrets_manager.save(secret)

Parameter

Type

Required

Default

Description

field_type

String

Yes

Field type to get

single

boolean

Optional

False

Return only the first value

value

String or String[]

Optional

None

If passed, set the value of the field to the given value

Update a Custom Field Value

secret.custom_field(label, field_type=None, single=False, value=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by UID
secret = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# Get a standard template field
password = secret.field('password', single=True)

# Set custom field 'API Key'
my_new_api_key = "wKridl2ULt20qGuiP3IY"
secret.custom_field('API Key', single=True, my_new_api_key)

# Save changes to the secret
secrets_manager.save(secret)

Parameter

Type

Required

Default

Description

label

String

Yes

Label of the custom field

field_type

String

Yes

Field type to get

single

boolean

Optional

False

Return only the first value

value

String or String[]

Optional

None

If passed, set the value of the field to the given value

Generate a Random Password

generate_password(length, lowercase, uppercase, digits, specialCharacters)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage
from keeper_secrets_manager_core.utils import generate_password

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# get a specific secret by UID
secret = secrets_manager.get_secrets(['EG6KdJaaLG7esRZbMnfbFA'])[0]

# generate a random password
password = generate_password()
# update a record with new password
secret.field('password', value=password)

# Save changes to the secret
secrets_manager.save(secret)
Parameter
Type
Required
Default

length

int

Optional

64

lowercase

int

Optional

0

uppercase

int

Optional

0

digits

int

Optional

0

specialCharacters

int

Optional

0

Each parameter indicates the min number of a type of character to include. For example, 'uppercase' indicates the minimum number of uppercase letters to include.

Download a File

file.save_file(file_path, create_folders=False)
# Save all files to a /tmp folder (create folder if does not exist)
for file in secret.files:
    print("file: %s" % file)
    file.save_file("/tmp/" + file.name, True)

Parameter

Type

Required

Default

Description

file_path

String

Yes

Path to save file to

create_folders

boolean

No

False

Create folders in the file_path if not present

Upload a File

Upload File:

upload_file(owner_record, file: my_file)

Creating the Keeper File Upload Object:

KeeperFileUpload.from_file(path, file_name=None, file_title=None, mime_type=None)
from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage
from keeper_secrets_manager_core.core import KeeperFileUpload

secrets_manager = SecretsManager(
    config=FileKeyValueStorage('ksm-config.json')
)

# Get an individual secret by UID to attach the file to
UID_FILTER = 'XXX'
owner_record= secrets_manager.get_secrets([UID_FILTER])[0]

# Prepare file data for upload
my_file = KeeperFileUpload.from_file("./myFile.json", "myfile.json", "My File") 

# Upload file attached to the owner record and get the file UID
file_uid = secrets_manager.upload_file(owner_record, file = my_file)

Upload File

Parameter
Type
Required
Description

owner_record

KeeperRecord

Yes

The record to attach the uploaded file to

file

KeeperFileUpload

Yes

The File to upload

Keeper File Upload From File

Parameter
Type
Required
Default
Description

path

string

Yes

Path to the file to upload

file_name

string

No

None

What the name of the file will be in Keeper once uploaded

file_title

string

No

None

What the title of the file will be in Keeper once uploaded

mime_type

string

No

None

The type of data in the file. If none is provided, 'application/octet-stream' will be used

Returns

Type: string

The file UID of the attached file

Create a Secret

Prerequisites:

  • Shared folder UID

    • Shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using upload_file

from keeper_secrets_manager_core.dto.dtos import RecordCreate,RecordField

record = RecordCreate(record_type='login', title='test_KSM')
record.fields = [ 
    RecordField(field_type='login',value='test_login'),
    RecordField(field_type='password',value='test_pwd') 
]

secrets_manager.create_secret(folder_uid, record)
Parameter
Type
Required
Default

folder_uid

String

Yes

record

KeeperRecord

Yes

from keeper_secrets_manager_core.dto.dtos import RecordCreate,RecordField

record = RecordCreate(record_type='login', title='test_KSM')
record.fields = [ 
    RecordField(field_type='login',value='test_login'),
    RecordField(field_type='password',value='test_pwd') 
]

from keeper_secrets_manager_core.dto.payload import CreateOptions

create_options = CreateOptions(
    folder_uid='shared_folder_uid',
    subfolder_uid='user_folder_uid'
)

secrets_manager.create_secret_with_options(create_options, record)
Parameter
Type
Required
Default

create_options

CreateOptions

Yes

record

KeeperRecord

Yes

This example creates a login type record with a login value and a generated password.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

# create a new login record
new_login_record = RecordCreate('login', "Sample KSM Record: Python")
# fill in login and password fields
new_login_record.fields = [
    RecordField(field_type='login', value='[email protected]'),
    RecordField(field_type='password', value=generate_password())
]
# fill in notes
new_login_record.notes = 'This is a Python record creation example'
# create the new record and get its UID
record_uid = secrets_manager.create_secret('[FOLDER UID]', new_login_record)

This example creates a record with a custom record type.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage
from keeper_secrets_manager_core.dto.dtos import RecordCreate, RecordField
from keeper_secrets_manager_core.utils import generate_password

# setup secrets manger
secrets_manager = SecretsManager(
    # token='US:XXXXXX',
    config=FileKeyValueStorage('ksm-config.json')
)

custom_login = RecordCreate(record_type='Custom Login', title='Sample Custom Type KSM Record: Python')
custom_login.fields = [
    RecordField(field_type='host', 
                value={'hostName': '127.0.0.1', 'port': '8080'}, 
                label="My Custom Host lbl", 
                required=True),
    RecordField(field_type='login', 
                value='[email protected]', 
                label='My Custom Login lbl', 
                required=True),
    RecordField(field_type='password', 
                value=generate_password(), 
                label='My Custom Password lbl', 
                required=True),
    RecordField(field_type='url', 
                value='http://localhost:8080/login', 
                label='My Login Page', 
                required=True),
    RecordField(field_type='securityQuestion', 
                value={
                    'question': 'What is one plus one (write just a number)', 
                    'answer': '2'
                }, 
                label='My Question 1', 
                required=True),
    RecordField(field_type='phone', 
                value={
                  'region': 'US', 
                  'number': '510-444-3333', 
                  'ext': '2345', 
                  'type': 'Mobile'}, 
                label='My Phone Number'),
    RecordField(field_type='date', 
                value=1641934793000, 
                label='My Date Lbl', 
                required=True),
    RecordField(field_type='name', 
                value={
                  'first': 'John', 
                  'middle': 'Patrick', 
                  'last': 'Smith'}, 
                label="My Custom Name lbl", 
                required=True),
    RecordField(field_type='oneTimeCode', 
                value='otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example', 
                label='My TOTP', 
                required=True)
]

custom_login.custom = [
    RecordField(field_type='phone', 
                value={'region': 'US', 'number': '510-222-5555', 'ext': '99887', 'type': 'Mobile'}, 
                label='My Custom Phone Lbl 1'),
    RecordField(field_type='phone', 
                value={'region': 'US', 'number': '510-111-3333', 'ext': '45674', 'type': 'Mobile'}, 
                label='My Custom Phone Lbl 2'),
]

custom_login.notes = "\tThis custom type record was created\n\tvia Python SDK copied from https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/python-sdk"

record_uid = secrets_manager.create_secret('[FOLDER UID]', custom_login)

Returns

Type: string

The record UID of the new record

Delete a Secret

The Python KSM SDK can delete records in the Keeper Vault.

secrets_manager.delete_secret(record_uid)

Parameter
Type
Required

record_uid

string

Yes

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

# setup secrets manger
secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json')
)

# delete a specific secret by record UID
secret = secrets_manager.delete_secret('EG6KdJaaLG7esRZbMnfbFA')

Caching

To protect against losing access to your secrets when network access is lost, the Python SDK allows caching of secrets to the local machine in an encrypted file.

Setup and Configure Cache

In order to setup caching in the Python SDK, include a caching post function when creating a SecretsManager object.

The Python SDK includes a default caching function in KSMCache class which stores cached queries to a local file thus serving as a disaster recovery function (as long as there's network connectivity it always prefers network over cached data and will use cache only if web vault is inaccessible). You can create your own caching function using KSMCache as a starting point - ex. one that prefers local cache over network access and provide own cache management (ex. refresh cached data once every 5 min)

secrets_manager = SecretsManager(
    token='<One Time Access Token>',
    config=FileKeyValueStorage('ksm-config.json'),
    custom_post_function=KSMCache.caching_post_function
)

The default caching function in KSMCache class always stores last request only - ex. filtered request on UID1 but on disconnect request UID2 from same cache will return empty response (although UID2 may be shared to the same KSM app but it was not cached)

Updating a record from cache (or creating new record) invalidates cached record data and consecutive updates of the same record will fail. Batch updates work as long as they modify different records. Always follow up cached record updates with a call to get_secrets function to refresh cache (and pull updated metadata from vault like the new record revision etc.)

Creating your own caching function

For start create caching function with following arguments and call post_function

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.core import KSMCache, KSMHttpResponse

def caching_post_function(
        url, transmission_key, encrypted_payload_and_signature, verify_ssl_certs=True, proxy_url=None
):
    ksm_rs = SecretsManager.post_function(
        url, transmission_key, encrypted_payload_and_signature, verify_ssl_certs
    )
    # Your custom caching logic here ...

    # Make sure to always return a KSMHttpResponse object
    return ksm_rs

Then you can implement any custom logic of caching using KSMCache. Full basic example:

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.core import KSMCache, KSMHttpResponse
from keeper_secrets_manager_core.storage import FileKeyValueStorage
from http import HTTPStatus

def caching_post_function(
        url, transmission_key, encrypted_payload_and_signature, verify_ssl_certs=True, proxy_url=None
):
    ksm_rs = SecretsManager.post_function(
        url, transmission_key, encrypted_payload_and_signature, verify_ssl_certs
    )

    if ksm_rs.status_code < 400:
        KSMCache.save_cache(transmission_key.key + ksm_rs.data)
        return ksm_rs

    # KSMCache can be empty    
    cached_data = KSMCache.get_cached_data()
    cached_transmission_key = cached_data[:32]
    transmission_key.key = cached_transmission_key
    data = cached_data[32 : len(cached_data)]

    new_rs = KSMHttpResponse(HTTPStatus.OK, data, None)
    return new_rs


secrets_manager = SecretsManager(
    config=FileKeyValueStorage('ksm-config.json'),
    verify_ssl_certs=False,
    custom_post_function=caching_post_function
)

Folders

Folders have full CRUD support - create, read, update and delete operations.

Read Folders

Downloads full folder hierarchy.

get_folders()

Response

Type: List[KeeperFolder]

Example Usage

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

secrets_manager = SecretsManager(config=FileKeyValueStorage('ksm-config.json'))
folders = secrets_manager.get_folders()

Create a Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required - UID of a shared folder, while sub-folder UID is optional and if missing new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

create_folder(create_options: CreateOptions, folder_name: str, folders=None)
Parameter
Type
Required
Default
Description

create_options

CreateOptions

Yes

The parent and sub-folder UIDs

folder_name

str

Yes

The Folder name

folders

List[KeeperFolder]

No

None

List of folders to use in the search for parent and sub-folder from CreateOptions

Example Usage

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.core import CreateOptions
from keeper_secrets_manager_core.storage import FileKeyValueStorage

secrets_manager = SecretsManager(config=FileKeyValueStorage('ksm-config.json'))
co = CreateOptions(folder_uid="[PARENT_SHARED_FOLDER_UID]", subfolder_uid="")
new_folder_uid = secrets_manager.create_folder(co, "new_folder")

Update a Folder

Updates the folder metadata - currently folder name only.

update_folder(folder_uid: str, folder_name: str, folders=None)
Parameter
Type
Required
Default
Description

folder_uid

str

Yes

The folder UID

folder_name

str

Yes

The new folder name

folders

List[KeeperFolder]

No

None

List of folders to use in the search for parent folder

Example Usage

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

secrets_manager = SecretsManager(config=FileKeyValueStorage('ksm-config.json'))
secrets_manager.update_folder("[FOLDER_UID]", "new_folder_name")

Delete Folders

Removes a list of folders. Use force_deletion flag to remove non-empty folders.

When using force_deletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

delete_folder(folder_uids: List[str], force_deletion: bool = False)
Parameter
Type
Required
Default
Description

folder_uids

List[str]

Yes

The folder UID list

force_deletion

bool

No

False

Force deletion of non-empty folders

Example Usage

from keeper_secrets_manager_core import SecretsManager
from keeper_secrets_manager_core.storage import FileKeyValueStorage

secrets_manager = SecretsManager(config=FileKeyValueStorage('ksm-config.json'))
secrets_manager.delete_folder(["[FOLDER_UID1]", "[FOLDER_UID2]"], True)

Proxy support

Environment variable

Keeper Secrets Manager SDK uses the requests library to support the HTTPS_PROXY environment variable by default

HTTPS_PROXY=https://yourproxy:8888 python main.py

Every request including Keeper Secrets Manager requests will go through declared proxy

Using environment variables for proxy settings is preferred because it keeps configuration out of code, ensures consistency across tools, and simplifies deployment.

SecretsManager parameter

Optionally, you can pass your proxy url to SecretsManager if you want proxy to be used only in SDK:

secrets_manager = SecretsManager(
    config=FileKeyValueStorage('ksm-config.json'),
    proxy_url="https://yourproxy:8888"
)

If your proxy has authentication, just pass your username and password in proxy url

https://username:pass@yourproxy:8888

Java/Kotlin SDK

Detailed Java and Kotlin SDK docs for Keeper Secrets Manager

Download and Installation

Install With Maven or Gradle

build.gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.keepersecurity.secrets-manager:core:17.1.2+'
    implementation("org.bouncycastle:bc-fips:1.0.2.4")
}
pom.xml
<dependency>
    <groupId>com.keepersecurity.secrets-manager</groupId>
    <artifactId>core</artifactId>
    <version>[17.1.2,)</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bc-fips</artifactId>
    <version>1.0.2.4</version>
</dependency>

Cryptographic Provider

The Keeper Secrets Manager SDK expects the developer to use their required cryptographic provider. As documented above, Keeper will use the default cryptographic module of the Java runtime unless a specific provider is added. In the examples here in this documentation, we are using the BouncyCastle FIPS provider.

In the source code, ensure that the provider is loaded in the security context:

fun main() {
    Security.addProvider(BouncyCastleFipsProvider())
...

See the file CryptoUtilsTest.kt as shown in this example on how to use a custom security provider.

Source Code

Find the Java/Kotlin source code in the GitHub repository

Initialize Storage

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

In order to retrieve secrets, you must first initialize the local storage on your machine.

initializeStorage(storage: KeyValueStorage, clientKey: String? = null, hostName: String? = null)

Parameter

Type

Required

Default

Description

storage

KeyValueStorage

Yes

clientKey

String

Optional

null

hostName

String

Optional

null

Example Usage

import static com.keepersecurity.secretsManager.core.SecretsManager.initializeStorage;
import com.keepersecurity.secretsManager.core.LocalConfigStorage;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// oneTimeToken is used only once to initialize the storage
// after the first run, subsequent calls will use "ksm-config.txt" file
String oneTimeToken = "[One Time Access Token]";
LocalConfigStorage storage = new LocalConfigStorage("ksm-config.txt");

Security.addProvider(new BouncyCastleFipsProvider());

try {
    initializeStorage(storage, oneTimeToken);
    SecretsManagerOptions options = new SecretsManagerOptions(storage);
    // Using token only to generate a config (for later usage)
    // requires at least one access operation to bind the token
    //getSecrets(options)
 } catch (Exception e) {
    System.out.println(e.getMessage());
 }

Retrieve Secrets

getSecrets(options: SecretsManagerOptions, recordsFilter: List<String> = emptyList()): KeeperSecrets

Parameter

Type

Required

Default

Description

options

SecretsManagerOptions

Yes

Storage and query configuration

recordsFilter

List<String>

Optional

Empty List

Record search filters

Response

Type: KeeperSecrets

Object containing all Keeper records, or records that match the given filter criteria

Example Usage

Retrieve all Secrets

import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

//get secrets
SecretsManagerOptions options = new SecretsManagerOptions(storage);
KeeperSecrets secrets = SecretsManager.getSecrets(options);

//get records from secrets
List<KeeperRecord> records = secrets.getRecords();

Retrieve one secret by UID

import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

//get secrets
SecretsManagerOptions options = new SecretsManagerOptions(storage);
KeeperSecrets secrets = SecretsManager.getSecrets(options);

// identify one or more record UID to fetch secrets by
List<String> uidFilter = List.of("[XXX]");

// fetch secrets with the filter
KeeperSecrets secrets = SecretsManager.getSecrets(options, uidFilter);

//get records from secrets
List<KeeperRecord> records = secrets.getRecords();

Retrieve Secrets by Title

// get all matching records
getSecretsByTitle(recordTitle: String): List<KeeperRecord>

// get only the first matching record
getSecretByTitle(recordTitle: String): KeeperRecord
Parameter
Type
Required
Description

recordTitle

String

Yes

Record title to search for

Example Usage

import com.keepersecurity.secretsManager.core.*;
import java.util.List;

public class KSMSample {
    public static void main(String[] args){
        
        // Ensure security provider is loaded
        Security.addProvider(new BouncyCastleFipsProvider());

        // get pre-initialized storage
        KeyValueStorage storage = new LocalConfigStorage("ksm-config.json");
        try {
            SecretsManagerOptions options = new SecretsManagerOptions(storage);

            // title of the record to fetch
            String recordTitle = "My Credentials";
            
            // search for record by title
            KeeperRecord myCredentials = secrets.getRecords().getSecretByTitle(recordTitle);

            // print out record details
            System.out.println("Record UID: " + myCredentials.getRecordUid());
            System.out.println("Title: " + myCredentials.getData().getTitle());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

Retrieve Values From a Secret

Retrieve a Password

This shortcut gets the password of a secret once that secret has been retrieved from Keeper Secrets Manager.

secret.getPassword()
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

//get secrets
SecretsManagerOptions options = new SecretsManagerOptions(storage);
KeeperSecrets secrets = SecretsManager.getSecrets(options);

//get the first record
List<KeeperRecord> records = secrets.getRecords().get(0);

//get the password from the first record
firstRecord.getPassword()

Retrieve Fields

secret.getData().getField(<FIELD_TYPE>)
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

//get secrets
SecretsManagerOptions options = new SecretsManagerOptions(storage);
KeeperSecrets secrets = SecretsManager.getSecrets(options);

//get the first record
List<KeeperRecord> records = secrets.getRecords();
KeeperRecord firstRecord = secrets.getRecords().get(0);

//get the password from the first record
KeeperRecordField pwd = firstRecord.getData().getField(Password.class)

To get a field value, you will need to cast the return to the class of the corresponding field type. For a list of field types see the page.

Keeper Notation

Notation.getValue(secret, "<query>");
// Query example "<RECORD UID>/field/login"
import static com.keepersecurity.secretsManager.core.SecretsManager.*
import static com.keepersecurity.secretsManager.core.Notation.*;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

// get secrets
KeeperSecrets secrets = getSecrets(options);

// get login with dot notation
String login = getValue(secrets, "BediNKCMG21ztm5xGYgNww/field/login");

See Keeper Notation documentation to learn about Keeper Notation format and capabilities

Parameter

Type

Required

Default

Description

secret

KeeperRecord

Yes

Record to get field value from

query

String

Yes

Dot notation query of desired field

Get TOTP Code

TotpCode.uriToTotpCode(url)
import static com.keepersecurity.secretsManager.core.Notation.*;
import static com.keepersecurity.secretsManager.core.TotpCode.*;
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;

...

// get secrets
KeeperSecrets secrets = getSecrets(options);

// get TOTP url from record
String url= getValue(secrets, "BediNKCMG21ztm5xGYgNww/field/oneTimeCode");

// get TOTP code
TotpCode totp = uriToTotpCode(url);

Parameter

Type

Required

Default

Description

url

String

Yes

TOTP Url

Update Values in a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Update Secret

updateSecret(options: SecretsManagerOptions, recordToUpdate: KeeperRecord);
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import static com.keepersecurity.secretsManager.core.SecretsManager.*;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

// get secrets
SecretsManagerOptions options = SecretsManagerOptions(storage);
KeeperSecrets secrets = getSecrets(options);

// we'll update the first record
KeeperRecord recordToUpdate = secrets.getRecords().get(0);

// update password
recordToUpdate.updatePassword("aP1$t367QOCvL$eM$bG#");

// update title and notes
recordToUpdate.data.title = "New Title"
recordToUpdate.data.notes = "My Notes"

// save changes
updateSecret(options, recordToUpdate); 
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;

import static com.keepersecurity.secretsManager.core.SecretsManager.*;

...

// get secrets
SecretsManagerOptions options = SecretsManagerOptions(storage);
KeeperSecrets secrets = getSecrets(options);

// we'll update the first record
KeeperRecord record = secrets.getRecords().get(0);

// rotate password on the record
record.updatePassword("aP1$t367QOCvL$eM$bG#");

// start a transaction
updateSecret(options, record, transactionType = UpdateTransactionType.GENERAL);
// rotate password on remote host
boolean success = rotateRemoteSshPassword("aP1$t367QOCvL$eM$bG#");
// complete the transaction - commit or rollback
completeTransaction(options, record.recordUid, rollback = !success);

Update Secret is used to save changes made to a secret. Once updateSecret is performed successfully, the changes are reflected in the Keeper Vault.

Parameter

Type

Required

Default

Description

options

SecretsManagerOptions

Yes

Storage and query configuration

recordToUpdate

KeeperRecord

Yes

Record to update

Update Password

recordToUpdate.updatePassword(password: String);

SecretsManager.updateSecret(options, recordToUpdate);
import static com.keepersecurity.secretsManager.core.SecretsManager;

import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperSecrets;

// get secrets
SecretsManagerOptions options = SecretsManagerOptions(storage);
KeeperSecrets secrets = getSecrets(options);

// we'll update the first record
KeeperRecord recordToUpdate = secrets.getRecords().get(0);

// update password
recordToUpdate.updatePassword("aP1$t367QOCvL$eM$bG#");

// save changes
SecretsManager.updateSecret(options, recordToUpdate);

Parameter

Type

Required

Default

Description

password

String

Yes

New password to set

Update other fields

//format
RecordField.getValue().set(index, value)

//example - Login field
recordLogin.getValue().set(0, "New Login");
// get field to edit
Login recordLogin = (Login) recordToUpdate.getData().getField(Login.class);

// update field value
recordLogin.getValue().set(0, "New Login");

// save changes
SecretsManager.updateSecret(options, recordToUpdate);

Each record field type is represented by a class. Cast the field to the corresponding class in order to correctly access the field's value. Check the documentation for a list of field types.

Fields can have multiple values, which is accessed in a List. In this example we are updating the login field, which only accepts one value, so we update the one value in the values list.

Generate a Random Password

generatePassword(length: int, lowercase: int, uppercase: int, digits: int, specialCharacters: int)
import com.keepersecurity.secretsManager.core.CryptoUtils;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

// get field to edit
Password recordPassword = (Password) recordToUpdate.getData().getField(Password.class);

// generate a random password
String password = CryptoUtils.generatePassword();

// update field value
recordPassword.getValue().set(0, password);

// save changes
SecretsManager.updateSecret(options, recordToUpdate);
Parameter
Type
Required
Default

length

int

Optional

64

lowercase

int

Optional

0

uppercase

int

Optional

0

digits

int

Optional

0

specialCharacters

int

Optional

0

Each parameter indicates the min number of a type of character to include. For example, 'uppercase' indicates the minimum number of uppercase letters to include.

Download a File

SecretsManager.downloadFile(file): ByteArray
import static com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperFile;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

// download the first file from the first record
KeeperRecord firstRecord = secrets.getRecords().get(0);
KeeperFile file = firstRecord.getFileByName("acme.cer");
byte[] fileBytes = SecretsManager.downloadFile(file);

// write file to a disk
try (FileOutputStream fos = new FileOutputStream(file.getData().getName())) {
    fos.write(fileBytes);
} catch (IOException ioException){
    ioException.printStackTrace();
}

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File to download

Response

Type: ByteArray

ByteArray of file for download

Download a Thumbnail

SecretsManager.downloadThumbnail(file): ByteArray
import static com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperFile;

// Ensure security provider is loaded
Security.addProvider(new BouncyCastleFipsProvider());

// download the first file from the first record
KeeperRecord firstRecord = secrets.getRecords().get(0);
KeeperFile file = firstRecord.getFileByName("acme.cer");
byte[] fileBytes = SecretsManager.downloadThumbnail(file);

// write file to a disk
try (FileOutputStream fos = new FileOutputStream(file.getData().getName())) {
    fos.write(fileBytes);
} catch (IOException ioException){
    ioException.printStackTrace();
}

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File with thumbnail to download

Response

Type: ByteArray

ByteArray of thumbnail for download

Upload a File

Upload File:

uploadFile(options: SecretsManagerOptions, ownerRecord: KeeperRecord, file: KeeperFileUpload): String
Parameter
Type
Required
Description

options

SecretsManagerOptions

Yes

Storage and query configuration

ownerRecord

KeeperRecord

Yes

The record to attach the uploaded file to

file

KeeperFileUpload

Yes

The File to upload

Creating the Keeper File Upload Object:

KeeperFileUpload(
    val name: String,
    val title: String,
    val type: String?,
    val data: ByteArray
)
Parameter
Type
Required
Description

name

string

Yes

What the name of the file will be in Keeper once uploaded

title

string

Yes

What the title of the file will be in Keeper once uploaded

type

string

Optional

The mime type of data in the file. 'application/octet-stream' will be used if nothing is given

data

ByteArray

Yes

File data as bytes

Example Usage

import com.keepersecurity.secretsManager.core.*;

import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;

public class KSMSample {
    public static void main(String[] args){
    
        // Ensure security provider is loaded
        Security.addProvider(new BouncyCastleFipsProvider());

        // get pre-initialized storage
        KeyValueStorage storage = new LocalConfigStorage("ksm-config.json");
        try {
            SecretsManagerOptions options = new SecretsManagerOptions(storage);

            // create a filter with the UID of the record we want
            List<String> uidFilter = List.of("XXX");

            // fetch secrets with the filter
            KeeperSecrets secrets = SecretsManager.getSecrets(options, uidFilter);

            // get the desired secret to upload a file to
            KeeperRecord ownerRecord = secrets.getRecords().get(0);
        
            // get bytes from file to upload
            File file = new File("./myFile.json");
            FileInputStream fl = new FileInputStream(file);
            byte[] fileBytes = new byte[(int)file.length()];
            fl.read(fileBytes);
            fl.close();
            
            // create a Keeper File to upload
            KeeperFileUpload myFile = new KeeperFileUpload(
                "myFile.json",
                "My File", 
                "application/json", 
                fileBytes
            )

            // upload the file to the selected record
            SecretsManager.uploadFile(options, ownerRecord, myFile);
            
        } catch (Exception e) {
            System.out.println("KSM ran into an problem: " + e.getMessage());
        }
    }
}

Remove Files from a Record

SDK Version Required: 17.1.1 or higher

This feature add the ability to remove file attachments from records using the UpdateOptions class with the linksToRemove parameter.

Prerequisites:

  • Record UID or KeeperRecord object containing files

  • File UIDs of the files to be removed

  • Files must exist on the record to be removed

Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

record

KeeperRecord

Yes

The record to update

updateOptions

UpdateOptions

Yes

Options containing files to remove

Parameter
Type
Required
Default
Description

transactionType

UpdateTransactionType

No

null

Transaction type for batch operations

linksToRemove

List<String>

Yes

List of file UIDs to remove

// Remove files that start with "teamp_"
List<String> filesToRemove = new ArrayList<>();
for (KeeperFile file : record.getFiles()) {
    if (file.getData().getTitle().startsWith("temp_")) {
        filesToRemove.add(file.getFileUid());
    }
}

if (!filesToRemove.isEmpty()) {
    UpdateOptions updateOptions = new UpdateOptions(null, filesToRemove);
    SecretsManager.updateSecretWithOptions(options, record, updateOptions);
}
// Remove files that start with "teamp_"
val filesToRemove = record.files
    ?.filter { it.data?.title?.startsWith("temp_") == true }
    ?.map { it.fileUid }
    ?: emptyList()

if (filesToRemove.isNotEmpty()) {
    updateSecretWithOptions(
        options,
        record,
        UpdateOptions(linksToRemove = filesToRemove)
    )
}

Full Example Usage:

import com.keepersecurity.secretsManager.core.*;
import java.util.*;

// Get record with files
QueryOptions queryOptions = new QueryOptions(
    Arrays.asList(recordUid),
    Collections.emptyList(),
    true  // request files
);

KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);
KeeperRecord record = secrets.getRecords().get(0);

// Remove specific files
List<String> fileUidsToRemove = Arrays.asList("fileUid1", "fileUid2");

UpdateOptions updateOptions = new UpdateOptions(
    null,              // transactionType
    fileUidsToRemove  // linksToRemove
);

SecretsManager.updateSecretWithOptions(options, record, updateOptions);

Create a Secret

Prerequisites:

  • Shared folder UID

    • Shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using uploadFile

SecretsManager.createSecret(options, folderUid, newRecordData, secrets);
Parameter
Type
Required
Default

options

SecretsManagerOptions

Yes

folderUid

String

Yes

newRecordData

KeeperRecordData

Yes

secrets

KeeperSecrets

Optional

Freshly fetched list of all secrets from the Keeper servers

SecretsManager.createSecret2(options, createOptions, newRecordData, folders);
Parameter
Type
Required
Default

options

SecretsManagerOptions

Yes

createOptions

CreateOptions

Yes

newRecordData

KeeperRecordData

Yes

folders

KeeperFolder[]

Optional

Freshly fetched list of all folders from the Keeper servers

This example creates a login type record with a login value and a generated password.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager Application has access to.

import com.keepersecurity.secretsManager.core.*;

KeeperRecordData newRecordData = new KeeperRecordData(
        "Sample KSM Record: Java",
        "login",
        Arrays.asList(
                new Login("My Username"),
                new Password(CryptoUtils.generatePassword())
        ),
        null,
        "This is a \nmultiline\n\n\tnote"
);

String recordUid = SecretsManager.createSecret(options, folderUid, newRecordData);

This example creates a record with a custom record type.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager Application has access to.

import com.keepersecurity.secretsManager.core.*;

KeeperRecordData newRecordData = new KeeperRecordData(
        "Sample Custom Type KSM Record: Java",
        "Custom Login",                              // Record Type Name
        Arrays.asList(
                new Hosts(
                        "My Custom Host lbl",        // label
                        true,                        // required
                        false,                       // private screen
                        List.of(new Host("127.0.0.1", "8000"))),
                // OR new Hosts(new Host("127.0.0.1", "8000"))

                new Login("My Custom Login lbl",
                        true,
                        false,
                        List.of("[email protected]")),
                // OR new Login("[email protected]")

                new Password( "My Custom Password lbl",
                        true,
                        false,
                        List.of(CryptoUtils.generatePassword())),
                // OR new Password(CryptoUtils.generatePassword())

                new Url("My Login Page",
                        true,
                        false,
                        List.of("http://localhost:8080/login")),
                // OR new Url("http://localhost:8080/login")
                
                new SecurityQuestions(
                        "My Question 1",
                        true,
                        false,
                        List.of(new SecurityQuestion("What is one plus one (write just a number)", "2"))),
                // OR new SecurityQuestions(new SecurityQuestion("What is one plus one (write just a number)", "2"))

                new Phones("My Phone Number",
                        true,
                        false,
                        List.of(new Phone("US", "510-444-3333", "2345", "Mobile"))),
                // OR new Phones(new Phone("US", "510-444-3333", "2345", "Mobile"))

                new Date("My Date Lbl",
                        true,
                        false,
                        List.of(1641934793000L)
                ),
                // OR new Date(1641934793000L),

                new Names("My Custom Name lbl",
                        true,
                        false,
                        List.of(new Name("John", "Patrick", "Smith"))),
                // OR new Names(new Name("John", "Patrick", "Smith"))

                new OneTimeCode("My TOTP",
                        true,
                        false,
                        List.of("otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"))
                // OR new OneTimeCode("otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example")
        ),
        Arrays.asList(
                new Phones(new Phone("US", "(510) 123-3456")),
                new Phones(new Phone("US", "510-111-3333", "45674", "Mobile"))
        ),
        "\tThis custom type record was created\n\tvia KSM Java Document Example"
);

String recordUid = SecretsManager.createSecret(options, "[FOLDER UID]", newRecordData);

Delete a Secret

The Java/Kotlin KSM SDK can delete records in the Keeper Vault.

deleteSecret(smOptions, recordUids);

Parameter
Type
Required

smOptions

SecretsManagerOptions

Yes

recordUids

List<Sting>

Yes

// setup secrets manager
val storage = LocalConfigStorage("ksm-config.json")
//initializeStorage(storage, "<One Time Access Token>")
val smOptions = SecretsManagerOptions(storage)

// delete a specific secret by record UID
deleteSecret(smOptions, List.of("EG6KdJaaLG7esRZbMnfbFA"));

Caching

To protect against losing access to your secrets when network access is lost, the Java SDK allows caching of secrets to the local machine in an encrypted file.

Setup and Configure Cache

In order to setup caching in the Java SDK, include a caching post function as the second argument when instantiating aSecretsManagerOptions object.

The Java SDK includes a default caching function cachingPostFunction which stores cached queries to a file.

//create options with caching
SecretsManagerOptions options = new SecretsManagerOptions(storage, SecretsManager::cachingPostFunction);

//example get all secrets
SecretsManager.getSecrets(options)

Folders

Folders have full CRUD support - create, read, update and delete operations.

Read Folders

Downloads full folder hierarchy.

getFolders(options: SecretsManagerOptions): List<KeeperFolder>

Response

Type: List<KeeperFolder>

Example Usage

import com.keepersecurity.secretsManager.core.*;
SecretsManagerOptions options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
List<KeeperFolder> folders = SecretsManager.getFolders(options);

Create a Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required - UID of a shared folder, while sub-folder UID is optional and if missing new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

createFolder(options: SecretsManagerOptions, createOptions: CreateOptions, folderName: String, folders: List<KeeperFolder> = getFolders(options)): String
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

createOptions

CreateOptions

Yes

The parent and sub-folder UIDs

folderName

String

Yes

The Folder name

folders

List<KeeperFolder>

No

List<KeeperFolder>

List of folders to use in the search for parent and sub-folder from CreateOptions

data class CreateOptions  constructor(
    val folderUid: String,
    val subFolderUid: String? = null,
)
data class KeeperFolder(
    val folderKey: ByteArray,
    val folderUid: String,
    val parentUid: String? = null,
    val name: String
)

Example Usage

import com.keepersecurity.secretsManager.core.*;
SecretsManagerOptions options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
CreateOptions co := new CreateOptions("[PARENT_SHARED_FOLDER_UID]");
String folderUid = SecretsManager.createFolder(options, co, "new_folder");

Update a Folder

Updates the folder metadata - currently folder name only.

updateFolder(options: SecretsManagerOptions, folderUid: String, folderName: String, folders: List<KeeperFolder> = getFolders(options))
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

folderUid

String

Yes

The folder UID

folderName

String

Yes

The new folder name

folders

List<KeeperFolder>

No

List<KeeperFolder>

List of folders to use in the search for parent folder

Example Usage

import com.keepersecurity.secretsManager.core.*;
SecretsManagerOptions options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
SecretsManager.updateFolder(options, "[FOLDER_UID]", "new_folder_name");

Delete Folders

Removes a list of folders. Use forceDeletion flag to remove non-empty folders.

When using forceDeletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

deleteFolder(options: SecretsManagerOptions, folderUids: List<String>, forceDeletion: Boolean = false): SecretsManagerDeleteResponse
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

folderUids

List<String>

Yes

The folder UID list

forceDeletion

Boolean

No

false

Force deletion of non-empty folders

Example Usage

import com.keepersecurity.secretsManager.core.*;
SecretsManagerOptions options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
SecretsManager.deleteFolder(options, Arrays.asList("[FOLDER_UID1]", "[FOLDER_UID2]"), true);

PAM Records Types - Accessing Linked Credentials

SDK Version Required: 17.1.1 or higher

On PAM Resource Records Types (PAM Machine, PAM Directory, PAM Database), the following credentials can be linked:

  • Administrative Credentials - the credentials used to perform administrative operations on the resource

  • Launch Credentials - the credentials used to authenticate a launched session to the resource

Prerequisites:

  • Use getSecrets2() method instead of getSecrets()

  • Set requestLinks = true in QueryOptions to enable GraphSync™

  • Links will be null if requestLinks is false, empty list if true but no links exist

Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

queryOptions

QueryOptions

Yes

Must set requestLinks=true

QueryOptions Parameters

Parameter
Type
Required
Default
Description

recordsFilter

List<String>

No

Empty

Filter by record UIDs

foldersFilter

List<String>

No

Empty

Filter by folder UIDs

requestLinks

boolean

Yes

false

Must be true for GraphSync

Link Methods

Method
Returns
Description

getRecordUid()

String

Target record UID

isAdminUser()

boolean

Admin privileges

allowsRotation()

boolean

Rotation allowed

allowsConnections()

boolean

Connections allowed

Basic Usage - Retrieve Records with Links

import com.keepersecurity.secretsManager.core.*;
import java.util.*;

// Enable GraphSync™
QueryOptions queryOptions = new QueryOptions(
    Collections.emptyList(),  // recordsFilter
    Collections.emptyList(),  // foldersFilter
    true                      // requestLinks - REQUIRED
);

SecretsManagerOptions options = new SecretsManagerOptions(storage);
KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

// Access links
for (KeeperRecord record : secrets.getRecords()) {
    List<KeeperRecordLink> links = record.getLinks();
    if (links != null && !links.isEmpty()) {
        for (KeeperRecordLink link : links) {
            System.out.println("Links to: " + link.getRecordUid());
        }
    }
}

Check Link Properties

for (KeeperRecordLink link : record.getLinks()) {
    // Check user privileges
    if (link.isAdminUser()) {
        System.out.println("Admin user");
    }
    
    // Check permissions
    if (link.allowsRotation()) {
        System.out.println("Password rotation allowed");
    }
}

Common Example - Find PAM Users

// Find users associated with a PAM machine
for (KeeperRecord machine : secrets.getRecords()) {
    if ("pamMachine".equals(machine.getType())) {
        System.out.println("PAM Machine: " + machine.getTitle());
        
        List<KeeperRecordLink> links = machine.getLinks();
        if (links != null) {
            for (KeeperRecordLink link : links) {
                // Check if user is admin
                if (link.isAdminUser()) {
                    System.out.println("  Admin user: " + link.getRecordUid());
                }
            }
        }
    }
}

Additional Details

For detailed information on the retrievable fields on the PAM record types, see the Record Field Classes page.

For examples on handling Linked Credentials for advanced PAM use cases, see the Linked Credentials on PAM records page.

Linked Credentials on PAM Records

Description of each accessible field type on PAM Resource Records

SDK Version Required: 17.1.1 or higher

The document lists out the full list of Property methods and advanced use cases when interacting with the linked credentials on PAM Resource Records:

  • All Property Methods

  • Advanced Use Cases

  • Full Method Reference

All Property Methods

for (KeeperRecordLink link : record.getLinks()) {
    // Basic properties
    String targetUid = link.getRecordUid();
    String linkPath = link.getPath(); // e.g., "pamUser", "ai_settings", "jit_settings"
    String rawData = link.getData(); // Base64-encoded data

    // User privilege methods
    boolean isAdmin = link.isAdminUser();
    boolean isLaunchCredential = link.isLaunchCredential();

    // Permission methods
    boolean allowsRotation = link.allowsRotation();
    boolean allowsConnections = link.allowsConnections();
    boolean allowsPortForwards = link.allowsPortForwards();
    boolean allowsSessionRecording = link.allowsSessionRecording();
    boolean allowsTypescriptRecording = link.allowsTypescriptRecording();
    boolean allowsRemoteBrowserIsolation = link.allowsRemoteBrowserIsolation();

    // Settings methods
    boolean rotatesOnTermination = link.rotatesOnTermination();
    Integer dataVersion = link.getLinkDataVersion();

    // Data analysis methods
    boolean hasReadableData = link.hasReadableData();
    boolean hasEncryptedData = link.hasEncryptedData();
    boolean mightBeEncrypted = link.mightBeEncrypted();

    System.out.println("Link Analysis for " + targetUid + ":");
    System.out.println("  Path: " + linkPath);
    System.out.println("  Admin: " + isAdmin);
    System.out.println("  Launch Credential: " + isLaunchCredential);
    System.out.println("  Allows Rotation: " + allowsRotation);
    System.out.println("  Allows Connections: " + allowsConnections);
    System.out.println("  Has Encrypted Data: " + hasEncryptedData);
}

Advanced Use Cases

Advanced Data Access Patterns

Encrypted Data Handling

public void handleEncryptedLinkData(KeeperRecord record) {
    for (KeeperRecordLink link : record.getLinks()) {
        if (link.getData() != null) {
            System.out.println("\nAnalyzing link data for: " + link.getRecordUid());
            System.out.println("  Path: " + (link.getPath() != null ? link.getPath() : "null"));

            // Check encryption status
            boolean mightBeEncrypted = link.mightBeEncrypted();
            boolean hasEncryptedData = link.hasEncryptedData();
            boolean hasReadableData = link.hasReadableData();

            System.out.println("  Encryption Analysis:");
            System.out.println("    mightBeEncrypted(): " + mightBeEncrypted);
            System.out.println("    hasEncryptedData(): " + hasEncryptedData);
            System.out.println("    hasReadableData(): " + hasReadableData);

            try {
                if (hasEncryptedData || mightBeEncrypted) {
                    // Method 1: Use getDecryptedData for encrypted content
                    String decryptedData = link.getDecryptedData(record.getRecordKey());
                    System.out.println("    Decrypted Data: " + decryptedData);

                    // Method 2: Use getLinkData for structured access
                    Map<String, Object> linkData = link.getLinkData(record.getRecordKey());
                    if (linkData != null) {
                        System.out.println("    Structured Data:");
                        for (Map.Entry<String, Object> entry : linkData.entrySet()) {
                            System.out.println("      " + entry.getKey() + ": " + entry.getValue());
                        }
                    }
                } else {
                    // Plain base64 data
                    String plainData = link.getDecodedData();
                    System.out.println("    Plain Data: " + plainData);
                }

            } catch (Exception e) {
                System.out.println("    Error processing data: " + e.getMessage());
                System.out.println("    Raw Base64: " + link.getData());
            }
        }
    }
}

Settings-Specific Access Methods

public void demonstrateSettingsDataMethods(SecretsManagerOptions options) throws Exception {
    QueryOptions queryOptions = new QueryOptions(
        Collections.emptyList(),
        Collections.emptyList(),
        true
    );

    KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

    System.out.println("Settings Data Methods Demo:");
    boolean foundSettings = false;

    for (KeeperRecord record : secrets.getRecords()) {
        if (record.getLinks() != null && !record.getLinks().isEmpty()) {
            System.out.println("\nRecord: " + record.getTitle() + " (" + record.getType() + ")");

            for (KeeperRecordLink link : record.getLinks()) {
                String linkPath = link.getPath();
                System.out.println("  Link to " + link.getRecordUid() + " (path: " + linkPath + ")");

                // Test AI Settings method
                if ("ai_settings".equals(linkPath)) {
                    foundSettings = true;
                    System.out.println("    Testing getAiSettingsData():");
                    try {
                        Map<String, Object> aiSettings = link.getAiSettingsData(record.getRecordKey());
                        if (aiSettings != null) {
                            System.out.println("      AI Settings found:");
                            for (Map.Entry<String, Object> entry : aiSettings.entrySet()) {
                                System.out.println("        " + entry.getKey() + ": " + entry.getValue());
                            }
                        } else {
                            System.out.println("      AI Settings data could not be parsed");
                        }
                    } catch (Exception e) {
                        System.out.println("      Error parsing AI settings: " + e.getMessage());
                    }
                }

                // Test JIT Settings method
                if ("jit_settings".equals(linkPath)) {
                    foundSettings = true;
                    System.out.println(" Testing getJitSettingsData():");
                    try {
                        Map<String, Object> jitSettings = link.getJitSettingsData(record.getRecordKey());
                        if (jitSettings != null) {
                            System.out.println("   JIT Settings found:");
                            for (Map.Entry<String, Object> entry : jitSettings.entrySet()) {
                                System.out.println("        " + entry.getKey() + ": " + entry.getValue());
                            }
                        } else {
                            System.out.println("       JIT Settings data could not be parsed");
                        }
                    } catch (Exception e) {
                        System.out.println("   Error parsing JIT settings: " + e.getMessage());
                    }
                }

                // Test generic getSettingsForPath method
                if (linkPath != null && linkPath.endsWith("_settings")) {
                    foundSettings = true;
                    System.out.println("  Testing getSettingsForPath(\"" + linkPath + "\"):");
                    try {
                        Map<String, Object> settings = link.getSettingsForPath(linkPath, record.getRecordKey());
                        if (settings != null) {
                            System.out.println("   Settings found for path '" + linkPath + "':");
                            for (Map.Entry<String, Object> entry : settings.entrySet()) {
                                System.out.println("        " + entry.getKey() + ": " + entry.getValue());
                            }
                        } else {
                            System.out.println("       Settings data could not be parsed");
                        }
                    } catch (Exception e) {
                        System.out.println("   Error parsing settings: " + e.getMessage());
                    }
                }
            }
        }
    }

    if (!foundSettings) {
        System.out.println(" No settings paths found in current records.");
        System.out.println(" Settings paths to look for: ai_settings, jit_settings, *_settings");
    }
}

Complex Relationship Analysis

public class ComprehensiveDagAnalyzer {

    public static void analyzeLinkingPatterns(SecretsManagerOptions options) throws Exception {
        QueryOptions queryOptions = new QueryOptions(
            Collections.emptyList(),
            Collections.emptyList(),
            true // requestLinks
        );

        KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

        // Build relationship map
        Map<String, List<String>> relationshipMap = new HashMap<>();
        Map<String, String> recordTitles = new HashMap<>();
        Map<String, String> recordTypes = new HashMap<>();
        int totalLinks = 0;

        for (KeeperRecord record : secrets.getRecords()) {
            recordTitles.put(record.getRecordUid(), record.getTitle());
            recordTypes.put(record.getRecordUid(), record.getType());

            List<KeeperRecordLink> links = record.getLinks();
            if (links != null && !links.isEmpty()) {
                List<String> targets = new ArrayList<>();
                for (KeeperRecordLink link : links) {
                    targets.add(link.getRecordUid());
                    totalLinks++;
                }
                relationshipMap.put(record.getRecordUid(), targets);
            }
        }

        System.out.println("DAG Analysis Report:");
        System.out.println("===================");
        System.out.println("Total records: " + secrets.getRecords().size());
        System.out.println("Records with outgoing links: " + relationshipMap.size());
        System.out.println("Total links: " + totalLinks);

        // Find records that are targets (have incoming links)
        Set<String> targets = new HashSet<>();
        for (List<String> linkTargets : relationshipMap.values()) {
            targets.addAll(linkTargets);
        }
        System.out.println("Records that are link targets: " + targets.size());

        // Show detailed relationship patterns
        if (!relationshipMap.isEmpty()) {
            System.out.println("\nDetailed Relationship Patterns:");
            for (Map.Entry<String, List<String>> entry : relationshipMap.entrySet()) {
                String sourceTitle = recordTitles.get(entry.getKey());
                String sourceType = recordTypes.get(entry.getKey());
                System.out.println("  " + sourceTitle + " [" + sourceType + "] → " + entry.getValue().size() + " record(s)");

                for (String targetUid : entry.getValue()) {
                    String targetTitle = recordTitles.get(targetUid);
                    String targetType = recordTypes.get(targetUid);
                    System.out.println("    → " + (targetTitle != null ? targetTitle : "Unknown record: " + targetUid) +
                        " [" + (targetType != null ? targetType : "Unknown") + "]");
                }
            }
        } else {
            System.out.println("  No links found in current records.");
        }
    }
}

Advanced PAM User Management

public static List<UserStatus> getPamMachineUsers(String pamMachineUid, InMemoryStorage storage) {
    List<UserStatus> users = new ArrayList<>();

    try {
        QueryOptions queryOptions = new QueryOptions(
            Collections.emptyList(),
            Collections.emptyList(),
            true // requestLinks
        );

        SecretsManagerOptions options = new SecretsManagerOptions(storage);
        KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

        // Find the PAM Machine record
        KeeperRecord pamMachine = null;
        for (KeeperRecord record : secrets.getRecords()) {
            if (record.getRecordUid().equals(pamMachineUid) && "pamMachine".equals(record.getType())) {
                pamMachine = record;
                break;
            }
        }

        if (pamMachine != null && pamMachine.getLinks() != null) {
            System.out.println("PAM Machine: " + pamMachine.getTitle());
            System.out.println("Number of users associated with this PAM machine: " + pamMachine.getLinks().size());

            for (KeeperRecordLink link : pamMachine.getLinks()) {
                // Find the linked user record
                for (KeeperRecord record : secrets.getRecords()) {
                    if (record.getRecordUid().equals(link.getRecordUid()) && "pamUser".equals(record.getType())) {
                        // Use SDK utility method to check admin status
                        boolean isAdmin = link.isAdminUser();
                        boolean isLaunchCredential = link.isLaunchCredential();

                        users.add(new UserStatus(record.getTitle(), record.getRecordUid(), isAdmin, isLaunchCredential));
                        System.out.println("  " + record.getTitle() + " - [" + (isAdmin ? "IS ADMIN" : "IS NOT ADMIN") + "] [" +
                                         (isLaunchCredential ? "IS LAUNCH CREDENTIAL" : "IS NOT LAUNCH CREDENTIAL") + "]");
                        break;
                    }
                }
            }

            // Validate PAM configuration (from your test logic)
            long adminUsersCount = users.stream().filter(UserStatus::isAdmin).count();
            long launchCredentialUsersCount = users.stream().filter(UserStatus::isLaunchCredential).count();

            System.out.println("Summary:");
            System.out.println("  Admin users: " + adminUsersCount);
            System.out.println("  Launch credential users: " + launchCredentialUsersCount);

            if (adminUsersCount > 1) {
                System.out.println("Warning: Multiple admin users found - should typically be 1");
            }
            if (launchCredentialUsersCount > 1) {
                System.out.println("Warning: Multiple launch credentials - should typically be 1");
            }
        }

    } catch (Exception e) {
        System.err.println("Error retrieving PAM machine users: " + e.getMessage());
    }

    return users;
}

public static class UserStatus {
    private final String userName;
    private final String userUid;
    private final boolean isAdmin;
    private final boolean isLaunchCredential;

    public UserStatus(String userName, String userUid, boolean isAdmin, boolean isLaunchCredential) {
        this.userName = userName;
        this.userUid = userUid;
        this.isAdmin = isAdmin;
        this.isLaunchCredential = isLaunchCredential;
    }

    public String getUserName() { return userName; }
    public String getUserUid() { return userUid; }
    public boolean isAdmin() { return isAdmin; }
    public boolean isLaunchCredential() { return isLaunchCredential; }

    @Override
    public String toString() {
        return userName + " (" + userUid + ") - [" +
               (isAdmin ? "IS ADMIN" : "IS NOT ADMIN") + "] [" +
               (isLaunchCredential ? "IS LAUNCH CREDENTIAL" : "IS NOT LAUNCH CREDENTIAL") + "]";
    }
}

Comprehensive Linked Record Data Analysis

public static void analyzeLinkDataStructure(SecretsManagerOptions options) throws Exception {
    QueryOptions queryOptions = new QueryOptions(
        Collections.emptyList(),
        Collections.emptyList(),
        true
    );

    KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

    System.out.println("Link Data Structure Analysis:");
    for (KeeperRecord record : secrets.getRecords()) {
        if (record.getLinks() != null && !record.getLinks().isEmpty()) {
            System.out.println("\nRecord: " + record.getTitle() + " (" + record.getType() + ")");
            System.out.println("UID: " + record.getRecordUid());

            for (int i = 0; i < record.getLinks().size(); i++) {
                KeeperRecordLink link = record.getLinks().get(i);
                System.out.println("  Link " + (i + 1) + ":");
                System.out.println("    Target UID: " + link.getRecordUid());
                System.out.println("    Path: " + (link.getPath() != null ? link.getPath() : "null"));

                if (link.getData() != null) {
                    try {
                        if (link.hasEncryptedData() || link.mightBeEncrypted()) {
                            String decodedData = link.getDecryptedData(record.getRecordKey());
                            System.out.println("    Decoded Data: " + decodedData);
                        } else {
                            String decodedData = link.getDecodedData();
                            System.out.println("    Decoded Data: " + decodedData);
                        }
                    } catch (Exception e) {
                        System.out.println("    Raw Base64: " + link.getData());
                        System.out.println("    Decode Error: " + e.getMessage());
                    }
                } else {
                    System.out.println("    Data: null");
                }
            }
        }
    }
}

Complete Utility Methods Example

public static void demonstrateLinkUtilityMethods(SecretsManagerOptions options) throws Exception {
    QueryOptions queryOptions = new QueryOptions(
        Collections.emptyList(),
        Collections.emptyList(),
        true
    );

    KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

    System.out.println("Link Utility Methods Demo:");
    for (KeeperRecord record : secrets.getRecords()) {
        if (record.getLinks() != null && !record.getLinks().isEmpty()) {
            System.out.println("\nRecord: " + record.getTitle() + " (" + record.getType() + ")");

            for (int i = 0; i < record.getLinks().size(); i++) {
                KeeperRecordLink link = record.getLinks().get(i);
                System.out.println("  Link " + (i + 1) + " to " + link.getRecordUid() + ":");
                System.out.println("    Path: " + (link.getPath() != null ? link.getPath() : "null"));

                // User-related utilities
                if (link.isAdminUser()) {
                    System.out.println("     Admin user");
                }
                if (link.isLaunchCredential()) {
                    System.out.println("     Launch credential");
                }

                // Permission utilities
                if (link.allowsRotation()) {
                    System.out.println("     Allows rotation");
                }
                if (link.allowsConnections()) {
                    System.out.println("     Allows connections");
                }
                if (link.allowsPortForwards()) {
                    System.out.println("     Allows port forwards");
                }
                if (link.allowsSessionRecording()) {
                    System.out.println("     Allows session recording");
                }
                if (link.allowsTypescriptRecording()) {
                    System.out.println("     Allows typescript recording");
                }
                if (link.allowsRemoteBrowserIsolation()) {
                    System.out.println("     Allows remote browser isolation");
                }

                // Settings utilities
                if (link.rotatesOnTermination()) {
                    System.out.println("     Rotates on termination");
                }

                Integer version = link.getLinkDataVersion();
                if (version != null) {
                    System.out.println("     Data version: " + version);
                }

                if (link.hasReadableData()) {
                    System.out.println("     Has readable JSON data");
                } else if (link.getData() != null) {
                    System.out.println("     Has encrypted/binary data");
                } else {
                    System.out.println("     No data");
                }
            }
        }
    }
}

Full Method Reference

Method
Returns
Description

getRecordUid()

String

Target record UID

getPath()

String

Link metadata type

getData()

String

Raw Base64-encoded link data

isAdminUser()

boolean

User has admin privileges

isLaunchCredential()

boolean

This is a launch credential

allowsRotation()

boolean

Password rotation allowed

allowsConnections()

boolean

Connections allowed

allowsPortForwards()

boolean

Port forwarding allowed

allowsSessionRecording()

boolean

Session recording enabled

allowsTypescriptRecording()

boolean

Typescript recording enabled

allowsRemoteBrowserIsolation()

boolean

Remote browser isolation allowed

rotatesOnTermination()

boolean

Password rotates on session termination

getLinkDataVersion()

Integer

Data format version number

hasReadableData()

boolean

Data is readable JSON format

hasEncryptedData()

boolean

Data is encrypted

mightBeEncrypted()

boolean

Data might be encrypted (heuristic check)

getDecryptedData(byte[])

String

Decrypt data using record key

getDecodedData()

String

Base64 decode without decryption

getLinkData(byte[])

Map<String, Object>

Generic encrypted data access

getAiSettingsData(byte[])

Map<String, Object>

AI settings specific access

getJitSettingsData(byte[])

Map<String, Object>

JIT settings specific access

getSettingsForPath(String, byte[])

Map<String, Object>

Generic settings access by path

DAG Concepts for Infrastructure Management

Understanding Directed Acyclic Graphs

GraphSync implements a Directed Acyclic Graph structure where:

  • DIRECTED: Links have direction (A → B is different from B → A)

  • ACYCLIC: No circular references (A → B → C → A is NOT allowed)

  • GRAPH: Records (nodes) connected by links (edges)

Benefits:

  • ✅ Track dependencies ("this server needs this database")

  • ✅ Organize related credentials

  • ✅ Understand infrastructure relationships

  • ✅ Maintain security boundaries

Performance Optimization

Efficient Processing Strategies

public class OptimizedGraphOperations {

    // Strategy 1: Selective retrieval
    public void processSpecificRecords(List<String> recordUids, SecretsManagerOptions options) throws Exception {
        // Only get specific records with links to reduce bandwidth
        QueryOptions filtered = new QueryOptions(
            recordUids,  // Only these records
            Collections.emptyList(),
            true
        );

        KeeperSecrets secrets = SecretsManager.getSecrets2(options, filtered);
        // Process only what you need
    }

    // Strategy 2: Caching for multiple operations
    private Map<String, KeeperRecord> recordCache = new HashMap<>();
    private Map<String, List<KeeperRecord>> typeCache = new HashMap<>();

    public void initializeCache(SecretsManagerOptions options) throws Exception {
        QueryOptions queryOptions = new QueryOptions(null, null, true);
        KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

        // Build efficient lookup structures
        for (KeeperRecord record : secrets.getRecords()) {
            recordCache.put(record.getRecordUid(), record);
            typeCache.computeIfAbsent(record.getType(), k -> new ArrayList<>()).add(record);
        }
    }

    public List<KeeperRecord> getPamMachines() {
        return typeCache.getOrDefault("pamMachine", new ArrayList<>());
    }

    public KeeperRecord getRecord(String uid) {
        return recordCache.get(uid);
    }
}

Error Handling Best Practices

public void robustLinkProcessing(SecretsManagerOptions options) {
    try {
        QueryOptions queryOptions = new QueryOptions(null, null, true);
        KeeperSecrets secrets = SecretsManager.getSecrets2(options, queryOptions);

        for (KeeperRecord record : secrets.getRecords()) {
            try {
                List<KeeperRecordLink> links = record.getLinks();

                // Handle null links (requestLinks was false)
                if (links == null) {
                    System.err.println("Warning: Links not available for " + record.getTitle() +
                                     " - ensure requestLinks=true in QueryOptions");
                    continue;
                }

                // Process each link safely
                for (KeeperRecordLink link : links) {
                    try {
                        // Safely access encrypted data
                        if (link.hasEncryptedData()) {
                            Map<String, Object> data = link.getLinkData(record.getRecordKey());
                            if (data != null) {
                                // Successfully decrypted and processed
                                System.out.println("Processed encrypted data for " + link.getRecordUid());
                            } else {
                                System.out.println("Could not decrypt data for link to " + link.getRecordUid());
                            }
                        }

                        // Access link properties safely
                        boolean isAdmin = link.isAdminUser();
                        boolean allowsRotation = link.allowsRotation();
                        // ... other properties

                    } catch (Exception linkError) {
                        System.err.println("Error processing link to " + link.getRecordUid() + ": " + linkError.getMessage());
                    }
                }

            } catch (Exception recordError) {
                System.err.println("Error processing record " + record.getRecordUid() + ": " + recordError.getMessage());
            }
        }

    } catch (Exception e) {
        System.err.println("Failed to retrieve records with links: " + e.getMessage());
        e.printStackTrace();
    }
}

Important Implementation Notes

Critical Understanding

  • Links vs Files: The linksToRemove parameter in UpdateOptions removes FILES, not record links

  • Null vs Empty: Links field is null when requestLinks=false, empty list when requestLinks=true but no links exist

  • Performance Impact: Requesting links significantly increases response size and processing time

  • Encryption: Link data may be encrypted and requires the record's key to decrypt

Security Considerations

  • Key Management: Always use the source record's key for decrypting link data

  • Access Control: Link properties indicate what operations are permitted

  • Validation: Always check link properties before performing operations

Best Practices from Test Implementation

  1. Only request links when needed - Use requestLinks=true judiciously for performance

  2. Filter records when possible - Use recordsFilter to limit data retrieval

  3. Cache results - Build lookup maps for multiple operations on the same data

  4. Handle errors gracefully - Link data decryption and access may fail

  5. Validate assumptions - Check link properties match expected permissions

  6. Test configurations - Verify PAM setups have correct admin/launch credential counts

Kotlin Support

// Kotlin implementation with enhanced syntax
fun analyzeAdvancedGraphRelationships(options: SecretsManagerOptions) {
    val queryOptions = QueryOptions(
        recordsFilter = emptyList(),
        foldersFilter = emptyList(),
        requestLinks = true
    )
    
    val secrets = getSecrets2(options, queryOptions)
    
    secrets.records.forEach { record ->
        record.links?.forEach { link ->
            println("${record.title} → ${link.recordUid}")
            
            // Advanced property checking with Kotlin's concise syntax
            when {
                link.isAdminUser() -> println("   Admin privileges")
                link.isLaunchCredential() -> println("   Launch credential")
                link.allowsRotation() -> println("   Rotation allowed")
                link.allowsConnections() -> println("   Connections allowed")
                link.allowsSessionRecording() -> println("   Recording enabled")
            }
            
            // Settings data access with safe calls
            when (link.path) {
                "ai_settings" -> {
                    link.getAiSettingsData(record.recordKey)?.let { aiData ->
                        println("  AI: ${aiData["aiEnabled"]} - Model: ${aiData["aiModel"]}")
                    }
                }
                "jit_settings" -> {
                    link.getJitSettingsData(record.recordKey)?.let { jitData ->
                        println("  JIT: ${jitData["enabled"]} - TTL: ${jitData["ttl"]}s")
                    }
                }
            }
            
            // Generic encrypted data access
            link.getLinkData(record.recordKey)?.let { data ->
                data.forEach { (key, value) ->
                    println("  $key: $value")
                }
            }
        }
    }
}

JavaScript SDK

Detailed Javascript SDK docs for Keeper Secrets Manager

Download and Installation

Install with NPM

Source Code

Find the JavaScript source code in the

Using the SDK

Initialize Storage

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

In order to retrieve secrets, you must first initialize the local storage on your machine.

Example Usage

Retrieve Secrets

Response

Type: KeeperSecrets

Object containing all Keeper records, or records that match the given filter criteria

Example Usage

Retrieve all Secrets

Retrieve Secrets by Title

Parameter
Type
Required
Description

Example Usage

Retrieve Values From a Secret

Retrieve a Password

Field types are based on the Keeper . For a detailed list of available fields based on the Keeper Record Type, see the command in Keeper Commander.

Retrieve other Fields with Keeper Notation

See to learn about Keeper Notation format and capabilities

* The record UID in the notation query must be for a secret passed in the secrets parameter or nothing will be found by the query

Returns

Type: any

The value of the field at the location specified by the dot notation query if any, otherwise undefined.

Retrieve a TOTP Code

See to learn about Keeper Notation format and capabilities

* The record UID in the notation query must be for a secret passed in the secrets parameter or nothing will be found by the query

Returns

Type: any

The value of the field at the location specified by the dot notation query if any, otherwise undefined.

Update a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Returns

Type: Promise<void>

Generate a Random Password

Parameter
Type
Required
Default

Each parameter indicates the min number of a type of character to include. For example, 'uppercase' indicates the minimum number of uppercase letters to include.

Returns

Type: String

Download a File

Response

Type: Promise<Uint8Array

Bytes of file for download

Download a Thumbnail

Response

Type: Promise<Uint8Array>

Bytes of thumbnail for download

Upload a File

Upload File:

Parameter
Type
Required
Description

Creating the Keeper File Upload Object:

Parameter
Type
Required
Description

Example Usage

Create a Secret

Prerequisites:

  • Shared folder UID

    • Shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using

Parameter
Type
Required
Default
Parameter
Type
Required
Default

This example creates a login type record with a login value and a generated password.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

This example creates a record with a custom record type.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

Delete a Secret

The JavaScript KSM SDK can delete records in the Keeper Vault.

Parameter
Type
Required

Caching

To protect against losing access to your secrets when network access is lost, the JavaScript SDK allows caching of secrets to the local machine in an encrypted file.

Add queryFunction: cachingPostFunction to SecretManagerOptions

Example usage:

Folders

Folders have full CRUD support - create, read, update and delete operations.

Read Folders

Downloads full folder hierarchy.

Response

Type: KeeperFolder[]

Example Usage

Create a Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required - UID of a shared folder, while sub-folder UID is optional and if missing new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

Parameter
Type
Required
Description

Example Usage

Update a Folder

Updates the folder metadata - currently folder name only.

Parameter
Type
Required
Description

Example Usage

Delete Folders

Removes a list of folders. Use forceDeletion flag to remove non-empty folders.

When using forceDeletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

Parameter
Type
Required
Default
Description

Example Usage

Proxy Support

In order to use proxy, you need to install and set a proxy agent using setCustomProxyAgent from @keeper-security/secrets-manager-core

Example Usage

setCustomProxyAgent works only in NodeJs environment and is not supported in browser.

npm install @keeper-security/secrets-manager-core
initializeStorage(storage: KeyValueStorage, clientKey: String? = null, hostName: String? = null)

Parameter

Type

Required

Default

Description

storage

KeyValueStorage

Yes

storage location

clientKey

string

Optional

null

token for connecting with Keeper Secrets Manager

hostName

string

Optional

null

server location to get secrets. If nothing is passed, will use keepersecurity.com (US)

const { getSecrets, initializeStorage, localConfigStorage } = require('@keeper-security/secrets-manager-core')

const getKeeperRecords = async () => {

    // oneTimeToken is used only once to initialize the storage
    // after the first run, subsequent calls will use ksm-config.txt
    const oneTimeToken = "<One Time Access Token>";
    
    const storage = localConfigStorage("ksm-config.json")
    
    await initializeStorage(storage, oneTimeToken)
    // Using token only to generate a config (for later usage)
    // requires at least one access operation to bind the token
    //await getSecrets({storage: storage})
    
    const {records} = await getSecrets({storage: storage})
    console.log(records)

    const firstRecord = records[0]
    const firstRecordPassword = firstRecord.data.fields.find(x => x.type === 'password')
    console.log(firstRecordPassword.value[0])
}

getKeeperRecords().finally()
getSecrets(options: SecretsManagerOptions, recordsFilter: List<String> = emptyList()): KeeperSecrets

Parameter

Type

Required

Default

Description

storage

KeyValueStorage

Yes

Storage location

recordsFilter

string[]

Optional

Empty List

Record UIDs to get

const storage = inMemoryStorage() // see initialization example
val secrets = getSecrets(storage)
// get all matching records
getSecretsByTitle = async (options: SecretManagerOptions, recordTitle: string): Promise<KeeperRecord[]>

// get only the first matching record
getSecretByTitle = async (options: SecretManagerOptions, recordTitle: string): Promise<KeeperRecord>

options

SecretsManagerOptions

Yes

Preconfigured options

recordTitle

string

Yes

Record title to search for

const {
    getSecretByTitle,
    localConfigStorage,
} = require('@keeper-security/secrets-manager-core')

const getKeeperRecord = async () => {
    const options = { storage: localConfigStorage("ksm-config.json") }
    const myCredential = await getSecretByTitle(options, "My Credential")
}

getKeeperRecord().finally()
secret.data.fields.find(x => x.type === 'password')
const { getSecrets, initializeStorage, localConfigStorage } = require('@keeper-security/secrets-manager-core')

const getKeeperRecords = async () => {
    const storage = localConfigStorage("ksm-config.json")
    // get records
    const {records} = await getSecrets({storage: storage})
    // get password from first record
    const firstRecord = records[0]
    const firstRecordPassword = firstRecord.data.fields.find(x => x.type === 'password')
}
getValue(secrets: KeeperSecrets, query: string): any
const {
    getSecrets,
    localConfigStorage,
    getValue
} = require('@keeper-security/secrets-manager-core')

const getKeeperRecords = async () => {
    const options = { storage: localConfigStorage("ksm-config.json") }
    
    // get secrets
    const secrets = await getSecrets(options)

    // get login with dot notation
    const loginValue = getValue(secrets, 'RECORD_UID/field/login')
}

Parameter

Type

Required

Default

Description

secrets

KeeperSecrets

Yes

Secrets to query

query

string

Yes

Keeper Notation query

getTotpCode(url: string): string
const { 
    getSecrets, 
    localConfigStorage, 
    getTotpCode, 
    getValue} = require('@keeper-security/secrets-manager-core')

const getKeeperRecords = async () => {
    const options = { storage: localConfigStorage("ksm-config.json") }

    // get secrets
    const secrets = await getSecrets(options)

    // get login with dot notation
    const totpUri = getValue(secrets,'RECORD_UID/field/oneTimeCode')

    //get TOTP code
    const totp = await getTotpCode(totpUri)
}

Parameter

Type

Required

Default

Description

url

string

Yes

TOTP Url

updateSecret(options, record)
const { 
    getSecrets, 
    localConfigStorage, 
    updateSecret} = require('@keeper-security/secrets-manager-core')

const storage = localConfigStorage("ksm-config.json")

// get records
const {records} = await getSecrets({storage: storage})

// get the first record
const recordToUpdate = records[0]

// set new record title and notes
recordToUpdate.data.title = 'New Title'
recordToUpdate.data.notes = "New Notes"

// save record changes
await updateSecret(options, recordToUpdate)
const { 
    getSecrets, 
    localConfigStorage, 
    updateSecret,
    completeTransaction,
    UpdateTransactionType,
    SecretManagerOptions
} = require('@keeper-security/secrets-manager-core')

// get records
const options = { storage: localConfigStorage("ksm-config.json") }
const {records} = await getSecrets(options)

// rotate password on the first record
const secret = records[0]
const password = secret.data.fields.find(x => x.type === "password")
password.value[0] = "MyNewPassword"

//start a transaction to update record in vault
await updateSecret(options, secret, UpdateTransactionType.Rotation)

// rotate password on remote host
const success = rotateRemoteSshPassword("MyNewPassword");

// complete the transaction - commit or rollback
const rollback = !success
await completeTransaction(options, secret.recordUid, rollback)

Parameter

Type

Required

Default

Description

options

SecretManagerOptions

Yes

record

KeeperRecord

Yes

generatePassword(length, lowercase, uppercase, digits, specialCharacters)
const { 
    getSecrets, 
    localConfigStorage, 
    updateSecret, 
    generatePassword } = require('@keeper-security/secrets-manager-core')

// generate a random password
let newRandomPwd = await generatePassword()

const storage = localConfigStorage("ksm-config.json")
const {records} = await getSecrets({storage: storage})

// get the first record
const recordToUpdate = records[0]

// Find the field with the type "password"
const recordToUpdatePasswordField = recordToUpdate.data.fields.find(x => x.type === 'password')

// set new value to the password field
recordToUpdatePasswordField.value[0] = newRandomPwd

await updateSecret({storage: storage}, recordToUpdate)

length

int

Optional

64

lowercase

int

Optional

0

uppercase

int

Optional

0

digits

int

Optional

0

specialCharacters

int

Optional

0

downloadFile(file: KeeperFile): ByteArray

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File to download

downloadThumbnail(file: KeeperFile): ByteArray

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File with thumbnail to download

uploadFile = async (options: SecretManagerOptions, ownerRecord: KeeperRecord, file: KeeperFileUpload): Promise<string>

options

SecretsManagerOptions

Yes

Storage and query configuration

ownerRecord

KeeperRecord

Yes

The record to attach the uploaded file to

file

KeeperFileUpload

Yes

The File to upload

type KeeperFileUpload = {
    name: string
    title: string
    type?: string
    data: Uint8Array
}

name

string

Yes

What the name of the file will be in Keeper once uploaded

title

string

Yes

What the title of the file will be in Keeper once uploaded

type

string

Optional

The mime type of data in the file. 'application/octet-stream' will be used if nothing is given

data

Uint8Array

Yes

File data as bytes

// get record to attach file to
const {records} = await getSecrets({storage: storage}, ['XXX'])
const ownerRecord = records[0]

// get file data to upload
const fileData = fs.readFileSync('./assets/my-file.json')

// upload file to selected record
await uploadFile(options, ownerRecord, {
    name: 'my-file.json',
    title: 'Sample File',
    type: 'application/json',
    data: fileData
})
createSecret(options, folderUid, record)

options

SecretManagerOptions

Yes

folderUid

string

Yes

record

JSON Object

Yes

createSecret2(options, createOptions, record)

options

SecretManagerOptions

Yes

createOptions

CreateOptions

Yes

record

JSON Object

Yes

let newRec = {
    "title": "Sample KSM Record: JavaScript",
    "type": "login",
    "fields": [
        { "type": "login",    "value": [ "[email protected]" ] },
        { "type": "password", "value": [ await generatePassword() ] }
    ],
    "notes": "This is a JavaScript record creation example"
}

let recordUid = await createSecret(options, folderUid, newRec)
let newRec = {
    "title": "Sample Custom Type KSM Record: JavaScript",
    "type": "Custom Login",
    "fields": [
        {
            "type": "host",
            "label": "My Custom Host lbl",
            "value": [ {"hostName": "127.0.0.1", "port": "8080"} ],
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "login",
            "label": "My Custom Login lbl",
            "value": [ "[email protected]" ],
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "password",
            "label": "My Custom Password lbl",
            "value": [ await generatePassword() ],
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "url",
            "label": "My Login Page",
            "value": [ "http://localhost:8080/login" ],
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "securityQuestion",
            "label": "My Question 1",
            "value": [ {
                "question": "What is one plus one (write just a number)",
                "answer": "2"
            } ],
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "phone",
            "value": [{
                "region": "US",
                "number": "510-444-3333",
                "ext": "2345",
                "type": "Mobile"
            }],
            "label": "My Phone Number"
        },
        {
            "type": "date",
            "value": [ 1641934793000 ],
            "label": "My Date Lbl",
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "name",
            "value": [{
                "first": "John",
                "middle": "Patrick",
                "last": "Smith"
            }],
            "label": "My Custom Name lbl",
            "required": true,
            "privacyScreen": false
        },
        {
            "type": "oneTimeCode",
            "label": "My TOTP",
            "value": ["otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"],
            "required": true,
            "privacyScreen": false
        }
    ],
    "custom": [
        {
            "type": "phone",
            "value": [{
                "region": "US",
                "number": "(510) 123-3456"
            }],
            "label": "My Custom Phone Lbl 1"
        },
        {
            "type": "phone",
            "value": [ {
                "region": "US",
                "number": "510-111-3333",
                "ext": "45674",
                "type": "Mobile" } ],
            "label": "My Custom Phone Lbl 2"
        }
    ],
    "notes": "\tThis custom type record was created\n\tvia KSM Katacoda JavaScript Example"
}

let recordUid = await createSecret(options, "[FOLDER UID]", newRec)
deleteSecret(smOptions, recordUids);

smOptions

SecretManagerOptions

Yes

recordUids

string[]

Yes

// setup secrets manager
const smOptions = { storage: localConfigStorage("ksm-config.json") 

// delete a specific secret by record UID
await deleteSecret(smOptions, ["EG6KdJaaLG7esRZbMnfbFA"]);
const options: SecretManagerOptions = {    
    storage: kvs,
    queryFunction: cachingPostFunction // Import `cachingPostFunction`
}
getFolders = async (options: SecretManagerOptions): Promise<KeeperFolder[]>
const storage = localConfigStorage("ksm-config.json")
const folders = await getFolders({storage: storage})
createFolder = async (options: SecretManagerOptions, createOptions: CreateOptions, folderName: string): Promise<string>

options

SecretsManagerOptions

Yes

Preconfigured options

createOptions

CreateOptions

Yes

The parent and sub-folder UIDs

folderName

string

Yes

The Folder name

type CreateOptions = {
    folderUid: string
    subFolderUid?: string
}
const storage = localConfigStorage("ksm-config.json")
const folderUid = await createFolder({storage: storage}, {folderUid: "[PARENT_SHARED_FOLDER_UID]"}, "new_folder")
updateFolder = async (options: SecretManagerOptions, folderUid: string, folderName: string): Promise<void>

options

SecretsManagerOptions

Yes

Preconfigured options

folderUid

string

Yes

The folder UID

folderName

string

Yes

The new folder name

const storage = localConfigStorage("ksm-config.json")
await updateFolder({storage: storage}, "[FOLDER_UID]", "new_folder_name")
deleteFolder = async (options: SecretManagerOptions, folderUids: string[], forceDeletion?: boolean): Promise<SecretsManagerDeleteResponse>

options

SecretsManagerOptions

Yes

Preconfigured options

folderUids

string[]

Yes

The folder UID list

forceDeletion

bool

No

false

Force deletion of non-empty folders

const storage = localConfigStorage("ksm-config.json")
await deleteFolder({storage: storage}, ["[FOLDER_UID1]", "[FOLDER_UID2]"], true)
const {
    getSecrets,
    initializeStorage,
    localConfigStorage,
    setCustomProxyAgent
} = require('@keeper-security/secrets-manager-core')
const { HttpsProxyAgent } = require('https-proxy-agent')

const getKeeperRecords = async () => {
    // Set you proxy URL
    setCustomProxyAgent(new HttpsProxyAgent('http://user:[email protected]:3128'))

    const storage = localConfigStorage("config.json")
    
    await initializeStorage(storage, 'US:EXAMPLE_ONE_TIME_TOKEN', 'keepersecurity.com')
    const {records} = await getSecrets({storage: storage})

    console.log(records)
}
GitHub repository
record-type-info
Keeper Notation documentation
Keeper Notation documentation
uploadFile

Go SDK

Detailed Go SDK docs for Keeper Secrets Manager

Download and Installation

Install from GitHub

Find the latest Go SDK release at: https://github.com/Keeper-Security/secrets-manager-go

$ go get github.com/keeper-security/secrets-manager-go/core

Source Code

Find the Go source code in the GitHub repository

Using the SDK

Initialize

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

In order to retrieve secrets, you must first initialize the secrets manager client.

package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	// Using token only to generate a config (for later usage)
	// requires at least one access operation to bind the token
	//sm.GetSecrets([]string{})
}

Parameter

Type

Required

Default

Description

token

string

Yes

Keeper Secrets Manager One time token

hostName

string

Yes

Server to connect to

verifySslCerts

bool

yes

Choose whether to verify SSL certificates or not

config

IKeyValueStorage

yes

File Storage Configuration

The NewSecretsManager function will initialize Secrets Manager from provided parameters and store settings from ClientOptions struct.

secretsManager := NewSecretsManager(options)

Retrieve Secrets

records, err := sm.GetSecrets([]string{})

Parameter

Type

Required

Default

Description

uids

[]string

Yes

Empty slice

Record UIDs to get

Response

Type: []*Record

Records with the specified UIDs, or all records shared with the Secrets Manager client if no UIDs are provided

Example Usage

Retrieve all Secrets

package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	allRecords, err := sm.GetSecrets([]string{})
}

Retrieve Secrets with a Filter

package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	records, err := sm.GetSecrets([]string{"[Secret UID]"})
}

Retrieve Secrets by Title

// get all matching records
GetSecretsByTitle(recordTitle string) (records []*Record, err error)

// get only the first matching record
GetSecretByTitle(recordTitle string) (records *Record, err error)
Parameter
Type
Required
Description

recordTitle

string

Yes

Record title to search for

Example Usage

package main

// Import Secrets Manager
import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {

	options := &ksm.ClientOptions{
		// One time tokens can be used only once - afterwards use the generated config file
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}

	sm := ksm.NewSecretsManager(options)

	// Retrieve the first matching record by title
	aRecord, _ := ksm.GetSecretByTitle("My Credentials")

	// Retrieve all matching records by title
	allRecords, _ := ksm.GetSecretsByTitle("My Credentials")
	for _, record := range allRecords {
		println("UID", record.Uid, ", title [", record.Title(), "]")
	}
}

Get Values From a Secret

Get a Password

secret.GetFieldsByType("password")
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	
	// Get all records
	allRecords, err := sm.GetSecrets([]string{})
	if err != nil {
		println("Error retrieving all records: ", err.Error())
		os.Exit(1)
	}

	// Get first record
	firstRecord := allRecords[0]

	// Get first field in a record of type password
	passwordField := map[string]interface{}{}
	if passwordFields := firstRecord.GetFieldsByType("password"); len(passwordFields) > 0 {
		passwordField = passwordFields[0]
	}

Field types are based on the Keeper . For a detailed list of available fields based on the Keeper Record Type, see the record-type-info command in Keeper Commander.

Retrieve Values using Keeper Notation

sm.GetNotation(query)
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)

	// Get password from record with the given UID
	value, err := sm.GetNotation("[Record UID]/field/password")
	if err == nil && len(value) > 0 {
		if password, ok := value[0].(string); ok {
			println("Successfully retrieved field value using notation")
		}
	}

See Keeper Notation documentation to learn about Keeper Notation format and capabilities

Parameter

Type

Required

Default

Description

query

String

Yes

Keeper Notation query for getting a value from a specified field

Returns

Type: []interface{}

The value of the queried field

Retrieve TOTP Code

GetTotpCode(url)
clientOptions := &ksm.ClientOptions{
	Token:  "[One Time Access Token]",
	Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(clientOptions)

// Get all records
allRecords, err := sm.GetSecrets([]string{})
if err == nil {
	// Get TOTP url from record
	urls, err := sm.GetNotation("[Record UID]/field/OneTimeCode")
	if err == nil && len(urls) == 1 {
		// Get TOTP code from url
		url := urls[0].(string)
		totp, err := ksm.GetTotpCode(url)
		if err == nil {
			println(totp.Code, totp.TimeLeft)
		}
	}
}

Parameter

Type

Required

Default

Description

url

string

Yes

TOTP Url

Update a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Update Password

(r *Record) SetPassword(password string) 

Parameter

Type

Required

Default

Description

password

string

Yes

New password to set to the record

Update Other Fields

(r *Record) SetFieldValueSingle(field string, value string) 

Parameter

Type

Required

Default

Description

field

string

Yes

name of the field to update

value

string

Yes

Value to set the field to

Update Secret in Vault

Save the record to make the changes made appear in the

(c *secretsManager) Save(record *Record) (err error) 

Parameter

Type

Required

Default

Description

record

KeeperRecord

Yes

Record with updated field to save changes for

Example Usage

Update Password

package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	records, err := sm.GetSecrets([]string{"[Record UID]"})

	// get record to update
	record := records[0]

	// set new password
	record.SetPassword("NewPassword123$")

	// save changes
	ksm.Save(record)

	// Transactional updates
	// rotate password on the record
	record.SetPassword("NewPassword1234$")
	// start a transaction
	ksm.SaveBeginTransaction(secret, ksm.TransactionTypeRotation)
	// rotate password on remote host
	success := rotateRemoteSshPassword("NewPassword1234$")
	// complete the transaction - commit or rollback
	ksm.CompleteTransaction(secret.Uid, !success)
}

Update other fields

package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	records, err := sm.GetSecrets([]string{"[Record UID]"})

	// get record to update
	record := records[0]

	// set login field to a new value
	record.SetFieldValueSingle("login", "New Login Value")
	
	// update title and notes
	record.SetTitle("New Title")
	record.SetNotes("New Notes")

	// save changes
	sm.Save(record)
}

Each record field type is represented by a class. Cast the field to the corresponding class in order to correctly access the field's value. Check the documentation for a list of field types.

Generate a Random Password

GeneratePassword(length, lowercase, uppercase, digits, specialCharaters)
// get a record
allRecords, err := sm.GetSecrets([]string{})
record := allRecords[0]
// generate a random password
password := GeneratePassword(64, 0,0,0,0)
// updaterecord with new password
record.SetPassword(password)
Parameter
Type
Required
Default

length

int

Yes

lowercase

int

Yes

uppercase

int

Yes

digits

int

Yes

specialCharacters

int

Yes

Each parameter indicates the minimum number of a type of character to include. For example, uppercase indicates the minimum uppercase letters to include.

Download a File

(r *Record) DownloadFileByTitle(title string, path string) bool

Parameter

Type

Required

Default

Description

title

string

Yes

Name of file to download

path

string

Yes

Path to save the file to

Response

Type: bool

Did the file save succeed

Example Usage

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)
clientOptions := &ksm.ClientOptions{
	Token:  "[One Time Access Token]",
	Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(clientOptions)

// get record to update
record, err := sm.GetSecrets([]string{"[Record UID]"})

// download a file attached to the record
record.DownloadFileByTitle("certs.txt","secret_files/certs.txt")

Upload a File

UploadFile(record *Record, file *KeeperFileUpload) (uid string, err error)
Parameter
Type
Required
Description

ownerRecord

Record

Yes

The record to attach the uploaded file to

file

KeeperFileUpload

Yes

The File to upload

type KeeperFileUpload struct {
	Name  string
	Title string
	Type  string
	Data  []byte
}
Parameter
Type
Required
Description

name

string

Yes

What the name of the file will be in Keeper once uploaded

title

string

Yes

What the title of the file will be in Keeper once uploaded

type

string

Yes

The mime type of data in the file. 'application/octet-stream' for example

data

[]byte

Yes

File data as bytes

Example Usage

package main

// Import Secrets Manager
import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {

	options := &ksm.ClientOptions{
		// One time tokens can be used only once - afterwards use the generated config file
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}

	sm := ksm.NewSecretsManager(options)

	// Get a record to upload the file to
	allRecords, _ := sm.GetSecrets([]string{"[Record UID]"})
	ownerRecord := allRecords[0]
	
	// get file data and prepare for upload
	dat, err := ioutil.ReadFile("/myFile.json")
	var myFile := KeeperFileUpload{
		Name: "myFile.json",
		Title: "My File",
		Type: "application/json",
		Data: dat
	}
	
	// upload file to selected record
	sm.UploadFile(ownerRecord, myFile)
}

Create a Secret

Prerequisites:

  • Shared folder UID

    • Shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using UploadFile

secretsManager.CreateSecretWithRecordData(recordUid, folderUid, record)
Parameter
Type
Required
Default

recordUid

string

No

auto generated random UID

folderUid

string

Yes

record

*RecordCreate

Yes

secretsManager.CreateSecretWithRecordDataAndOptions(createOptions, recordData, folders)
Parameter
Type
Required
Default

createOptions

CreateOptions

Yes

recordData

*RecordCreate

Yes

folders

[]*KeeperFolder

No

This example creates a login type record with a login value and a generated password.

Replace [FOLDER UID] in the example with the UID of a shared folder that your Secrets Manager has access to.

// create a new login record
newLoginRecord := NewRecordCreate("login", "Sample KSM Record: Go SDK")
// fill in login and password fields
password, _ := GeneratePassword(32,0,0,0,0)
newLoginRecord.Fields = append(newLoginRecord.Fields,
    NewLogin("[email protected]"),
    NewPassword(password))
// fill in notes
newLoginRecord.Notes = "This is a Go record creation example"
// create the new record 
recordUid, err := secretsManager.CreateSecretWithRecordData("", "[FOLDER UID]", newLoginRecord)

Replace [FOLDER UID] in the example with the UID of a shared folder that your Secrets Manager has access to.

This example creates a record with a custom record type.

customLogin := ksm.NewRecordCreate("Custom Login", "Sample Custom Type KSM Record: Go SDK")
password, _ := ksm.GeneratePassword(32, 0, 0, 0, 0)
customLogin.Fields = append(customLogin.Fields,
	ksm.NewHosts(ksm.Host{Hostname: "127.0.0.1", Port: "8080"}),
	ksm.NewLogin("[email protected]"),
	ksm.NewPassword(password),
	ksm.NewUrl("http://localhost:8080/login"),
	ksm.NewSecurityQuestions(ksm.SecurityQuestion{Question: "What is one plus one (write just a number)", Answer: "2"}),
	ksm.NewPhones(ksm.Phone{Region: "US", Number: "510-444-3333", Ext: "2345", Type: "Mobile"}),
	ksm.NewDate(1641934793000),
	ksm.NewNames(ksm.Name{First: "John", Middle: "Patrick", Last: "Smith"}),
	ksm.NewOneTimeCode("otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"),
)
customLogin.Custom = append(customLogin.Custom,
	ksm.NewPhones(ksm.Phone{Region: "US", Number: "510-222-5555", Ext: "99887", Type: "Mobile"}),
	ksm.NewPhones(ksm.Phone{Region: "US", Number: "510-111-3333", Ext: "45674", Type: "Mobile"}),
)
customLogin.Notes = "\tThis custom type record was created\n\tvia Go SDK copied from https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/golang-sdk"
recordUid, err := sm.CreateSecretWithRecordData("", "[FOLDER UID]", customLogin)

Delete a Secret

The Go KSM SDK can delete records in the Keeper Vault.

secretsManager.DeleteSecrets(recordUids)

Parameter
Type
Required

recordUids

[]string

Yes

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	// setup secrets manager
	options := &ksm.ClientOptions{
		// Token:  "<One Time Access Token>",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	secretsManager := ksm.NewSecretsManager(options)
	
	// delete a specific secret by record UID
	secrets, err = secretsManager.DeleteSecrets([]string{"EG6KdJaaLG7esRZbMnfbFA"})
}

Caching

To protect against losing access to your secrets when network access is lost, the Go SDK allows caching of secrets to the local machine in an encrypted file.

Setup and Configure Cache

In order to setup caching in the Go SDK, use the function SetCache(cache ICache) to set the cache to either one of the built-in memory or file based caches or use your own implementation.

type ICache interface {
	SaveCachedValue(data []byte) error
	GetCachedValue() ([]byte, error)
	Purge() error
}

The Go SDK includes a memory based cache and a file based cache for convenience.

options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(options)

// Memory based cache
memCache := ksm.NewMemoryCache()
sm.SetCache(memCache)

// File based cache
fileCache := ksm.NewFileCache("ksm_cache.bin")
sm.SetCache(fileCache)

Folders

Folders have full CRUD support - create, read, update and delete operations.

Read Folders

Downloads full folder hierarchy.

GetFolders() ([]*KeeperFolder, error)

Response

Type: []*KeeperFolder, error

Example Usage

package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)
	folders, err := sm.GetFolders()
}

Create a Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required - UID of a shared folder, while sub-folder UID is optional and if missing new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

CreateFolder(createOptions CreateOptions, folderName string, folders []*KeeperFolder) (folderUid string, err error)
Parameter
Type
Required
Description

createOptions

CreateOptions

Yes

The parent and sub-folder UIDs

folderName

string

Yes

The Folder name

folders

[]*KeeperFolder

No

List of folders to use in the search for parent and sub-folder from CreateOptions

type CreateOptions struct {
	FolderUid    string
	SubFolderUid string
}
type KeeperFolder struct {
	FolderKey []byte
	FolderUid string
	ParentUid string
	Name      string
}

Example Usage

package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)

	co := ksm.CreateOptions{FolderUid: "[PARENT_SHARED_FOLDER_UID]", SubFolderUid: ""}
	uid, err := sm.CreateFolder(co, "new_folder", nil)
}

Update a Folder

Updates the folder metadata - currently folder name only.

UpdateFolder(folderUid, folderName string, folders []*KeeperFolder) (err error)
Parameter
Type
Required
Description

folderUid

string

Yes

The folder UID

folderName

string

Yes

The new folder name

folders

[]*KeeperFolder

No

List of folders to use in the search for parent folder

Example Usage

package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)

	err := sm.UpdateFolder("[FOLDER_UID]", "new_folder_name", nil)
}

Delete Folders

Removes a list of folders. Use forceDeletion flag to remove non-empty folders.

When using forceDeletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

DeleteFolder(folderUids []string, forceDeletion bool) (statuses map[string]string, err error)
Parameter
Type
Required
Description

folderUids

[]string

Yes

The folder UID list

forceDeletion

bool

Yes

Force deletion of non-empty folders

Example Usage

package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)

	stats, err := sm.DeleteFolder([]string{"[FOLDER_UID1]", "[FOLDER_UID2]"}, true)
}

Ruby SDK

Detailed Ruby SDK docs for Keeper Secrets Manager

Download and Installation

Installation

The Ruby SDK supports Ruby version 3.1 and above. For more information, see:

https://rubygems.org/gems/keeper_secrets_manager

Install with gem:

gem install keeper_secrets_manager -v 17.1.0

Or add to your Gemfile:

gem 'keeper_secrets_manager', '~> 17.1'

Then run:

bundle install

Source Code

Find the Ruby source code in the GitHub repository

Using the SDK

Initialize Storage

The Keeper Secrets Manager SDK requires a One-Time Access Token to initialize storage on a client device. After initialization, the SDK stores the configuration for future use.

KeeperSecretsManager.new(token: token, config: storage, hostname: hostname, verify_ssl_certs: verify_ssl_certs)
Parameter
Type
Required
Default
Description

token

String

Optional

nil

One-Time Access Token for initial binding

config

KeyValueStorage

Yes

-

Storage implementation for configuration persistence

hostname

String

Optional

'keepersecurity.com'

API hostname (e.g., 'keepersecurity.eu' for EU datacenter)

verify_ssl_certs

Boolean

Optional

true

Enable/disable SSL certificate verification

Note: Using a One-Time Access Token requires at least one read operation to bind the token and fully populate the configuration.

Example Usage

Using a One-Time Access Token:

require 'keeper_secrets_manager'

token = "US:ONE_TIME_TOKEN_HERE"

# First time setup - bind the token
storage = KeeperSecretsManager::Storage::FileStorage.new('keeper_config.json')
secrets_manager = KeeperSecretsManager.new(token: token, config: storage)

# Complete the binding (requires at least one operation)
records = secrets_manager.get_secrets

# Verify config was saved
File.exist?('keeper_config.json')  # Should return true

Using File-Based Storage

For persistent configuration across application restarts:

require 'keeper_secrets_manager'

# After first time binding, load from file
secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

Alternatively connect with the base64 configuration file generated by your vault:

require 'keeper_secrets_manager'

base64_config = File.read('config.base64').strip
storage = KeeperSecretsManager::Storage::InMemoryStorage.new(base64_config)
secrets_manager = KeeperSecretsManager.new(config: storage)

Using Environment Variables

For read-only configuration from environment:

require 'keeper_secrets_manager'

# Set environment variables:
# export KSM_HOSTNAME=keepersecurity.com
# export KSM_CLIENT_ID=your-client-id
# export KSM_PRIVATE_KEY=your-private-key
# export KSM_APP_KEY=your-app-key
# export KSM_SERVER_PUBLIC_KEY_ID=10

# Load from environment
config = KeeperSecretsManager::Storage::EnvironmentStorage.new('KSM_')
secrets_manager = KeeperSecretsManager.new(config: config)

Retrieve Secrets

Get Secrets

get_secrets(uids = [])
Parameter
Type
Required
Default
Description

uids

Array<String>

Optional

[]

Record UIDs to retrieve. Empty array retrieves all secrets.

Response:

Type: Array<KeeperRecord>

Array containing all Keeper records, or records that match the given UID filter.

Example Usage

Retrieve All Secrets:

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Retrieve all secrets
records = secrets_manager.get_secrets

records.each do |record|
  puts "#{record.title} (#{record.type})"
end

Retrieve Secrets by UID:

# Get single secret by UID
records = secrets_manager.get_secrets(['RECORD_UID'])
record = records.first

# Get multiple secrets by UIDs
uids = ['UID1', 'UID2', 'UID3']
records = secrets_manager.get_secrets(uids)

Get Secrets by Title

# Get all secrets matching title
get_secrets_by_title(title)

# Get first secret matching title
get_secret_by_title(title)
Parameter
Type
Required
Default
Description

title

String

Yes

-

Record title to search for (exact match)

Response:

Type: Array<KeeperRecord> (for get_secrets_by_title) or KeeperRecord (for get_secret_by_title)

Returns all records matching the title, or the first matching record.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get secret by exact title match
record = secrets_manager.get_secret_by_title('My Database Credentials')

# Get multiple secrets with same title
records = secrets_manager.get_secrets_by_title('My Login')

# Access fields from the record
puts "Login: #{record.login}"
puts "Password: #{record.password}"

Retrieve Values From a Secret

Once a secret is retrieved, individual fields can be accessed using multiple approaches:

Using Dynamic Field Access

record = secrets_manager.get_secrets(['RECORD_UID']).first

# Access standard fields dynamically
login = record.login
password = record.password
url = record.url

# Access complex fields
host = record.host  # Returns hash with hostName and port

Using Explicit Field Methods

# Get single field value (returns first value)
login = record.get_field_value_single('login')

# Get all values for a field (returns array)
passwords = record.get_field_value('password')

# Access custom fields by label
api_key = record.get_field_value_single('API Key')
environment = record.get_field_value_single('Environment')

Using Keeper Notation

# Access fields using URI-style notation
password = secrets_manager.get_notation("keeper://#{record.uid}/field/password")

# Access by record title
url = secrets_manager.get_notation("keeper://My Login/field/url")

# Access complex field properties
hostname = secrets_manager.get_notation("keeper://#{record.uid}/field/host[hostName]")
port = secrets_manager.get_notation("keeper://#{record.uid}/field/host[port]")

# Access custom fields
env = secrets_manager.get_notation("keeper://#{record.uid}/custom_field/Environment")

Retrieve a TOTP Code

To generate a TOTP code, retrieve the TOTP URL from the record and use the KeeperSecretsManager::TOTP module.

# Get TOTP URL from record
totp_url = record.get_field_value_single('oneTimeCode')

# Parse and generate code
require 'keeper_secrets_manager/totp'
totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)
totp_code = KeeperSecretsManager::TOTP.generate_code(
  totp_params['secret'],
  algorithm: totp_params['algorithm'],
  digits: totp_params['digits'],
  period: totp_params['period']
)
Parameter
Type
Required
Default
Description

secret

String

Yes

-

Base32-encoded TOTP secret

algorithm

String

Optional

'SHA1'

Hash algorithm (SHA1, SHA256, SHA512)

digits

Integer

Optional

6

Number of digits in the code

period

Integer

Optional

30

Time period in seconds

Response:

Type: String

Returns the current Time-Based One-Time Password (TOTP) code for two-factor authentication.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get record with TOTP
record = secrets_manager.get_secrets(['RECORD_UID']).first

# Get TOTP URL from record
totp_url = record.get_field_value_single('oneTimeCode')

# Parse TOTP parameters
require 'keeper_secrets_manager/totp'
totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)

# Generate TOTP code
totp_code = KeeperSecretsManager::TOTP.generate_code(
  totp_params['secret'],
  algorithm: totp_params['algorithm'],
  digits: totp_params['digits'],
  period: totp_params['period']
)

puts "Current TOTP code: #{totp_code}"
puts "Expires in: #{30 - (Time.now.to_i % 30)} seconds"

Note: TOTP generation requires the base32 gem for decoding the secret. Install with gem install base32.

Generate a Random Password

Generate cryptographically secure random passwords with customizable character requirements. This utility function is useful when creating or updating secrets programmatically.

KeeperSecretsManager::Utils.generate_password(
  length: 64,
  lowercase: 0,
  uppercase: 0,
  digits: 0,
  special_characters: 0
)
Parameter
Type
Required
Default
Description

length

Integer

Optional

64

Total password length

lowercase

Integer

Optional

0

Minimum number of lowercase letters (a-z)

uppercase

Integer

Optional

0

Minimum number of uppercase letters (A-Z)

digits

Integer

Optional

0

Minimum number of digit characters (0-9)

special_characters

Integer

Optional

0

Minimum number of special characters (!@#$%^&*()_+-=[]{}

Response:

Type: String

Returns a cryptographically secure random password meeting the specified requirements.

Note: This function uses Ruby's SecureRandom for cryptographic-strength randomness and applies Fisher-Yates shuffle to ensure proper character distribution.

Example Usage

Generate a default 64-character password:

require 'keeper_secrets_manager'

# Generate with all defaults (64 random characters)
password = KeeperSecretsManager::Utils.generate_password
puts "Generated: #{password}"
# => "Xk9$mP2..."  (64 characters)

Generate password with specific requirements:

# Generate 32-character password with specific minimums
password = KeeperSecretsManager::Utils.generate_password(
  length: 32,
  lowercase: 2,
  uppercase: 2,
  digits: 2,
  special_characters: 2
)

puts "Generated: #{password}"
# => "aB12$xY34..."  (32 chars with at least 2 of each type)

# Generate strong password with mixed requirements
password = KeeperSecretsManager::Utils.generate_password(
  length: 20,
  lowercase: 3,
  uppercase: 3,
  digits: 3,
  special_characters: 3
)

Use when creating a new secret:

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Create a new login record with generated password
record_data = {
  type: 'login',
  title: 'Production Database',
  fields: [
    { type: 'login', value: ['db_admin'] },
    {
      type: 'password',
      value: [KeeperSecretsManager::Utils.generate_password(
        length: 32,
        lowercase: 4,
        uppercase: 4,
        digits: 4,
        special_characters: 4
      )]
    },
    { type: 'url', value: ['https://db.example.com'] }
  ],
  notes: 'Auto-generated secure password'
}

# Create options with required folder_uid
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)

puts "Created record with secure password: #{record_uid}"

Use when updating an existing secret:

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get existing record
record = secrets_manager.get_secrets(['RECORD_UID']).first

# Generate and set new password
new_password = KeeperSecretsManager::Utils.generate_password(
  length: 40,
  lowercase: 5,
  uppercase: 5,
  digits: 5,
  special_characters: 5
)

record.password = new_password

# Save changes
secrets_manager.update_secret(record)

puts "Password updated with new secure value"

Password rotation script:

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Rotate passwords for multiple records
record_uids = ['UID1', 'UID2', 'UID3']

record_uids.each do |uid|
  record = secrets_manager.get_secrets([uid]).first

  # Generate new password
  new_password = KeeperSecretsManager::Utils.generate_password(
    length: 32,
    lowercase: 3,
    uppercase: 3,
    digits: 3,
    special_characters: 3
  )

  # Update record
  record.password = new_password
  record.notes = "Password rotated on #{Time.now}"

  secrets_manager.update_secret(record)

  puts "✓ Rotated password for: #{record.title}"
end

Update a Secret

update_secret(record)
Parameter
Type
Required
Default
Description

record

KeeperRecord

Yes

-

The modified record to update in the vault

Response:

Type: void

Updates the secret in the vault with the modified values.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get existing record
record = secrets_manager.get_secrets(['RECORD_UID']).first

# Update fields using dynamic access
record.password = 'NewSecurePassword123!'

# Update fields using explicit method
record.set_field('login', '[email protected]')

# Update notes
record.notes = "Updated on #{Time.now}"

# Save changes
secrets_manager.update_secret(record)

puts "Secret updated successfully"

Download a File

download_file(file)
Parameter
Type
Required
Default
Description

file

KeeperFile

Yes

-

File object from a KeeperRecord to download

Response:

Type: Hash

Returns a hash containing:

  • 'name' - File name

  • 'data' - File contents as binary string

  • 'size' - File size in bytes

  • 'type' - MIME type of the file

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get record with files
record = secrets_manager.get_secrets(['RECORD_UID']).first

# Check if record has files
if record.files && record.files.any?
  # Download first file
  file = record.files.first
  downloaded = secrets_manager.download_file(file)

  # Save to disk
  filename = downloaded['name'] || 'downloaded_file'
  File.write(filename, downloaded['data'])

  puts "Downloaded: #{filename}"
  puts "Size: #{downloaded['size']} bytes"
  puts "Type: #{downloaded['type']}"
end

Upload a File

upload_file(owner_record_uid, file_data, file_name, file_title = nil)
Parameter
Type
Required
Default
Description

owner_record_uid

String

Yes

-

UID of the record to attach the file to

file_data

String

Yes

-

File contents as binary string or text

file_name

String

Yes

-

Name of the file in Keeper

file_title

String

Optional

nil

Title/description of the file in Keeper

Response:

Type: String

Returns the UID of the uploaded file.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Upload a file
file_uid = secrets_manager.upload_file(
  'RECORD_UID',                          # owner_record_uid
  File.read('/path/to/certificate.pem'), # file_data
  'certificate.pem',                      # file_name
  'Server Certificate'                    # file_title (optional)
)

puts "File uploaded with UID: #{file_uid}"

# Upload text content
file_uid = secrets_manager.upload_file(
  'RECORD_UID',
  "server=localhost\nport=5432\n",
  'config.txt',
  'Database Config'
)

Create a Secret

create_secret(record_data, options = nil)
Parameter
Type
Required
Default
Description

record_data

Hash

Yes

-

Hash containing record structure (type, title, fields, custom, notes)

options

CreateOptions

Yes

-

CreateOptions object containing folder_uid (required) and optional settings

Response:

Type: String

Returns the UID of the created secret.

Prerequisites:

  • Shared folder UID (if specifying folder_uid)

  • Shared folder must be accessible by the Secrets Manager Application

  • You and the Secrets Manager application must have edit permission

  • There must be at least one record in the shared folder

  • Record fields must be formatted correctly (see field type documentation)

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Create a login record
record_data = {
  type: 'login',
  title: 'Production Database',
  fields: [
    { type: 'login', value: ['db_admin'] },
    { type: 'password', value: ['SecurePassword123!'] },
    { type: 'url', value: ['https://db.example.com'] },
    {
      type: 'host',
      value: [{ hostName: '192.168.1.100', port: '5432' }],
      label: 'Database Host'
    }
  ],
  custom: [
    { type: 'text', label: 'Environment', value: ['Production'] },
    { type: 'text', label: 'Database Name', value: ['main_db'] }
  ],
  notes: 'Production database credentials'
}

# Create options with required folder_uid
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')

# Create the secret
record_uid = secrets_manager.create_secret(record_data, options)

puts "Secret created with UID: #{record_uid}"

# Alternative: Create options inline
record_uid = secrets_manager.create_secret(
  record_data,
  KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
)

Create Custom Type Record

# Create a database credentials record
record_data = {
  type: 'databaseCredentials',
  title: 'MySQL Production',
  fields: [
    { type: 'text', label: 'Database Type', value: ['MySQL'] },
    {
      type: 'host',
      value: [{ hostName: 'mysql.example.com', port: '3306' }]
    },
    { type: 'login', value: ['root'] },
    { type: 'password', value: ['SecurePassword123!'] }
  ],
  notes: 'MySQL production database'
}

# Create options with required folder_uid
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)

Delete a Secret

delete_secret(uids)
Parameter
Type
Required
Default
Description

uids

String or Array<String>

Yes

-

UID or array of UIDs of secrets to delete

Response:

Type: void

Deletes the specified secret(s) from the vault.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Delete a single secret
secrets_manager.delete_secret('RECORD_UID')

puts "Secret deleted successfully"

# Delete multiple secrets
uids = ['UID1', 'UID2', 'UID3']
secrets_manager.delete_secret(uids)

puts "#{uids.length} secrets deleted"

Folders

The Ruby SDK provides full CRUD support for folder operations.

Get Folders

get_folders

Response:

Type: Array<KeeperFolder>

Returns all folders accessible to the Secrets Manager application.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Get all folders
folders = secrets_manager.get_folders

folders.each do |folder|
  puts "#{folder.name} (UID: #{folder.uid})"
end

Get Folder Path

get_folder_path(folder_uid)
Parameter
Type
Required
Default
Description

folder_uid

String

Yes

-

UID of the folder

Response:

Type: String

Returns the full path to the folder (breadcrumb trail separated by "/").

Example Usage

# Get folder path (breadcrumb trail)
path = secrets_manager.get_folder_path('FOLDER_UID')
puts "Folder path: #{path}"  # "Parent/Child/Grandchild"

Find Folder by Name

find_folder_by_name(name, parent_uid: nil)
Parameter
Type
Required
Default
Description

name

String

Yes

-

Name of the folder to find

parent_uid

String

Optional

nil

UID of parent folder to search within

Response:

Type: KeeperFolder or nil

Returns the first folder matching the name, or nil if not found.

Example Usage

# Find folder by name
folder = secrets_manager.find_folder_by_name('Finance')

# Find folder within specific parent
folder = secrets_manager.find_folder_by_name('Reports', parent_uid: 'PARENT_UID')

Build Folder Tree

# Get folder manager for advanced operations
fm = secrets_manager.folder_manager

# Build complete folder tree structure
tree = fm.build_folder_tree

# Print folder tree to console
fm.print_tree

# Get folder relationships
ancestors = fm.get_ancestors('FOLDER_UID')      # [parent, grandparent, ...]
descendants = fm.get_descendants('FOLDER_UID')   # [children, grandchildren, ...]

Create a Folder

create_folder(name, parent_uid:)
Parameter
Type
Required
Default
Description

name

String

Yes

-

Name of the folder to create

parent_uid

String

Yes

-

UID of the parent shared folder

Response:

Type: String

Returns the UID of the created folder.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Create folder at root level (within a shared folder)
folder_uid = secrets_manager.create_folder('New Folder', parent_uid: 'SHARED_FOLDER_UID')

puts "Folder created with UID: #{folder_uid}"

# Create subfolder within existing folder
subfolder_uid = secrets_manager.create_folder(
  'Subfolder',
  parent_uid: folder_uid
)

puts "Subfolder created: #{subfolder_uid}"

Update a Folder

update_folder(folder_uid, new_name)
Parameter
Type
Required
Default
Description

folder_uid

String

Yes

-

UID of the folder to update

new_name

String

Yes

-

New name for the folder

Response:

Type: void

Renames the specified folder.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Rename a folder
secrets_manager.update_folder('FOLDER_UID', 'New Folder Name')

puts "Folder renamed successfully"

Delete Folders

delete_folder(folder_uid, force: false)
Parameter
Type
Required
Default
Description

folder_uid

String

Yes

-

UID of the folder to delete

force

Boolean

Optional

false

If true, deletes folder and all its contents. If false, only deletes empty folders.

Response:

Type: void

Deletes the specified folder from the vault.

Example Usage

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# Delete empty folder
secrets_manager.delete_folder('FOLDER_UID')

# Force delete folder (removes all contents)
secrets_manager.delete_folder('FOLDER_UID', force: true)

puts "Folder deleted"

# Delete multiple folders
folder_uids = ['UID1', 'UID2', 'UID3']
folder_uids.each do |uid|
  secrets_manager.delete_folder(uid, force: true)
end

Caching

Improve performance by caching secrets locally:

Using CachingStorage

require 'keeper_secrets_manager'

# Create base storage
base_storage = KeeperSecretsManager::Storage::FileStorage.new('keeper_config.json')

# Wrap with caching (600 second TTL)
cached_storage = KeeperSecretsManager::Storage::CachingStorage.new(base_storage, 600)

# Use cached storage
secrets_manager = KeeperSecretsManager.new(config: cached_storage)

# First call fetches from server
records = secrets_manager.get_secrets

# Subsequent calls within TTL use cache
records = secrets_manager.get_secrets  # Uses cached data

Custom Caching with custom_post_function

For advanced caching scenarios:

require 'keeper_secrets_manager'

# Create custom cache
cache = {}

custom_post = lambda do |url, payload|
  cache_key = "#{url}:#{payload}"

  # Check cache
  if cache[cache_key] && cache[cache_key][:expires_at] > Time.now
    return cache[cache_key][:response]
  end

  # Make actual request
  uri = URI(url)
  request = Net::HTTP::Post.new(uri)
  request['Content-Type'] = 'application/json'
  request.body = payload

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  # Cache response for 10 minutes
  cache[cache_key] = {
    response: response.body,
    expires_at: Time.now + 600
  }

  response.body
end

secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  custom_post_function: custom_post
)

Error Handling

The SDK provides specific exception classes for different error scenarios:

require 'keeper_secrets_manager'

begin
  secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
  records = secrets_manager.get_secrets

rescue KeeperSecretsManager::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
  # Token expired or invalid

rescue KeeperSecretsManager::NetworkError => e
  puts "Network error: #{e.message}"
  # Connection timeout or DNS failure

rescue KeeperSecretsManager::CryptoError => e
  puts "Encryption error: #{e.message}"
  # Decryption failed or key error

rescue KeeperSecretsManager::NotationError => e
  puts "Notation parsing error: #{e.message}"
  # Invalid notation URI format

rescue KeeperSecretsManager::Error => e
  puts "General error: #{e.message}"
  # Other SDK errors

rescue StandardError => e
  puts "Unexpected error: #{e.message}"
end

Common Error Scenarios

# Handle missing records gracefully
begin
  record = secrets_manager.get_secret_by_title('Nonexistent Record')
rescue KeeperSecretsManager::Error => e
  puts "Record not found: #{e.message}"
  # Provide fallback or create new record
end

# Retry logic for network errors
max_retries = 3
retries = 0

begin
  records = secrets_manager.get_secrets
rescue KeeperSecretsManager::NetworkError => e
  retries += 1
  if retries < max_retries
    sleep 2 ** retries  # Exponential backoff
    retry
  else
    raise
  end
end

Advanced Configuration

Custom Hostname

require 'keeper_secrets_manager'

# EU datacenter
secrets_manager = KeeperSecretsManager.new(
  token: 'EU:ONE_TIME_TOKEN',
  hostname: 'keepersecurity.eu',
  config: storage
)

# Australian datacenter
secrets_manager = KeeperSecretsManager.new(
  token: 'AU:ONE_TIME_TOKEN',
  hostname: 'keepersecurity.com.au',
  config: storage
)

SSL Certificate Verification

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.new(
  config: storage,
  verify_ssl_certs: true  # Default is true
)

Custom Logging

require 'keeper_secrets_manager'
require 'logger'

# Create custom logger
logger = Logger.new(STDOUT)
logger.level = Logger::DEBUG

secrets_manager = KeeperSecretsManager.new(
  config: storage,
  logger: logger,
  log_level: Logger::DEBUG
)

All Configuration Options

require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.new(
  token: 'US:ONE_TIME_TOKEN',           # One-time access token
  config: storage,                       # Storage implementation
  hostname: 'keepersecurity.com',        # API hostname
  verify_ssl_certs: true,                # SSL verification
  logger: Logger.new(STDOUT),            # Custom logger
  log_level: Logger::WARN,               # Log level
  custom_post_function: my_post_func     # Custom HTTP handler
)

Field Type Helpers

Optional convenience methods for creating typed fields:

require 'keeper_secrets_manager'

# Use field helpers for type safety
fields = [
  KeeperSecretsManager::FieldTypes::Helpers.login('admin'),
  KeeperSecretsManager::FieldTypes::Helpers.password('SecurePass123!'),
  KeeperSecretsManager::FieldTypes::Helpers.url('https://example.com'),
  KeeperSecretsManager::FieldTypes::Helpers.host(
    hostname: '192.168.1.100',
    port: 22
  ),
  KeeperSecretsManager::FieldTypes::Helpers.name(
    first: 'John',
    middle: 'Q',
    last: 'Doe'
  ),
  KeeperSecretsManager::FieldTypes::Helpers.address(
    street1: '123 Main St',
    city: 'New York',
    state: 'NY',
    zip: '10001'
  )
]

# Convert to hashes for record creation
record_data = {
  type: 'login',
  title: 'Server with Helpers',
  fields: fields.map(&:to_h)
}

# Create options with required folder_uid
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)

Dynamic Record Access

The Ruby SDK uses method_missing to provide JavaScript-style dynamic field access:

# Get record
record = secrets_manager.get_secrets(['RECORD_UID']).first

# Dynamic getters
login = record.login          # Returns field value
password = record.password    # Returns field value
url = record.url             # Returns field value

# Dynamic setters
record.password = 'NewPassword123!'
record.url = 'https://newurl.example.com'

# Check if field exists
if record.respond_to?(:oneTimeCode)
  # Generate TOTP code from oneTimeCode field
  require 'keeper_secrets_manager/totp'
  totp_url = record.oneTimeCode
  totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)
  totp_code = KeeperSecretsManager::TOTP.generate_code(
    totp_params['secret'],
    algorithm: totp_params['algorithm'],
    digits: totp_params['digits'],
    period: totp_params['period']
  )
end

# Access all fields as hash
fields = record.fields
fields.each do |type, values|
  puts "#{type}: #{values.join(', ')}"
end

.NET SDK

Detailed .Net SDK docs for Keeper Secrets Manager

Download and Installation

Prerequisites

dotnet add package Keeper.SecretsManager

Source Code

Find the .Net source code in the GitHub repository

Using the SDK

Initialize Storage

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

In order to retrieve secrets, you must first initialize the local storage on your machine.

SecretsManagerClient.InitializeStorage(storage: KeyValueStorage, clientKey: String? = null, hostName: String? = null)

Parameter

Type

Required

Default

Description

storage

KeyValueStorage

Yes

clientKey

String

Optional

null

hostName

String

Optional

null

Example Usage

var storage = new LocalConfigStorage("ksm-config.json");
SecretsManagerClient. InitializeStorage(storage, "[One Time Access Token]");
// Using token only to generate a config (for later usage)
// requires at least one access operation to bind the token
//var options = new SecretsManagerOptions(storage);
//await SecretsManagerClient.GetSecrets(options);

Secrets Manager Options

SecretsManagerOptions(IKeyValueStorage storage, QueryFunction queryFunction = null, bool allowUnverifiedCertificate = false, string proxyUrl = null)

Parameter

Type

Required

Default

storage

KeyValueStorage

Yes

queryFunction

String

Optional

null

allowUnverifiedCertificate

Bool

Optional

false

proxyUrl

String

Optional

null

Retrieve Secrets

GetSecrets(options: SecretsManagerOptions, recordsFilter: List<String> = emptyList()): KeeperSecrets

Parameter

Type

Required

Default

Description

options

SecretsManagerOptions

Yes

Storage and query configuration

recordsFilter

List<String>

Optional

Empty List

Record search filters

Response

Type: KeeperSecrets

Object containing all Keeper records, or records that match the given filter criteria

Example Usage

Retrieve all Secrets

var options = new SecretsManagerOptions(storage, testPostFunction);
var secrets = GetSecrets(options);

Retrieve Secrets by Title

// get all matching records
async Task<IEnumerable<KeeperRecord>> GetSecretsByTitle(SecretsManagerOptions options, string recordTitle)

// get only the first matching record
async Task<KeeperRecord> GetSecretByTitle(SecretsManagerOptions options, string recordTitle)
Parameter
Type
Required
Description

options

SecretsManagerOptions

Yes

Preconfigured options

recordTitle

string

Yes

Record title to search for

Example Usage

using System;
using System.Threading.Tasks;
using SecretsManager;

private static async Task getOneIndividualSecret()
{
    var storage = new LocalConfigStorage("ksm-config.json");
    var options = new SecretsManagerOptions(storage);
    var records = (await SecretsManagerClient.GetSecretsByTitle(
            options, "My Credentials")
        ).Records;
    foreach (var record in records)
    {
        Console.WriteLine(record.RecordUid + " - " + record.Data.title);
        foreach (var field in record.Data.fields)
        {
            Console.WriteLine("\t" + field.label + " (" + field.type + "): [" + String.Join(", ", field.value) + "]");
        }
    }
}

Retrieve Values from a Secret

Retrieve a Password

secret.FieldValue("password")
var storage = new LocalConfigStorage(configName);
Console.WriteLine($"Local Config Storage opened from the file {configName}");
if (clientKey != null)
    SecretsManagerClient.InitializeStorage(storage, "<One Time Access Token>");
}
var options = new SecretsManagerOptions(storage);
//get secrets
var secrets= (await SecretsManagerClient.GetSecrets(options)).Records;

// get the password from the first secret
var firstSecret= secrets[0];
var password = firstSecret.FieldValue("password").ToString();

Field types are based on the Keeper . For a detailed list of available fields based on the Keeper Record Type, see the record-type-info command in Keeper Commander.

Retrieve Other Fields Using Keeper Notation

GetValue(KeeperSecrets secrets, string notation)
var storage = new LocalConfigStorage(configName);
Console.WriteLine($"Local Config Storage opened from the file {configName}");
if (clientKey != null)
    SecretsManagerClient.InitializeStorage(storage, "<One Time Access Token>");
}
var options = new SecretsManagerOptions(storage);
//get secrets
var secrets (await SecretsManagerClient.GetSecrets(options)).Records;

// get login field value using dot notation
var password = Notation.GetValue(secrets, "BediNKCMG21ztm5xGYgNww/field/login");

See Keeper Notation documentation to learn about Keeper Notation format and capabilities

Parameter

Type

Required

Default

Description

secrets

KeeperSecrets

Yes

Secrets to query

notation

string

Yes

Field query in dot notation format

Retrieve TOTP Code

CryptoUtils.GetTotpCode(string url)
var storage = new LocalConfigStorage(configName);
Console.WriteLine($"Local Config Storage opened from the file {configName}");
if (clientKey != null)
    SecretsManagerClient.InitializeStorage(storage, "<One Time Access Token>");
}
var options = new SecretsManagerOptions(storage);
//get secrets
var secrets (await SecretsManagerClient.GetSecrets(options)).Records;

// get TOTP url from a record
var url = Notation.GetValue(secrets, "BediNKCMG21ztm5xGYgNww/field/OneTimeCode");

// get TOTP code
var totp = CryptoUtils.GetTotpCode(url);
Console.WriteLine(totp.Code);

Parameter

Type

Required

Default

Description

url

string

Yes

TOTP Url

Update Values in a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Save Changes to a Secret

UpdateSecret(options: SecretsManagerOptions, record: KeeperRecord);
var options = SecretsManagerOptions(storage, testPostFunction)
await SecretsManagerClient.UpdateSecret(options, secret);
var storage = new LocalConfigStorage(configName);
var options = new SecretsManagerOptions(storage);

//get secrets
var secrets = (await SecretsManagerClient.GetSecrets(options)).Records;

// get the first secret
var secret = secrets[0];

// rotate password on the record
secret.updateFieldValue("password", "MyNewPassword");
//start a transaction
await SecretsManagerClient.UpdateSecret(options, secret, UpdateTransactionType.Rotation);
// rotate password on remote host
success = rotateRemoteSshPassword("MyNewPassword");
// complete the transaction - commit or rollback
await SecretsManagerClient.CompleteTransaction(options, secret.RecordUid, rollback: !success);

Parameter

Type

Required

Default

Description

options

SecretsManagerOptions

Yes

Storage and query configuration

Use UpdateSecret to save changes made to a secret record. Changes will not be reflected in the Keeper Vault until UpdateSecret is performed.

Update a Field Value

UpdateFieldValue(string fieldType, object value)
var storage = new LocalConfigStorage(configName);
Console.WriteLine($"Local Config Storage opened from the file {configName}");
if (clientKey != null)
    SecretsManagerClient.InitializeStorage(storage, "<One Time Access Token>");
}
var options = new SecretsManagerOptions(storage);
//get secrets
var secrets= (await SecretsManagerClient.GetSecrets(options)).Records;

// get the password from the first secret
var firstSecret= secrets[0];

// update the login field
firstSecret.updateFieldValue("login", "My New Login");

// update title and notes
firstSecret.Data.title = "New Title";
firstSecret.Data.notes = "New Notes";

// save changes
await SecretsManagerClient.UpdateSecret(options, firstSecret);

Parameter

Type

Required

Default

Description

fieldType

string

Yes

The field to update

value

object

Yes

Value to set the field to

Generate a Random Password

CryptoUtils.GeneratePassword(int length, lowercase int, uppercase int, digits int, specialCharacters);
// generate a random password
var password = CryptoUtils.GeneratePassword();
// update a record with the new password
firstRecord.UpdateFieldValue("password", password);
await SecretsManagerClient.UpdateSecret(options, firstRecord);
Parameter
Type
Required
Default

length

int

Optional

64

lowercase

int

Optional

0

uppercase

int

Optional

0

digits

int

Optional

0

specialCharacters

int

Optional

0

Each parameter indicates the min number of a type of character to include. For example, 'uppercase' indicates the minimum number of uppercase letters to include.

Download a File

DownloadFile(file: KeeperFile): ByteArray

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File to download

Response

Type: ByteArray

ByteArray of file for download

Download a Thumbnail

DownloadThumbnail(file: KeeperFile): ByteArray

Parameter

Type

Required

Default

Description

file

KeeperFile

Yes

File with thumbnail to download

Response

Type: ByteArray

ByteArray of thumbnail for download

Upload a File

Upload File:

UploadFile(SecretsManagerOptions options, KeeperRecord ownerRecord, KeeperFileUpload file)
Parameter
Type
Required
Description

options

SecretsManagerOptions

Yes

Storage and query configuration

ownerRecord

KeeperRecord

Yes

The record to attach the uploaded file to

file

KeeperFileUpload

Yes

The File to upload

Creating the Keeper File Upload Object:

KeeperFileUpload(string name, string title, string type, byte[] data)
Parameter
Type
Required
Description

name

string

Yes

What the name of the file will be in Keeper once uploaded

title

string

Yes

What the title of the file will be in Keeper once uploaded

type

string

Yes

The mime type of data in the file. 'application/octet-stream' for example

data

byte[]

Yes

File data as bytes

Example Usage

using System;
using System.Threading.Tasks;
using SecretsManager;

private static async Task uploadFile()
{
    // initalize storage and options
    var storage = new LocalConfigStorage("ksm-config.json");
    var options = new SecretsManagerOptions(storage);
    
    // get a record to attach the file to
    var records = (await SecretsManagerClient.GetSecrets(
            options, new[] { "XXX" })
        ).Records;
        
    var ownerRecord = records[0];
    
    // get file data to upload
    var bytes = await File.ReadAllBytesAsync("my-file.json");
    var myFile = new KeeperFileUpload(
        "my-file1.json", 
        "My File", 
        null, 
        bytes
    );
       
    // upload file to selected record                     
    await SecretsManagerClient.UploadFile(options, firstRecord, myFile);
    
}

Create a Secret

Prerequisites:

  • Shared folder UID

    • Shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using UploadFile

SecretsManagerClient.CreateSecret(options, folderUid, record)
Parameter
Type
Required
Defaut

options

SecretsManagerOptions

Yes

folderUid

string

Yes

record

KeeperRecordData

Yes

SecretsManagerClient.CreateSecret2(options, createOptions, record, folders)
Parameter
Type
Required
Defaut

options

SecretsManagerOptions

Yes

createOptions

CreateOptions

Yes

record

KeeperRecordData

Yes

folders

KeeperFolder[]

No

This example creates a login type record with a login value and a generated password.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

var newRecord = new KeeperRecordData{type = "login", title = "Sample KSM Record: C#"};

newRecord.fields = new[]
{
    new KeeperRecordField { type = "login", value = new[] { "My Username" } },
    new KeeperRecordField { type = "password", value = new[] { CryptoUtils.GeneratePassword() } },
};
newRecord.notes = "This is a C# record creation example";

var recordUid = await SecretsManagerClient.CreateSecret(options, folderUid, newRecord);

This example creates a record with a custom record type.

Replace '[FOLDER UID]' in the example with the UID of a shared folder that your Secrets Manager has access to.

var newRecord = new KeeperRecordData();
newRecord.type = "Custom Login";
newRecord.title = "Sample Custom Type KSM Record: C#";
newRecord.fields = new[]
{
    new KeeperRecordField { 
        type = "host", 
        value = new[] 
        {
            new Dictionary<string, string>
            {
                { "hostName", "127.0.0.1"},
                { "port", "8080"}
            }
        },
        label = "My Custom Host lbl",
        required = true
    },
    
    new KeeperRecordField { 
        type = "login", 
        value = new[] { "[email protected]" }, 
        required = true, 
        label = "My Custom Login lbl"
    },
    
    new KeeperRecordField
    {
        type = "password", 
        value = new[] { CryptoUtils.GeneratePassword() }, 
        required = true, 
        label = "My Custom Password lbl"
    },
    
    new KeeperRecordField
    {
        type = "url",
        value = new[] { "http://localhost:8080/login" },
        label = "My Login Page",
        required = true
    },
    
    new KeeperRecordField { 
        type = "securityQuestion", 
        value = new[]
        {
            new Dictionary<string, string>
            {
                {"question", "What is one plus one (write just a number)"}, 
                { "answer", "2" }
            }
        }, 
        label = "My Question 1",
        required = true
    },
    
    new KeeperRecordField { 
        type = "phone", 
        value = new[]
        {
            new Dictionary<string,string>
            {
                { "region", "US" },
                { "number", "510-444-3333" },
                { "ext", "2345" },
                { "type", "Mobile" }
            }
        }, 
        label = "My Private Phone", 
        privacyScreen = true
    },

    new KeeperRecordField
    {
        type = "date", 
        value = new[] {(object) 1641934793000 }, 
        label = "My Date Lbl"
    },
    
    new KeeperRecordField { 
        type = "name", 
        value = new[]
        {
            new Dictionary<string, string>
            {
                {"first", "John"},
                {"middle", "Patrick"},
                {"last", "Smith"}
            }
        },
        required = true
    },
    new KeeperRecordField
    {
        type = "oneTimeCode", 
        value = new[]
        {
            "otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example"
        }, 
        label = "My TOTP",
        required = true
    }
};
newRecord.notes = "\tThis custom type record was created\n\tvia Python SDK copied from https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/.net-sdk";

var recordUid = await SecretsManagerClient.CreateSecret(options, "[FOLDER_UID]", newRecord);

Delete a Secret

The .Net KSM SDK can delete records in the Keeper Vault.

DeleteSecret(smOptions, recordsUids);
Parameter
Type
Required

smOptions

SecretsManagerOptions

Yes

recordsUids

string[]

Yes

using SecretsManager;

// setup secrets manager
var storage = new LocalConfigStorage("ksm-config.json");
//SecretsManagerClient.InitializeStorage(storage, "<One Time Access Token>");
var smOptions = new SecretsManagerOptions(storage);

// delete a specific secret by record UID
await SecretsManagerClient.DeleteSecret(smOptions, new string[] {"EG6KdJaaLG7esRZbMnfbFA"});

Caching

To protect against losing access to your secrets when network access is lost, the .Net SDK allows caching of secrets to the local machine in an encrypted file.

Setup and Configure Cache

In order to setup caching in the .Net SDK, include a caching post function as the second argument when instantiating aSecretsManagerOptions object.

The .Net SDK includes a default caching function cachingPostFunction which stores cached queries to a file.

var options = new SecretsManagerOptions(storage, SecretsManagerClient.CachingPostFunction);
var secrets = await SecretsManagerClient.GetSecrets(options);

Folders

Folders have full CRUD support - create, read, update and delete operations.

Read Folders

Downloads full folder hierarchy.

Task<KeeperFolder[]> GetFolders(SecretsManagerOptions options)

Response

Type: KeeperFolder[]

Example Usage

using SecretsManager;

var options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
var folders = await SecretsManagerClient.GetFolders(options);

Create a Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required - UID of a shared folder, while sub-folder UID is optional and if missing, a new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

Task<string> CreateFolder(SecretsManagerOptions options, CreateOptions createOptions, string folderName, KeeperFolder[] folders = null)
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

createOptions

CreateOptions

Yes

The parent and sub-folder UIDs

folderName

string

Yes

The Folder name

folders

KeeperFolder[]

No

null

List of folders to use in the search for parent and sub-folder from CreateOptions

public class CreateOptions {
    public string FolderUid { get; }
    public string SubFolderUid { get; }
}
public class KeeperFolder {
        public byte[] FolderKey { get; }
        public string FolderUid { get; }
        public string ParentUid { get; }
        public string Name { get; }
}

Example Usage

using SecretsManager;

var options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
var co := new CreateOptions("[PARENT_SHARED_FOLDER_UID]");
var folderUid = await SecretsManagerClient.CreateFolder(options, co, "new_folder");

Update a Folder

Updates the folder metadata - currently folder name only.

Task UpdateFolder(SecretsManagerOptions options, string folderUid, string folderName, KeeperFolder[] folders = null)
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

folderUid

string

Yes

The folder UID

folderName

string

Yes

The new folder name

folders

KeeperFolder[]

No

null

List of folders to use in the search for parent folder

Example Usage

using SecretsManager;

var options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
await SecretsManagerClient.UpdateFolder(options, "[FOLDER_UID]", "new_folder_name");

Delete Folders

Removes a list of folders. Use forceDeletion flag to remove non-empty folders.

When using forceDeletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

Task DeleteFolder(SecretsManagerOptions options, string[] folderUids, bool forceDeletion = false)
Parameter
Type
Required
Default
Description

options

SecretsManagerOptions

Yes

Preconfigured options

folderUids

string[]

Yes

The folder UID list

forceDeletion

bool

No

false

Force deletion of non-empty folders

Example Usage

using SecretsManager;

var options = new SecretsManagerOptions(new LocalConfigStorage("ksm-config.json"));
await SecretsManagerClient.DeleteFolder(options, new string[]{"[FOLDER_UID1]", "[FOLDER_UID2]"}, true);

Proxy support

.NET SDK supports setting proxy through environment variables and passing proxy url to SecretsManagerOptions directly

Keeper recommends using environment variables for proxy settings. This approach keeps configuration details out of code, ensures consistency across tools and environments, and simplifies deployment and maintenance

Example usage through environment variables

HTTPS_PROXY=http://user:[email protected]:3128 dotnet run

Example usage passing url to SecretsManagerOptions

var options = new SecretsManagerOptions(storage, null, false, "http://user:[email protected]:3128");

Rust SDK

Detailed Rust SDK docs for Keeper Secrets Manager

Download and Installation

Adding as Package using Cargo

cargo add keeper-secrets-manager-core

Source Code

Find the Rust source code in the GitHub repository

Using the SDK

Initialise

Using token only to generate a new config (for later usage) requires at least one read operation to bind the token and fully populate config.json

SecretsManager::new(client_options)?
use keeper_secrets_manager_core::{ClientOptions, SecretsManager,storage::FileKeyValueStorage}

fn main()-> Result<(), KSMRError>{
    let client_options = ClientOptions::new_client_options_with_token(token, config);
    let mut secrets_manager = SecretsManager::new(client_options)?;
    Ok(())
}

Parameter

Required

Description

Type

token

Yes

One Time Access Token

String

config

Yes

Storage Configuration

KeyValueStorage

Retrieve Secrets

let records_filter = Vec::new(); // add record filters of needed based on UID
let secrets = secrets_manager.get_secrets(records_filter)?;
use keeper_secrets_manager_core::{core::{ClientOptions, SecretsManager}, custom_error::KSMRError, storage::FileKeyValueStorage};

fn main()-> Result<(), KSMRError>{
    let token = "<Your One time token>".to_string();
    let file_name = FileKeyValueStorage::new_config_storage("test.json".to_string())?;
    let client_options = ClientOptions::new_client_options(token, file_name); 
    
    let mut secrets_manager = SecretsManager::new(client_options)?;
    let secrets = secrets_manager.get_secrets(Vec::new())?;

    for secret in secrets {
        secret.print();
        println!("---");
    }
    Ok(())
}
use keeper_secrets_manager_core::{core::{ClientOptions, SecretsManager}, custom_error::KSMRError, storage::FileKeyValueStorage};

fn main()-> Result<(), KSMRError>{
    let token = "<Your One time token>".to_string();
    let file_name = FileKeyValueStorage::new_config_storage("test.json".to_string())?;
    let client_options = ClientOptions::new_client_options(token, file_name); 
    
    let mut secrets_manager = SecretsManager::new(client_options)?;
    let records_filter = vec!["record_uid1","record_uid2"]; // add record filters of needed based on UID
    let secrets = secrets_manager.get_secrets(records_filter)?;

    for secret in secrets {
        secret.print();
        println!("---");
    }
    Ok(())
}

Parameter

Type

Required

Default

Description

uids

Vec<String>

Optional

None

Record UIDs to fetch

Response

Type: Vec<Record>

All Keeper records, or records with the given UIDs

default - we will get all records which the token given has access to

Retrieve Values from secret

Retrieve a password

This shortcut gets the password of a secret once that secret has been retrieved from Keeper Secrets Manager.

secret.get_standard_field_value('password', true);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by record UID
    let secrets = secrets_manager.get_secrets(vec!["record_uid".to_string()])?;
    let secret = match secrets.len(){
        0 => return Err(KSMRError::CustomError("no secret with given uid is found".to_string())),
        _ => &secrets[0],
    };
    // get password from record
    let my_secret_password = secret.get_standard_field_value("password", true);
    Ok(())
}

Retrieve Standard Fields

secret.get_standard_field_value(“FIELD_TYPE”.to_string(), true);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::FileKeyValueStorage,
    custom_error::KSMRError,
    enums::StandardFieldTypeEnum
};

fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let token = "your_token_goes_here".to_string();
    let config = FileKeyValueStorage::new_config_storage("test.json".to_string())?;
    let client_options = ClientOptions::new_client_options_with_token(token, config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by record UID
    let secrets = secrets_manager.get_secrets(vec!["record_uid".to_string()])?;
    let secret = match secrets.len(){
        0 => return Err(KSMRError::CustomError("no secret with given uid is found".to_string())),
        _ => &secrets[0],
    };
    // use StandardFieldTypeEnum for getting accurate type for standard field without any typographic errors
    let login_field = StandardFieldTypeEnum::LOGIN.get_type().to_string();
    // get login field from the secret
    let my_secret_login = secret.get_standard_field_value(login_field, true)
    Ok(())
}
Parameter
Type
Required
Default
Description

field_type

String

Yes

None

Field type to get

single

boolean

Optional

False

Return only the first value

Field types are based on the Keeper . For a detailed list of available fields based on the Keeper Record Type, see the record-type-info command in Keeper Commander.

Retrieve Custom Fields

secret.get_custom_field_value(“FIELD_TYPE”, true);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by record UID
    let secrets = secrets_manager.get_secrets(vec!["record_uid".to_string()])?;
    let secret = match secrets.len(){
        0 => return Err(KSMRError::CustomError("no secret with given uid is found".to_string())),
        _ => &secrets[0],
    };
    // Get a custom field, e.g. API Key
    let api_key = secret.get_custom_field_value(“API Key”, true)
    Ok(())
}
Parameter
Type
Required
Default
Description

field_type

String

Yes

-

Field type to get

single

boolean

Optional

False

Return only the first value

Custom fields are any field that is not part of the record type definition but can be added by users.

Response

Type: String or Vec<String>

the value or values of the field. It will be a single value only if the single=true option is passed.

Records by Title

secrets_manager.get_secret_by_title(record_title);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get all secrets matching the record title
    let secrets = secrets_manager.get_secret_by_title("My Credentials").unwrap().unwrap();
    Ok(())
}

Response

Type: Record<Option<Vec<Record>>>

Parameter
Type
Required
Description

record_title

&str

Yes

Title of the record to be fetched

Retrieve Values using Keeper Notation

secrets_manager.get_notation(query)
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get all secrets matching the notation
    let mut notation = "HDQTnxkTcPSOsHNAlbI4aQ/field/login".to_string();
    let mut result = secrets_manager.get_notation(notation)?;
    Ok(())
}

See Keeper Notation documentation to learn about Keeper Notation format and capabilities

Parameter
Type
Required
Default
Description

query

String

Yes

-

Keeper Notation query for getting a value from a specified field

Returns

The value of the queried field

Type: String or Vec<String>

Retrieve a TOTP Code

get_totp_code(&url)
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get TOTP url value from a record
    let value = record.get_standard_field_value(StandardFieldTypeEnum::ONETIMECODE.get_type(), false)
    let url: String = utils::get_otp_url_from_value_obj(value)?;

    // get code from TOTP url
    let totp = utils::get_totp_code(&url)?;
    println!("{}", totp.get_code());
    Ok(())
}

Returns

Type: Result<TotpCode,KSMRError>

Parameter
Type
Required
Description

url

String

Yes

TOTP Url

Update a Secret

Record update commands don't update local record data on success (esp. updated record revision) so any consecutive updates to an already updated record will fail due to revision mismatch. Make sure to reload all updated records after each update batch.

Save Changes to a Secret

secrets_manager.save(Record, UpdateTransactionType)
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secret_to_update = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?;

    // update a field value
    let field_type= StandardFieldTypeEnum::LOGIN.get_type();
    secret_to_update.set_standard_field_value_mut(field_type, "[email protected]".into())?;

    let transaction_type: Option<UpdateTransactionType> = Some(UpdateTransactionType::None);

    secrets_manager.save(secret_to_update, transaction_type);
    Ok(())
}
Parameter
Type
Required
Default
Description

record

Record

Yes

Storage and query configuration

transaction_type

UpdateTransactionType

Yes

Configuration for transactional update

Set field values using the set_standard_field_value_mut or the set_custom_field_value_mut method.

Fields are found by type.

For a list of field types, see the Record Types documentation. Some fields have multiple values in these cases, the value can be set to a list.

Update a Standard Field Value

secret.set_standard_field_value_mut(field_type, "new_field_value".into())
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secret_to_update = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?;

    // update a field value
    let field_type= StandardFieldTypeEnum::LOGIN.get_type();
    secret_to_update.set_standard_field_value_mut(field_type, "[email protected]".into())?;

    let transaction_type: Option<UpdateTransactionType> = Some(UpdateTransactionType::None);

    secrets_manager.save(secret_to_update, transaction_type);
    Ok(())
}
Parameter
Type
Required
Default
Description

field_type

String

Yes

Field type to get

transaction_type

UpdateTransactionType

Yes

None

Configuration for transactional update

Fields are found by type. For a list of field types, see the Record Types documentation.

Update a Custom Field Value

secret.set_custom_field_value_mut(field_type, "new_field_value".into());
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secret_to_update = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?;

    // update a field value
    secret_to_update.set_custom_field_value_mut("Email", "[email protected]".into())?;

    let transaction_type: Option<UpdateTransactionType> = Some(UpdateTransactionType::None);

    secrets_manager.save(secret_to_update, transaction_type);
    Ok(())
}
Parameter
Type
Required
Default
Description

field_type

String

Yes

Field type to get

transaction_type

UpdateTransactionType

Yes

None

Configuration for transactional update

Generate a Random Password

generate_password_with_options(password_options);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secret_to_update = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?;

    # generate a random password
    let charset: String = "$_!?#".to_string();
    let length = 32;
    let digits = 2;
    let lowercase = 2;
    let uppercase = 2;
    let special_characters = 2;
    let password_options = PasswordOptions::new().length(length).digits(digits).lowercase(lowercase).uppercase(uppercase).special_characters(special_characters).special_characterset(charset);
    let password = generate_password_with_options(password_options).unwrap();

    # update a record with new password
    let field_type= StandardFieldTypeEnum::PASSWORD.get_type();
    secret.set_standard_field_value_mut(field_type, password.into())?;

    # Save changes to the secret
    let transaction_type: Option<UpdateTransactionType> = Some(UpdateTransactionType::None);
    secrets_manager.save(secret, transaction_type);
    Ok(())
}
Parameter
Type
Required
Default
Description

password_options

PasswordOptions

Yes

Configuration for the password

charset

String

Optional

Set of special characters to be included in the password

length

i32

Optional

64

Length of password

lowercase

i32

Optional

0

Count of lowercase characters in the password

uppercase

i32

Optional

0

Count of uppercase characters in the password

digits

i32

Optional

0

Count of digits in the password

special_characters

i32

Optional

0

Count of special characters in the password

Each parameter indicates the minimum number of a type of character to include. For example, 'uppercase' indicates the minimum number of uppercase letters to include.

Download a File

download_file(file_name, path);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secrets = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?[0];
    // Save all files to a tmp folder (create folder if does not exist)
    let path = format!("./temp/demo_{}.txt", secret.title);
    secret.download_file("uploaded_file.txt", &path)?;
    Ok(())
}
Parameter
Type
Required
Default
Description

file_name

&str

Yes

Name of the file to be downloaded

path

&str

Yes

Path to download file

Upload File

upload_file(owner_record, keeper_file);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // get a specific secret by UID
    let secrets = secrets_manager.get_secrets(["<RECORD UID>".to_string()])?[0];
    // Save all files to a tmp folder (create folder if does not exist)
    let path = format!("./temp/demo_{}.txt", secret.title);
    // Prepare file data for upload
    let keeper_file = KeeperFileUpload::get_file_for_upload(file_path, Some(file_name),file_title, mime_type)?;

    // Upload file attached to the owner record and get the file UID
    file_uid = secrets_manager.upload_file(owner_record, keeper_file)?;
    Ok(())
}

Upload File Parameters

Parameter
Type
Required
Default
Description

owner_record

Record

Yes

None

The record in which the file has to be uploaded

keeper_file

KeeperFileUpload

Yes

The file to be uploaded

File Parameters

Parameter
Type
Required
Default
Description

file_path

&str

Yes

Path to upload file

file_name

Option<&str>

Yes

Name of the file to be uploaded

file_title

Option<&str>

Yes

Title of the file to be uploaded

mime_type

Option<&str>

Yes

None

The type of data in the file. If none is provided, 'application/octet-stream' will be used

Returns

Type: String

The file UID of the attached file

Create a secret

Prerequisites:

  • Shared folder UID

    • The shared folder must be accessible by the Secrets Manager Application

    • You and the Secrets Manager application must have edit permission

    • There must be at least one record in the shared folder

  • Created records and record fields must be formatted correctly

    • See the documentation for expected field formats for each record type

  • TOTP fields accept only URL generated outside of the KSM SDK

  • After record creation, you can upload file attachments using upload_file

secrets_manager.create_secret(folder_uid, record);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    dto::{dtos::RecordCreate, field_structs::RecordField}
};
use serde_json::{self, json, Number, Value};

fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // This is how we create a Record
    let mut created_record =  RecordCreate::new("login".to_string(), "Login Record RUST_LOG_TEST".to_string(), Some("Dummy Notes".to_string()));
    
    // This is how we create a single field 
    let password_field = RecordField::new_record_field_with_options("password".to_string(), Value::String(utils::generate_password()?), Some("Random password label".to_string()), false, true);

    //This is one way to create all fields directly in a vector
    let fields = vec![
        RecordField::new_record_field("login".to_string(), Value::String("[email protected]".to_string()), Some("My Custom Login lbl".to_string())),

        password_field,
     ];

    created_record.fields = Some(fields);
  
    // Make the API call
    let _ = secrets_manager.create_secret("Shared_folder_uid".to_string(), created_record)?;
    Ok(())
}
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    dto::{dtos::RecordCreate, field_structs::RecordField}
};
use serde_json::{self, json, Number, Value};

fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // This is how we create a Record
    let mut created_record =  RecordCreate::new("login".to_string(), "Login Record RUST_LOG_TEST".to_string(), Some("Dummy Notes".to_string()));
    
    // This is how we create a single field 
    let password_field = RecordField::new_record_field_with_options("password".to_string(), Value::String(utils::generate_password()?), Some("Random password label".to_string()), false, true);

    // This is one of the ways to create a value object from JSON String
    let security_question_value = Value::from_str("{\"question\": \"What is the question?\", \"answer\": \"This is the answer!\"}")?;
    
    //This is one way to create all fields directly in a vector
    let fields = vec![
        RecordField::new_record_field("login".to_string(), Value::String("[email protected]".to_string()), Some("My Custom Login lbl".to_string())),

        RecordField::new_record_field("login".to_string(), Value::String("[email protected]".to_string()), Some("My Label".to_string())),

        password_field,
        
        RecordField::new_record_field("securityQuestion".to_string(),security_question_value , Some("My Label".to_string())),

        RecordField::new_record_field("multiline".to_string(),Value::String("This\nIs a multiline\nnote".to_string()) , Some("My Multiline lbl".to_string())),

        RecordField::new_record_field("secret".to_string(),Value::String("SecretText".to_string()) , Some("My Hidden Field lbl".to_string())),

        RecordField::new_record_field("pinCode".to_string(),Value::String("1234567890".to_string()) , Some("My Pin Code Field Lbl".to_string())),

        RecordField::new_record_field("addressRef".to_string(),Value::String("some_UID".to_string()) , Some("My Address Reference".to_string())),

        RecordField::new_record_field("phone".to_string(),json!({"region": "US", "number": "510-444-3333"}) , Some("My Phone Number".to_string())),

        RecordField::new_record_field("date".to_string(),Value::Number(Number::from(1641934793000i64)) , Some("My date".to_string())),

        RecordField::new_record_field("date".to_string(),Value::String("September eleventh two thousand and eleven".to_string()) , Some("Bad day in history of humanity".to_string())),

        RecordField::new_record_field("name".to_string(),json!({"first": "Lincoln", "last": "Adams"}) , Some("His Name".to_string())),
        ];

    // Here we are adding fields object to standard fields 
    created_record.fields = Some(fields);
    
    created_record.custom = Some(
        vec![
            RecordField::new_record_field("phone".to_string(),json!({"region": "US", "number": "510-222-5555", "ext": "99887", "type": "Mobile"}) , Some("My Custom Phone Lbl".to_string())),
        ]
    );
   
    // Make the API call
    let _ = secrets_manager.create_secret("Shared_folder_uid".to_string(), created_record)?;
    Ok(())
}
Parameter
Type
Required
Default
Description

record_type

DefaultRecordType

Yes

None

Type of record to be created

title

String

Yes

The title of the created record

note

String

Yes

None

The note to be made in the created record

value

String

Yes

Value for the field

label

String

Yes

None

Label for the field

required

bool

Yes

false

Defines if the field is required

privacy_screen

bool

Yes

false

Defines if the field value should be hidden

Returns

Type: String

The record UID of the new record

Delete A Secret

The Rust KSM SDK can delete records in the Keeper Vault.

secrets_manager.delete_secret(vec![record_uid]);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    // delete a specific secret by UID
    let secret_to_delete = secrets_manager.delete_secret(["<RECORD UID>".to_string()])?;
    Ok(())
}
Parameter
Type
Required
Default
Description

record_uid

String

Yes

None

The uid of the record to be deleted

Caching

To protect against losing access to your secrets when network access is lost, the Rust SDK allows caching of secrets to the local machine in an encrypted file.

Setup and Configure Cache

In order to setup caching in the Rust SDK, include a caching post function when creating a SecretsManager object.

The Rust SDK includes a default caching function in the KSMRCache class, which stores cached queries to a local file, thus serving as a disaster recovery function (as long as there's network connectivity, it always prefers network over cached data and will use cache only if the web vault is inaccessible).

use keeper_secrets_manager_core::{core::{ClientOptions, SecretsManager}, custom_error::KSMRError, storage::FileKeyValueStorage, cache::KSMRCache};
fn main()-> Result<(), KSMRError>{
    let cache = KSMRCache::new_file_cache(Some("./cache.bin"))?;

    let token = "<Token>".to_string();

    let file_name = FileKeyValueStorage::new_config_storage("test.json".to_string())?;
    
    let mut client_options = ClientOptions::new_client_options_with_token(token, file_name);
    client_options.set_cache(cache.into()); 
    
    let mut secrets_manager = SecretsManager::new(client_options)?;  
    let secrets = secrets_manager.get_secrets(Vec::new())?;
    for secret in secrets {
        info!("Secret: {}", secret);
    };
}

The default caching function in KSMCache class always stores last request only. For example, if the first request (R1) successfully retrieves UID1 and updates the cache, but a subsequent request (R2) for UID2 fails, the cache will not include UID2. As a result, any later operations involving UID2 (e.g., lookup or disconnect) will return an empty response, since it was never added to the cache.

Updating a record from cache (or creating new record) invalidates cached record data and consecutive updates of the same record will fail. Batch updates work as long as they modify different records. Always follow up cached record updates with a call to get_secrets function to refresh cache (and pull updated metadata from vault like the new record revision etc.)

Folders

Folders have full CRUD support—create, read, update, and delete operations.

Read Folders

Downloads full folder hierarchy.

get_folders()
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;
    
    // get all folder
    let secrets = secrets_manager.ger_folders()?;
    Ok(())
}

Returns

Type: Vec<KeeperFolder>

Create Folder

Requires CreateOptions and folder name to be provided. The folder UID parameter in CreateOptions is required—the UID of a shared folder, while sub-folder UID is optional, and if missing, a new regular folder is created directly under the parent (shared folder). There's no requirement for the sub-folder to be a direct descendant of the parent shared folder - it could be many levels deep.

create_folder(create_options: CreateOptions, folder_name: str, folders=None)
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    let parent_folder_uid: String = "<parent_folder_uid>".to_string();
    let sub_folder_uid: Option<String> = Option::Some((""));
    let create_options: CreateOptions = CreateOptions::new(parent_folder_uid, None);
    let new_folder_name: String = "Sample Folder 200".to_string();
    println!("Creating folder: {new_folder_name}");
    let created_folder_name = new_folder_name.clone();
    let result = secrets_manager.create_folder(create_options, new_folder_name, Vec::new())?;
    println!("Created folder {created_folder_name}");
    Ok(())
}
Parameter
Type
Required
Default
Description

create_options

CreateOptions

Yes

None

The parent and sub-folder UIDs

folder_name

str

Yes

The folder name

folders

Vec<KeeperFolder>

No

None

List of folders to use in the search for parent and sub-folder from CreateOptions

Update Folder

Updates the folder metadata—currently folder name only.

secrets_manager.update_folder(folder_uid: str, folder_name: str, folders=None)
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::InMemoryKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;

    let update_folder = secrets_manager.update_folder("<folder_uid>".to_string(),"dummy_updated_API_RUST".to_string(),Vec::new())?;
    println!("{}",(serde_json::to_string_pretty(&update_folder)?));
    Ok(())
}
Parameter
Type
Required
Default
Description

folder_uid

str

Yes

The folder uid

folder_name

str

Yes

The new folder name

folders

Vec<KeeperFolder>

No

None

List of folders to use in the search for parent folder

Delete Folders

Removes a list of folders. Use the force_deletion flag to remove non-empty folders.

Any folders UIDs missing from the vault or not shared to the KSM Application will not result in error.

When using force_deletion avoid sending parent with its children folder UIDs. Depending on the delete order you may get an error - ex. if parent force-deleted child first. There's no guarantee that list will always be processed in FIFO order.

delete_folder(vec![“<FOLDER_UID>”.to_string()], false);
use keeper_secrets_manager_core::{
    core::{ClientOptions, SecretsManager},
    storage::FileKeyValueStorage,
    custom_error::KSMRError
};
fn main()-> Result<(), KSMRError>{
    // setup secrets manager
    let config_string = "your_base64_goes_here".to_string();
    let config = InMemoryKeyValueStorage::new_config_storage(Some(config_string))?;
    let client_options = ClientOptions::new_client_options(config);
    let mut secrets_manager = SecretsManager::new(client_options)?;
    
    let folder_uids = vec!["folder1_uid".to_string(),"folder_2_uid".to_string()];
    secrets_manager.delete_folder(folder_uids, true)?;
    Ok(())
}
Parameter
Type
Required
Default
Description

folder_uids

Vec<String>

Yes

The folder UID list

force_deletion

boolean

No

false

Force deletion of non-empty folders

Record Field Classes

Description of each accessible field type Class in the Keeper Secrets Manager Java SDK

Accessing Record Fields

Use the getField function to access record fields.

secret.data.getfield<FIELD_TYPE>()

The 'FIELD_TYPE' needs to be a class from the list below.

Field Type Classes Reference

KeeperRecordField

All Record Fields extend the KeeperRecordField class, and contain a lbl field

sealed class KeeperRecordField(val lbl: String? = null)

Field Values

Name

Type

Required

Default

lbl

String

No

null

Password

data class Password(
    var label: String? = null,
    var required: Boolean? = null,
    var privacyScreen: Boolean? = null,
    var enforceGeneration: Boolean? = null,
    var complexity: PasswordComplexity? = null,
    val value: MutableList<String>
)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

enforceGeneration

Boolean

No

null

value

MutableList<String>

Yes

Url

data class Url(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

FileRef

data class FileRef(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

value

MutableList<String>

Yes

OneTimeCode

data class OneTimeCode(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

value

MutableList<String>

Yes

OneTimePassword

data class OneTimePassword(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

value

MutableList<String>

Yes

Name

data class Name(var first: String? = null, var middle: String? = null, var last: String? = null)

Field Values

Name

Type

Required

Default

first

String

No

null

middle

String

No

null

last

String

No

null

Names

data class Names(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Name>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Name>

Yes

BirthDate

data class BirthDate(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Long>

Yes

Date

data class Date(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Long>

Yes

ExpirationDate

data class ExpirationDate(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Long>

Yes

Text

data class Text(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, var value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

SecurityQuestion

data class SecurityQuestion(var question: String? = null, var answer: String? = null)

Field Values

Name

Type

Required

Default

question

String

No

null

answer

String

No

null

SecurityQuestions

data class SecurityQuestions(
    var label: String? = null,
    var required: Boolean? = null,
    var privacyScreen: Boolean? = null,
    val value: MutableList<SecurityQuestion>
)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<SecurityQuestion>

Yes

Multiline

data class Multiline(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

Email

data class Email(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

CardRef

data class CardRef(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

AddressRef

data class AddressRef(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

PinCode

data class PinCode(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

Label

String

No

null

required

Boolean

No

null

value

MutableList<String>

Yes

Phone

data class Phone(
    val region: String? = null,
    val number: String? = null,
    val ext: String? = null,
    val type: String? = null
)

Field Values

Name

Type

Required

Default

region

String

No

null

number

String

No

null

ext

String

No

null

type

String

No

null

Phones

data class Phones(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<Phone>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

List<Phone>

Yes

HiddenField

data class HiddenField(val label: String? = null, var required: Boolean? = null, val value: List<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

value

List<String>

Yes

SecureNote

data class SecureNote(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

List<String>

Yes

AccountNumber

data class AccountNumber(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

List<String>

Yes

PaymentCard

data class PaymentCard(
    var cardNumber: String? = null,
    var cardExpirationDate: String? = null,
    var cardSecurityCode: String? = null
)

Field Values

Name

Type

Required

Default

cardNumber

String

No

null

cardExpirationDate

String

No

null

cardSecurityCode

String

No

null

PaymentCards

data class PaymentCards(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<PaymentCard>) :

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<PaymentCard>)

Yes

BankAccount

data class BankAccount(
    var accountType: String? = null,
    var routingNumber: String? = null,
    var accountNumber: String? = null,
    var otherType: String? = null
)

Field Values

Name

Type

Required

Default

accountType

String

No

null

routingNumber

String

No

null

accountNumber

String

No

null

otherType

String

No

null

BankAccounts

data class BankAccounts(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<BankAccount>) :

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<BankAccount>)

Yes

KeyPair

data class KeyPair(
    val publicKey: String? = null,
    val privateKey: String? = null,
)

Field Values

Name

Type

Required

Default

publicKey

String

no

null

privateKey

String

no

null

KeyPairs

data class KeyPairs(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<KeyPair>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<KeyPair>

Yes

Host

data class Host(
    val hostName: String? = null,
    val port: String? = null,
)

Field Values

Name

Type

Required

Default

hostName

String

No

null

port

String

No

null

Hosts

data class Hosts(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Host>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Host>

Yes

Address

data class Address(
    val street1: String? = null,
    val street2: String? = null,
    val city: String? = null,
    val state: String? = null,
    val country: String? = null,
    val zip: String? = null
)

Field Values

Name

Type

Required

Default

street1

String

No

null

street2

String

No

null

city

String

No

null

state

String

No

null

county

String

No

null

zip

String

No

null

Addresses

data class Addresses(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Address>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<Address>

Yes

LicenseNumber

data class LicenseNumber(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)

Field Values

Name

Type

Required

Default

label

String

No

null

required

Boolean

No

null

privacyScreen

Boolean

No

null

value

MutableList<String>

Yes

KeeperFileData

data class KeeperFileData(
    val title: String,
    val name: String,
    val type: String,
    val size: Long,
    val lastModified: Long
)

Field Values

Name

Type

Required

Default

title

String

Yes

name

String

Yes

type

String

Yes

size

Long

Yes

lastModified

Long

Yes

Record Field Classes

Description of each accessible field type Class in the Keeper Secrets Manager Go SDK

Accessing Record Fields

Use the GetFieldByType function to access record fields.

loginField, ok := secret.GetFieldByType(ksm.Login{}).(*ksm.Login)

Field Type Classes Reference

KeeperRecordField

All Record Fields extend the KeeperRecordField class, and contain a Label and Type fields

type KeeperRecordField struct {
	Type  string `json:"type"`
	Label string `json:"label,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Type

string

Yes

""

Password

type Password struct {
	KeeperRecordField
	Required          bool               `json:"required,omitempty"`
	PrivacyScreen     bool               `json:"privacyScreen,omitempty"`
	EnforceGeneration bool               `json:"enforceGeneration,omitempty"`
	Complexity        PasswordComplexity `json:"complexity,omitempty"`
	Value             []string           `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

EnforceGeneration

bool

No

false

Value

[]string

Yes

Url

type Url struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

FileRef

type FileRef struct {
	KeeperRecordField
	Required bool     `json:"required,omitempty"`
	Value    []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

Value

[]string

Yes

OneTimeCode

type OneTimeCode struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

Name

type Name struct {
	First  string `json:"first,omitempty"`
	Middle string `json:"middle,omitempty"`
	Last   string `json:"last,omitempty"`
}

Field Values

Name

Type

Required

Default

First

string

No

""

Middle

string

No

""

Last

string

No

""

Names

type Names struct {
	KeeperRecordField
	Required      bool   `json:"required,omitempty"`
	PrivacyScreen bool   `json:"privacyScreen,omitempty"`
	Value         []Name `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]Name

Yes

BirthDate

type BirthDate struct {
	KeeperRecordField
	Required      bool    `json:"required,omitempty"`
	PrivacyScreen bool    `json:"privacyScreen,omitempty"`
	Value         []int64 `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]int64

Yes

Date

type Date struct {
	KeeperRecordField
	Required      bool    `json:"required,omitempty"`
	PrivacyScreen bool    `json:"privacyScreen,omitempty"`
	Value         []int64 `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]int64

Yes

ExpirationDate

type ExpirationDate struct {
	KeeperRecordField
	Required      bool    `json:"required,omitempty"`
	PrivacyScreen bool    `json:"privacyScreen,omitempty"`
	Value         []int64 `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]int64

Yes

Text

type Text struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

SecurityQuestion

type SecurityQuestion struct {
	Question string `json:"question,omitempty"`
	Answer   string `json:"answer,omitempty"`
}

Field Values

Name

Type

Required

Default

Question

string

No

""

Answer

string

No

""

SecurityQuestions

type SecurityQuestions struct {
	KeeperRecordField
	Required      bool               `json:"required,omitempty"`
	PrivacyScreen bool               `json:"privacyScreen,omitempty"`
	Value         []SecurityQuestion `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]SecurityQuestion

Yes

Multiline

type Multiline struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

Email

type Email struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

CardRef

type CardRef struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

AddressRef

type AddressRef struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

PinCode

type PinCode struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

Phone

type Phone struct {
	Region string `json:"region,omitempty"`
	Number string `json:"number,omitempty"`
	Ext    string `json:"ext,omitempty"`
	Type   string `json:"type,omitempty"`
}

Field Values

Name

Type

Required

Default

Region

string

No

""

Number

string

No

""

Ext

string

No

""

Type

string

No

""

Phones

type Phones struct {
	KeeperRecordField
	Required      bool    `json:"required,omitempty"`
	PrivacyScreen bool    `json:"privacyScreen,omitempty"`
	Value         []Phone `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]Phone

Yes

Secret

type Secret struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

SecureNote

type SecureNote struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

AccountNumber

type AccountNumber struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

PaymentCard

type PaymentCard struct {
	CardNumber         string `json:"cardNumber,omitempty"`
	CardExpirationDate string `json:"cardExpirationDate,omitempty"`
	CardSecurityCode   string `json:"cardSecurityCode,omitempty"`
}

Field Values

Name

Type

Required

Default

CardNumber

string

No

""

CardExpirationDate

string

No

""

CardSecurityCode

string

No

""

PaymentCards

type PaymentCards struct {
	KeeperRecordField
	Required      bool          `json:"required,omitempty"`
	PrivacyScreen bool          `json:"privacyScreen,omitempty"`
	Value         []PaymentCard `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]PaymentCard

Yes

BankAccount

type BankAccount struct {
	AccountType   string `json:"accountType,omitempty"`
	RoutingNumber string `json:"routingNumber,omitempty"`
	AccountNumber string `json:"accountNumber,omitempty"`
	OtherType     string `json:"otherType,omitempty"`
}

Field Values

Name

Type

Required

Default

AccountType

string

No

""

RoutingNumber

string

No

""

AccountNumber

string

No

""

OtherType

string

No

""

BankAccounts

type BankAccounts struct {
	KeeperRecordField
	Required      bool          `json:"required,omitempty"`
	PrivacyScreen bool          `json:"privacyScreen,omitempty"`
	Value         []BankAccount `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]BankAccount

Yes

KeyPair

type KeyPair struct {
	PublicKey  string `json:"publicKey,omitempty"`
	PrivateKey string `json:"privateKey,omitempty"`
}

Name

Type

Required

Default

PublicKey

string

No

""

PrivateKey

string

No

""

KeyPairs

type KeyPairs struct {
	KeeperRecordField
	Required      bool      `json:"required,omitempty"`
	PrivacyScreen bool      `json:"privacyScreen,omitempty"`
	Value         []KeyPair `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]KeyPair

Yes

Host

type Host struct {
	Hostname string `json:"hostName,omitempty"`
	Port     string `json:"port,omitempty"`
}

Field Values

Name

Type

Required

Default

Hostname

string

No

""

Port

string

No

""

Hosts

type Hosts struct {
	KeeperRecordField
	Required      bool   `json:"required,omitempty"`
	PrivacyScreen bool   `json:"privacyScreen,omitempty"`
	Value         []Host `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]Host

Yes

Address

type Address struct {
	Street1 string `json:"street1,omitempty"`
	Street2 string `json:"street2,omitempty"`
	City    string `json:"city,omitempty"`
	State   string `json:"state,omitempty"`
	Country string `json:"country,omitempty"`
	Zip     string `json:"zip,omitempty"`
}

Field Values

Name

Type

Required

Default

Street1

string

No

""

Street2

string

No

""

City

string

No

""

State

string

No

""

Country

string

No

""

Zip

string

No

""

Addresses

type Addresses struct {
	KeeperRecordField
	Required      bool      `json:"required,omitempty"`
	PrivacyScreen bool      `json:"privacyScreen,omitempty"`
	Value         []Address `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]Address

Yes

LicenseNumber

type LicenseNumber struct {
	KeeperRecordField
	Required      bool     `json:"required,omitempty"`
	PrivacyScreen bool     `json:"privacyScreen,omitempty"`
	Value         []string `json:"value,omitempty"`
}

Field Values

Name

Type

Required

Default

Label

string

No

""

Required

bool

No

false

PrivacyScreen

bool

No

false

Value

[]string

Yes

KeeperFileData

type KeeperFileData struct {
	Title        string `json:"title,omitempty"`
	Name         string `json:"name,omitempty"`
	Type         string `json:"type,omitempty"`
	Size         int64  `json:"size,omitempty"`
	LastModified int64  `json:"lastModified,omitempty"`
}

Field Values

Name

Type

Required

Default

Title

string

Yes

Name

string

Yes

Type

string

Yes

Size

int64

Yes

LastModified

int64

Yes

Record Type
documentation
Record Types
Record Types
documentation
Record Type
documentation
Record Type
Record Types
documentation
Record Type
documentation
Record Type