buildfire.services.keyStore
The Key Store service provides a secure flow for creating, recovering, and changing user PIN codes, as well as generating and managing encrypted key pairs. The private key is never stored on Buildfire servers; instead, it is generated on-device and encrypted using a PIN-selected key before being uploaded.
Use this service to implement:
- End-to-end encrypted user data
- PIN-protected user flows
- Secure key pair generation
- Recovery of existing encrypted keys when switching devices
- PIN reset flows that generate a fresh key pair
The Key Store service is not available on HTTP domains.
Use HTTPS, the Buildfire Previewer, or production app builds.
How the Key Store Works (Architectural Overview)
Before using the methods, it's important to understand the underlying model:
Private Key
- Generated on the user device.
- Never stored on the server.
- Must be stored locally by the developer.
Encrypted Private Key
- The private key is encrypted with a key derived from the user's PIN.
- Stored on the Buildfire server.
- Only recoverable with the correct PIN.
- Wrong PIN = cannot decrypt.
Public Key
- Stored on the server and retrievable anytime.
- Not sensitive.
PIN and Recovery Behavior
- PIN ≠ password — it's a key used to decrypt the encrypted private key.
- Buildfire does not know the PIN and cannot recover it.
- If the user resets the PIN → a brand new key pair is generated.
- Old encrypted content becomes permanently unreadable.
Requirements
Widget
Include keyStore.js right after buildfire.min.js
<head>
<!-- ... -->
<script src="../../../scripts/buildfire.min.js"></script>
<script src="../../../scripts/buildfire/services/keyStore/keyStore.js"></script>
</head>
Methods
initiateSetup(options, callback)
Begins the PIN creation and key pair setup flow.
After completion, developers must store the returned privateKey locally.
To check whether the user already has a Key Store entry, call
buildfire.services.keyStore.get() with the default key.
buildfire.services.keyStore.initiateSetup(
{
allowCancel: true,
translations: {
screens: {
introView: { title: 'Enable Encryption' }
},
errorMessages: {
mismatchMessage: 'PIN codes don’t match.'
}
}
},
(err, result) => {
if (err) return console.error(err);
console.log('Setup complete', result);
}
);
Options
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
allowCancel | boolean | no | Shows a cancel button. | false |
translations | object | no | Overrides UI text. | — |
Translations
The translations object is structured as follows:
translations: {
screens: {
introView: { /* ... */ },
entryPinView: { /* ... */ },
entryConfirmView: { /* ... */ }
},
errorMessages: { /* ... */ }
}
screens
introView
| Name | Type | Default |
|---|---|---|
title | string | "Enable Encryption" |
description | string | "End-to-end encryption keeps your data private..." |
infoNote | string | "If you lose or reset your PIN, you'll lose access..." |
primaryButtonText | string | "Create PIN" |
entryPinView
| Name | Type | Default |
|---|---|---|
title | string | "Enter 6-digit PIN" |
description | string | "Create a 6-digit PIN to protect your encrypted data..." |
hintText | string | "Avoid simple combinations like 123456" |
primaryButtonText | string | "Create PIN" |
entryConfirmView
| Name | Type | Default |
|---|---|---|
title | string | "Verify entered PIN" |
description | string | "Confirm your new 6-digit PIN..." |
hintText | string | "Avoid simple combinations like 123456" |
primaryButtonText | string | "Confirm PIN" |
secondaryButtonText | string | "Back" |
Callback
callback(err, data)
| Name | Type | Description |
|---|---|---|
err | string | null when successful |
data | object | Key pair data |
Returned Data
| Name | Type | Description |
|---|---|---|
privateKey | string | Store this locally (user device only) |
publicKey | string | Public key |
action | string | "initiate" |
generatedAt | date | Timestamp |
You must store the privateKey locally (e.g., secure device storage).
Without it, the user will be forced to enter their PIN again to decrypt it.
get(options, callback)
Retrieves metadata for an existing key pair (encrypted private key + public key).
Does not return the decrypted private key.
buildfire.services.keyStore.get({}, (err, keyPair) => {
if (err) return console.error(err);
console.log('Stored key pair info', keyPair);
});
Options
| Name | Type | Required | Description | Default |
|---|---|---|---|---|
id | string | no | Key pair identifier | "default" |
Returned Data
| Name | Type | Description |
|---|---|---|
encryptedPrivateKey | string | Stored encrypted private key |
publicKey | string | Public key |
salt | string | salt |
keyPairId | string | Identifier |
generatedAt | date | Timestamp |
initiateRecovery(options, callback)
Used when a user:
- switches devices
- uses a PWA / different platform
- clears the locally stored
privateKey
The user enters their PIN to decrypt the encrypted private key stored on the server.
If the PIN is incorrect → decryption fails.
If the user chooses Reset PIN → A new key pair is generated and old encrypted content becomes unreadable.
This method can be called when users change devices or use different platforms like PWAs.
Resetting the PIN creates a new key pair.
All data encrypted with the old private key becomes permanently inaccessible.
buildfire.services.keyStore.initiateRecovery(
{ allowCancel: false },
(err, result) => {
if (err) return console.error(err);
console.log('Recovery completed', result);
}
);
Options
| Name | Type | Default |
|---|---|---|
allowCancel | boolean | false |
translations | object |
screens
recoverView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Unlock Encrypted Content" |
description | string | no | "Enter your PIN to view encrypted content" |
primaryButtonText | string | no | "Unlock" |
secondaryLinkText | string | no | "Reset PIN" |
resetConfirmView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Reset PIN?" |
description | string | no | "Resetting your PIN will permanently remove access to all previously encrypted data. This action cannot be undone." |
primaryButtonText | string | no | "Reset Pin" |
secondaryButtonText | string | no | "Cancel" |
resetPinEntryView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Enter 6-digit PIN" |
description | string | no | "Enter a new 6-digit PIN to protect your new encryption key. You’ll use this new PIN to unlock encrypted content on all devices." |
infoNote | string | no | "Resetting your PIN will permanently remove access to all previously encrypted content." |
hintText | string | no | "Avoid simple combinations like 123456" |
primaryButtonText | string | no | "Continue" |
secondaryButtonText | string | no | "Cancel" |
resetPinEntryConfirmView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Verify entered PIN" |
description | string | no | "Confirm your new 6-digit PIN. Resetting your PIN will permanently erase access to all previously encrypted data." |
primaryButtonText | string | no | "Reset PIN" |
secondaryButtonText | string | no | "Cancel" |
Returned Data
The callback returns different data depending on whether the user successfully recovered their existing private key or reset their PIN and generated a new key pair.
When Recovery Succeeds
| Name | Description |
|---|---|
privateKey | Recovered private key |
action | "recovered" |
When PIN Is Reset
| Name | Description |
|---|---|
privateKey | New private key |
publicKey | New public key |
action | "reset" |
generatedAt | Timestamp |
initiatePinChange(options, callback)
Used to change the user’s PIN without generating a new key pair.
User must:
- Enter current PIN
- Enter new PIN
- Confirm new PIN
All encrypted data remains accessible.
buildfire.services.keyStore.initiatePinChange(
{ allowCancel: true },
(err, result) => {
if (err) return console.error(err);
console.log('PIN change complete', result);
}
);
Options
| Name | Type | Default |
|---|---|---|
allowCancel | boolean | false |
translations | object | — |
screens
changeCurrentPinView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Enter your current PIN" |
description | string | no | "Enter your current 6-digit PIN to confirm your identity before creating a new one." |
primaryButtonText | string | no | "Verify" |
secondaryButtonText | string | no | "Cancel" |
changeNewPinView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Enter New 6-Digit PIN" |
description | string | no | "Create a new PIN to protect your encrypted content. You’ll use it to unlock and access your encrypted data on any device." |
hintText | string | no | "Avoid simple combinations like 123456" |
primaryButtonText | string | no | "Continue" |
secondaryButtonText | string | no | "Cancel" |
changeNewPinConfirmView
| Name | Type | Required | Default |
|---|---|---|---|
title | string | no | "Verify entered PIN" |
description | string | no | "Confirm your new 6-digit PIN to protect your encrypted content. You’ll use it to unlock and access your encrypted data on any device." |
hintText | string | no | "Avoid simple combinations like 123456" |
primaryButtonText | string | no | "Change PIN" |
secondaryButtonText | string | no | "Back" |
Returned Data
| Name | Description |
|---|---|
publicKey | Public key |
action | "change" |
generatedAt | Timestamp |
Error Handling
You can override error message translations in any flow.
Error Messages
These properties belong in the translations.errorMessages object.
| Name | Type | Description |
|---|---|---|
mismatchMessage | string | PIN codes don’t match. |
incorrectPinMessage | string | Incorrect PIN. |
genericError | string | Something went wrong. |
Recommended Storage for Private Key
Because privateKey is sensitive, use one of these recommended secure options:
- Buildfire File Manager
- Buildfire localStorage