Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Sample code and SDK integration instructions for Keeper Secrets Manager
The Keeper Secrets Manager SDKs are purpose-built to provide extremely simple, fast and efficient access to Secrets Management functionality from all popular languages.
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-ipAfter 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:
{
"hostname": "keepersecurity.com",
"clientId": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"privateKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"serverPublicKeyId": "10",
"appKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"appOwnerPublicKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
}For more information on configuration files, see the Config File documentation.
Keeper provides several options for the secure encryption and storage of the KSM configuration file using popular cloud services:
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
For higher level functionality at the Vault and Administrative level, please see the Vault SDKs page which contains links to various development tools.

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.
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
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
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
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.
The Keeper GoLang SDK is used specifically in our Terraform provider.
PowerShell docs for Keeper Secrets Manager
Detailed Python SDK docs for Keeper Secrets Manager
pip3 install -U keeper-secrets-manager-coreFind the Python source code in the GitHub repository
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
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
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)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.
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.
# 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")record_title
String
Yes
Record title to search for
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')Parameter
Type
Required
Default
Description
query
String
Yes
Keeper Notation query for getting a value from a specified field
Type: string or string[]
The value of the queried field
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
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.
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
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_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)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.
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 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
owner_record
KeeperRecord
Yes
The record to attach the uploaded file to
file
KeeperFileUpload
Yes
The File to upload
Keeper File Upload From File
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
Type: string
The file UID of the attached file
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)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)create_options
CreateOptions
Yes
record
KeeperRecord
Yes
This example creates a login type record with a login value and a generated password.
# 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.
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)Type: string
The record UID of the new record
The Python KSM SDK can delete records in the Keeper Vault.
secrets_manager.delete_secret(record_uid)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')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.)
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_rsThen 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 have full CRUD support - create, read, update and delete operations.
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()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)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")Updates the folder metadata - currently folder name only.
update_folder(folder_uid: str, folder_name: str, folders=None)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")Removes a list of folders. Use force_deletion flag to remove non-empty folders.
delete_folder(folder_uids: List[str], force_deletion: bool = False)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)Keeper Secrets Manager SDK uses the requests library to support the HTTPS_PROXY environment variable by default
HTTPS_PROXY=https://yourproxy:8888 python main.pyEvery request including Keeper Secrets Manager requests will go through declared proxy
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"
)https://username:pass@yourproxy:8888
Detailed Java and Kotlin SDK docs for Keeper Secrets Manager
repositories {
mavenCentral()
}
dependencies {
implementation 'com.keepersecurity.secrets-manager:core:17.1.2+'
implementation("org.bouncycastle:bc-fips:1.0.2.4")
}<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>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.
Find the Java/Kotlin source code in the GitHub repository
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
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());
}getSecrets(options: SecretsManagerOptions, recordsFilter: List<String> = emptyList()): KeeperSecretsParameter
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();// get all matching records
getSecretsByTitle(recordTitle: String): List<KeeperRecord>
// get only the first matching record
getSecretByTitle(recordTitle: String): KeeperRecordrecordTitle
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());
}
}
}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()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");Parameter
Type
Required
Default
Description
secret
KeeperRecord
Yes
Record to get field value from
query
String
Yes
Dot notation query of desired field
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
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.
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);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.
SecretsManager.downloadFile(file): ByteArrayimport 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
SecretsManager.downloadThumbnail(file): ByteArrayimport 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 File:
uploadFile(options: SecretsManagerOptions, ownerRecord: KeeperRecord, file: KeeperFileUpload): Stringoptions
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
)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());
}
}
}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
options
SecretsManagerOptions
Yes
Preconfigured options
record
KeeperRecord
Yes
The record to update
updateOptions
UpdateOptions
Yes
Options containing files to remove
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);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);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);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.
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.
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);The Java/Kotlin KSM SDK can delete records in the Keeper Vault.
deleteSecret(smOptions, recordUids);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"));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 have full CRUD support - create, read, update and delete operations.
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);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)): Stringoptions
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");Updates the folder metadata - currently folder name only.
updateFolder(options: SecretsManagerOptions, folderUid: String, folderName: String, folders: List<KeeperFolder> = getFolders(options))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");Removes a list of folders. Use forceDeletion flag to remove non-empty folders.
deleteFolder(options: SecretsManagerOptions, folderUids: List<String>, forceDeletion: Boolean = false): SecretsManagerDeleteResponseoptions
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);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
options
SecretsManagerOptions
Yes
Preconfigured options
queryOptions
QueryOptions
Yes
Must set requestLinks=true
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
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());
}
}
}
}
}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.
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:
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);
}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());
}
}
}
}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");
}
}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.");
}
}
}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") + "]";
}
}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");
}
}
}
}
}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");
}
}
}
}
}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
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
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);
}
}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();
}
}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
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
Only request links when needed - Use requestLinks=true judiciously for performance
Filter records when possible - Use recordsFilter to limit data retrieval
Cache results - Build lookup maps for multiple operations on the same data
Handle errors gracefully - Link data decryption and access may fail
Validate assumptions - Check link properties match expected permissions
Test configurations - Verify PAM setups have correct admin/launch credential counts
// 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")
}
}
}
}
}Detailed Javascript SDK docs for Keeper Secrets Manager
Find the JavaScript source code in the
In order to retrieve secrets, you must first initialize the local storage on your machine.
Response
Type: KeeperSecrets
Object containing all Keeper records, or records that match the given filter criteria
Example Usage
Retrieve all Secrets
Example Usage
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
* 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
Type: any
The value of the field at the location specified by the dot notation query if any, otherwise undefined.
* 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
Type: any
The value of the field at the location specified by the dot notation query if any, otherwise undefined.
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>
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.
Type: String
Response
Type: Promise<Uint8Array
Bytes of file for download
Response
Type: Promise<Uint8Array>
Bytes of thumbnail for download
Upload File:
Creating the Keeper File Upload Object:
Example Usage
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
This example creates a login type record with a login value and a generated password.
This example creates a record with a custom record type.
The JavaScript KSM SDK can delete records in the Keeper Vault.
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 have full CRUD support - create, read, update and delete operations.
Downloads full folder hierarchy.
Response
Type: KeeperFolder[]
Example Usage
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.
Example Usage
Updates the folder metadata - currently folder name only.
Example Usage
Removes a list of folders. Use forceDeletion flag to remove non-empty folders.
Example Usage
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-coreinitializeStorage(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()): KeeperSecretsParameter
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): anyconst {
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): stringconst {
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): ByteArrayParameter
Type
Required
Default
Description
file
KeeperFile
Yes
File to download
downloadThumbnail(file: KeeperFile): ByteArrayParameter
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)
}Detailed Go SDK docs for Keeper Secrets Manager
Find the latest Go SDK release at: https://github.com/Keeper-Security/secrets-manager-go
$ go get github.com/keeper-security/secrets-manager-go/coreFind the Go source code in the GitHub repository
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)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]"})
}// get all matching records
GetSecretsByTitle(recordTitle string) (records []*Record, err error)
// get only the first matching record
GetSecretByTitle(recordTitle string) (records *Record, err error)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 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.
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")
}
}Parameter
Type
Required
Default
Description
query
String
Yes
Keeper Notation query for getting a value from a specified field
Type: []interface{}
The value of the queried field
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
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.
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)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.
(r *Record) DownloadFileByTitle(title string, path string) boolParameter
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")UploadFile(record *Record, file *KeeperFileUpload) (uid string, err error)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
}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)
}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)recordUid
string
No
auto generated random UID
folderUid
string
Yes
record
*RecordCreate
Yes
secretsManager.CreateSecretWithRecordDataAndOptions(createOptions, recordData, folders)createOptions
CreateOptions
Yes
recordData
*RecordCreate
Yes
folders
[]*KeeperFolder
No
This example creates a login type record with a login value and a generated password.
// 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)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)The Go KSM SDK can delete records in the Keeper Vault.
secretsManager.DeleteSecrets(recordUids)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"})
}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 have full CRUD support - create, read, update and delete operations.
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()
}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)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)
}Updates the folder metadata - currently folder name only.
UpdateFolder(folderUid, folderName string, folders []*KeeperFolder) (err error)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)
}Removes a list of folders. Use forceDeletion flag to remove non-empty folders.
DeleteFolder(folderUids []string, forceDeletion bool) (statuses map[string]string, err error)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)
}Detailed Ruby SDK docs for Keeper Secrets Manager
The Ruby SDK supports Ruby version 3.1 and above. For more information, see:
https://rubygems.org/gems/keeper_secrets_manager
gem install keeper_secrets_manager -v 17.1.0gem 'keeper_secrets_manager', '~> 17.1'Then run:
bundle installFind the Ruby source code in the GitHub repository
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)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.
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 trueFor 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)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)get_secrets(uids = [])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.
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})"
endRetrieve 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 all secrets matching title
get_secrets_by_title(title)
# Get first secret matching title
get_secret_by_title(title)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.
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}"Once a secret is retrieved, individual fields can be accessed using multiple approaches:
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# 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')# 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")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']
)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.
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
base32gem for decoding the secret. Install withgem install base32.
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
)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
SecureRandomfor cryptographic-strength randomness and applies Fisher-Yates shuffle to ensure proper character distribution.
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}"
endupdate_secret(record)record
KeeperRecord
Yes
-
The modified record to update in the vault
Response:
Type: void
Updates the secret in the vault with the modified values.
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_file(file)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
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']}"
endupload_file(owner_record_uid, file_data, file_name, file_title = nil)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.
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_secret(record_data, options = nil)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)
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 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_secret(uids)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.
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"The Ruby SDK provides full CRUD support for folder operations.
get_foldersResponse:
Type: Array<KeeperFolder>
Returns all folders accessible to the Secrets Manager application.
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})"
endget_folder_path(folder_uid)folder_uid
String
Yes
-
UID of the folder
Response:
Type: String
Returns the full path to the folder (breadcrumb trail separated by "/").
# Get folder path (breadcrumb trail)
path = secrets_manager.get_folder_path('FOLDER_UID')
puts "Folder path: #{path}" # "Parent/Child/Grandchild"find_folder_by_name(name, parent_uid: nil)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.
# 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')# 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_folder(name, parent_uid:)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.
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_folder(folder_uid, new_name)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.
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_folder(folder_uid, force: false)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.
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)
endImprove performance by caching secrets locally:
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 dataFor 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
)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# 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
endrequire '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
)require 'keeper_secrets_manager'
secrets_manager = KeeperSecretsManager.new(
config: storage,
verify_ssl_certs: true # Default is true
)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
)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
)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)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(', ')}"
endDetailed .Net SDK docs for Keeper Secrets Manager
dotnet add package Keeper.SecretsManager
Find the .Net source code in the GitHub repository
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
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);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
GetSecrets(options: SecretsManagerOptions, recordsFilter: List<String> = emptyList()): KeeperSecretsParameter
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);// 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)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 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");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
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.
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
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);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.
DownloadFile(file: KeeperFile): ByteArrayParameter
Type
Required
Default
Description
file
KeeperFile
Yes
File to download
Response
Type: ByteArray
ByteArray of file for download
DownloadThumbnail(file: KeeperFile): ByteArrayParameter
Type
Required
Default
Description
file
KeeperFile
Yes
File with thumbnail to download
Response
Type: ByteArray
ByteArray of thumbnail for download
Upload File:
UploadFile(SecretsManagerOptions options, KeeperRecord ownerRecord, KeeperFileUpload file)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)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);
}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)options
SecretsManagerOptions
Yes
folderUid
string
Yes
record
KeeperRecordData
Yes
SecretsManagerClient.CreateSecret2(options, createOptions, record, folders)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.
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.
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);
The .Net KSM SDK can delete records in the Keeper Vault.
DeleteSecret(smOptions, recordsUids);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"});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 have full CRUD support - create, read, update and delete operations.
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);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)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");Updates the folder metadata - currently folder name only.
Task UpdateFolder(SecretsManagerOptions options, string folderUid, string folderName, KeeperFolder[] folders = null)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");Removes a list of folders. Use forceDeletion flag to remove non-empty folders.
Task DeleteFolder(SecretsManagerOptions options, string[] folderUids, bool forceDeletion = false)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);.NET SDK supports setting proxy through environment variables and passing proxy url to SecretsManagerOptions directly
Example usage through environment variables
HTTPS_PROXY=http://user:[email protected]:3128 dotnet runExample usage passing url to SecretsManagerOptions
var options = new SecretsManagerOptions(storage, null, false, "http://user:[email protected]:3128");Detailed Rust SDK docs for Keeper Secrets Manager
cargo add keeper-secrets-manager-coreFind the Rust source code in the GitHub repository
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
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
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(())
}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(())
}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.
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(())
}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:
StringorVec<String>
the value or values of the field. It will be a single value only if the single=true option is passed.
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>>>
record_title
&str
Yes
Title of the record to be fetched
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
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>
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>
url
String
Yes
TOTP Url
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(())
}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.
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(())
}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.
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(())
}field_type
String
Yes
Field type to get
transaction_type
UpdateTransactionType
Yes
None
Configuration for transactional update
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(())
}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_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(())
}file_name
&str
Yes
Name of the file to be downloaded
path
&str
Yes
Path to download 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
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
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
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(())
}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
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(())
}record_uid
String
Yes
None
The uid of the record to be deleted
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 have full CRUD support—create, read, update, and delete operations.
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>
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(())
}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
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(())
}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
Removes a list of folders. Use the force_deletion flag to remove non-empty folders.
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(())
}folder_uids
Vec<String>
Yes
The folder UID list
force_deletion
boolean
No
false
Force deletion of non-empty folders
Description of each accessible field type Class in the Keeper Secrets Manager Java SDK
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.
All Record Fields extend the KeeperRecordField class, and contain a lbl field
sealed class KeeperRecordField(val lbl: String? = null)Name
Type
Required
Default
lbl
String
No
null
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>
)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
enforceGeneration
Boolean
No
null
value
MutableList<String>
Yes
data class Url(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class FileRef(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
value
MutableList<String>
Yes
data class OneTimeCode(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
value
MutableList<String>
Yes
data class OneTimePassword(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
value
MutableList<String>
Yes
data class Name(var first: String? = null, var middle: String? = null, var last: String? = null)Name
Type
Required
Default
first
String
No
null
middle
String
No
null
last
String
No
null
data class Names(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Name>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Name>
Yes
data class BirthDate(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Long>
Yes
data class Date(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Long>
Yes
data class ExpirationDate(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Long>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Long>
Yes
data class Text(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, var value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class SecurityQuestion(var question: String? = null, var answer: String? = null)Name
Type
Required
Default
question
String
No
null
answer
String
No
null
data class SecurityQuestions(
var label: String? = null,
var required: Boolean? = null,
var privacyScreen: Boolean? = null,
val value: MutableList<SecurityQuestion>
)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<SecurityQuestion>
Yes
data class Multiline(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class Email(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class CardRef(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class AddressRef(var label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class PinCode(var label: String? = null, var required: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
Label
String
No
null
required
Boolean
No
null
value
MutableList<String>
Yes
data class Phone(
val region: String? = null,
val number: String? = null,
val ext: String? = null,
val type: String? = null
)Name
Type
Required
Default
region
String
No
null
number
String
No
null
ext
String
No
null
type
String
No
null
data class Phones(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<Phone>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
List<Phone>
Yes
data class HiddenField(val label: String? = null, var required: Boolean? = null, val value: List<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
value
List<String>
Yes
data class SecureNote(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
List<String>
Yes
data class AccountNumber(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: List<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
List<String>
Yes
data class PaymentCard(
var cardNumber: String? = null,
var cardExpirationDate: String? = null,
var cardSecurityCode: String? = null
)Name
Type
Required
Default
cardNumber
String
No
null
cardExpirationDate
String
No
null
cardSecurityCode
String
No
null
data class PaymentCards(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<PaymentCard>) :Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<PaymentCard>)
Yes
data class BankAccount(
var accountType: String? = null,
var routingNumber: String? = null,
var accountNumber: String? = null,
var otherType: String? = null
)Name
Type
Required
Default
accountType
String
No
null
routingNumber
String
No
null
accountNumber
String
No
null
otherType
String
No
null
data class BankAccounts(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<BankAccount>) :Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<BankAccount>)
Yes
data class KeyPair(
val publicKey: String? = null,
val privateKey: String? = null,
)Name
Type
Required
Default
publicKey
String
no
null
privateKey
String
no
null
data class KeyPairs(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<KeyPair>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<KeyPair>
Yes
data class Host(
val hostName: String? = null,
val port: String? = null,
)
Name
Type
Required
Default
hostName
String
No
null
port
String
No
null
data class Hosts(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Host>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Host>
Yes
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
)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
data class Addresses(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<Address>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<Address>
Yes
data class LicenseNumber(val label: String? = null, var required: Boolean? = null, var privacyScreen: Boolean? = null, val value: MutableList<String>)Name
Type
Required
Default
label
String
No
null
required
Boolean
No
null
privacyScreen
Boolean
No
null
value
MutableList<String>
Yes
data class KeeperFileData(
val title: String,
val name: String,
val type: String,
val size: Long,
val lastModified: Long
)Name
Type
Required
Default
title
String
Yes
name
String
Yes
type
String
Yes
size
Long
Yes
lastModified
Long
Yes
Description of each accessible field type Class in the Keeper Secrets Manager Go SDK
Use the GetFieldByType function to access record fields.
loginField, ok := secret.GetFieldByType(ksm.Login{}).(*ksm.Login)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"`
}Name
Type
Required
Default
Label
string
No
""
Type
string
Yes
""
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"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
EnforceGeneration
bool
No
false
Value
[]string
Yes
type Url struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type FileRef struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
Value
[]string
Yes
type OneTimeCode struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type Name struct {
First string `json:"first,omitempty"`
Middle string `json:"middle,omitempty"`
Last string `json:"last,omitempty"`
}Name
Type
Required
Default
First
string
No
""
Middle
string
No
""
Last
string
No
""
type Names struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []Name `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]Name
Yes
type BirthDate struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []int64 `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]int64
Yes
type Date struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []int64 `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]int64
Yes
type ExpirationDate struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []int64 `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]int64
Yes
type Text struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type SecurityQuestion struct {
Question string `json:"question,omitempty"`
Answer string `json:"answer,omitempty"`
}Name
Type
Required
Default
Question
string
No
""
Answer
string
No
""
type SecurityQuestions struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []SecurityQuestion `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]SecurityQuestion
Yes
type Multiline struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type Email struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type CardRef struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type AddressRef struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type PinCode struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type Phone struct {
Region string `json:"region,omitempty"`
Number string `json:"number,omitempty"`
Ext string `json:"ext,omitempty"`
Type string `json:"type,omitempty"`
}Name
Type
Required
Default
Region
string
No
""
Number
string
No
""
Ext
string
No
""
Type
string
No
""
type Phones struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []Phone `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]Phone
Yes
type Secret struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type SecureNote struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type AccountNumber struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
type PaymentCard struct {
CardNumber string `json:"cardNumber,omitempty"`
CardExpirationDate string `json:"cardExpirationDate,omitempty"`
CardSecurityCode string `json:"cardSecurityCode,omitempty"`
}Name
Type
Required
Default
CardNumber
string
No
""
CardExpirationDate
string
No
""
CardSecurityCode
string
No
""
type PaymentCards struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []PaymentCard `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]PaymentCard
Yes
type BankAccount struct {
AccountType string `json:"accountType,omitempty"`
RoutingNumber string `json:"routingNumber,omitempty"`
AccountNumber string `json:"accountNumber,omitempty"`
OtherType string `json:"otherType,omitempty"`
}Name
Type
Required
Default
AccountType
string
No
""
RoutingNumber
string
No
""
AccountNumber
string
No
""
OtherType
string
No
""
type BankAccounts struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []BankAccount `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]BankAccount
Yes
type KeyPair struct {
PublicKey string `json:"publicKey,omitempty"`
PrivateKey string `json:"privateKey,omitempty"`
}Name
Type
Required
Default
PublicKey
string
No
""
PrivateKey
string
No
""
type KeyPairs struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []KeyPair `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]KeyPair
Yes
type Host struct {
Hostname string `json:"hostName,omitempty"`
Port string `json:"port,omitempty"`
}Name
Type
Required
Default
Hostname
string
No
""
Port
string
No
""
type Hosts struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []Host `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]Host
Yes
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"`
}Name
Type
Required
Default
Street1
string
No
""
Street2
string
No
""
City
string
No
""
State
string
No
""
Country
string
No
""
Zip
string
No
""
type Addresses struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []Address `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]Address
Yes
type LicenseNumber struct {
KeeperRecordField
Required bool `json:"required,omitempty"`
PrivacyScreen bool `json:"privacyScreen,omitempty"`
Value []string `json:"value,omitempty"`
}Name
Type
Required
Default
Label
string
No
""
Required
bool
No
false
PrivacyScreen
bool
No
false
Value
[]string
Yes
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"`
}Name
Type
Required
Default
Title
string
Yes
Name
string
Yes
Type
string
Yes
Size
int64
Yes
LastModified
int64
Yes