SecureBin Developer Platform
Build privacy-focused apps with standard HTML, CSS, and JavaScript, then submit provider-blind encrypted review envelopes for marketplace approval. SecureBin App Store uploads accept .sbapp-review.enc.json submissions only.



Includes the CLI, local development server, browser TryIt code environment, encrypted review submission builder, legacy private packager, runtime bridge, starter project, and security documentation. Requires Node.js 20 or newer.
.securebin/app.key, .securebin/signing-private.pem, the SecureBin review private key, or the publisher private key.Overview
A SecureBin project contains a readable local source directory and a manifest. The SDK turns those files into an encrypted review envelope with the .sbapp-review.enc.json extension. Only that review envelope is submitted to the App Store.
| Stage | What happens |
|---|---|
| Develop | Edit HTML, CSS, JavaScript, and assets locally in src/. |
| Preview | securebin dev serves the app on loopback with the SDK runtime bridge. |
| Optional signing | securebin keygen creates developer signing keys. Do not upload the generated private key. |
| Submit | securebin submit --review-key review-public.pem hashes files and writes a provider-blind .sbapp-review.enc.json. |
| Review | SecureBin decrypts the envelope only in the owner review dashboard with the offline review private key. |
| Publish | The trusted publisher converts approved review content into a signed installable .sbapp. |
Quick Start
Extract the SDK, open PowerShell in the extracted folder, and run:
node bin/securebin.js create my-app
cd my-app
node ..\bin\securebin.js keygen
node ..\bin\securebin.js dev
Open the loopback URL printed by the development server. When the app is ready, stop the server and build the encrypted marketplace review envelope:
node ..\bin\securebin.js submit --review-key review-public.pem --out dist\my-app.sbapp-review.enc.json
Upload dist\my-app.sbapp-review.enc.json at Upload App. The upload form rejects legacy .sbapp, .html, and .htm files for public marketplace submission.
| Command | Purpose |
|---|---|
create <folder> | Create a clean starter project. |
keygen [project] | Generate optional developer signing keys and a legacy private-package key. |
dev [project] [--port 4860] | Run the local preview server. |
submit [project] --review-key review-public.pem [--out file.sbapp-review.enc.json] | Build the encrypted marketplace review envelope. |
package [project] [--out file.sbapp] | Build a legacy encrypted private-distribution package. Not accepted by the public marketplace. |
inspect <file.sbapp> | Display only legacy package envelope metadata. |
Project Structure
The starter includes a .gitignore that excludes .securebin/ and dist/. Back up the package key securely outside source control.
Manifest
The SDK validates securebin.app.json before development and packaging.
{
"id": "com.example.my-app",
"name": "My App",
"version": "1.0.0",
"source": "src",
"entry": "index.html",
"permissions": ["storage.local"]
}
| Field | Rules |
|---|---|
id | 3–81 lowercase letters, numbers, dots, or hyphens; must begin with a letter or number. |
name | Required; 80 characters or fewer. |
version | Semantic version such as 1.0.0. |
source | Source folder, normally src. |
entry | HTML entry file inside the source folder. |
permissions | Array of supported runtime capabilities. |
Permissions
Declare only the runtime capabilities your app needs in securebin.app.json.
| Permission | Capability |
|---|---|
storage.local | Read and write app-scoped local storage. |
storage.usb | Access approved SecureBin USB storage operations. |
clipboard.write | Write to the clipboard after permission approval. |
clipboard.read | Read clipboard contents after permission approval. |
App Store listing permissions are also selected on the upload form. Keep those declarations consistent with the manifest and app behavior.
Runtime API
The included runtime/securebin-runtime.js exposes window.securebin. Include it from /securebin-runtime.js while using the SDK development server.
<script src="/securebin-runtime.js" defer></script>
<script src="app.js" defer></script>
| Method | Purpose |
|---|---|
securebin.app.getManifest() | Return the current app manifest. |
securebin.storage.read(path) | Read app-scoped data. |
securebin.storage.write(path, value) | Write app-scoped data. |
securebin.storage.list(path) | List an app-scoped storage path. |
securebin.permissions.request(permissions) | Request declared capabilities. |
securebin.crypto.randomId(prefix) | Create a cryptographically random identifier. |
securebin.crypto.sha256Base64Url(bytes) | Hash bytes with SHA-256. |
Host calls use a request/response bridge and time out after 30 seconds. Handle rejected promises and unavailable capabilities in your UI.
Security Model
Packaging happens locally. The hosting provider stores and serves the encrypted envelope but does not receive the package key.
| Visible to host | Encrypted inside payload |
|---|---|
| Package format/version | Readable manifest name and metadata |
| App ID | HTML, CSS, and JavaScript |
| Package size and creation time | Images, icons, and bundled assets |
| Encrypted hash and public signing key | Source filenames and implementation details |
Current package encryption is AES-256-GCM. The SDK signs the encrypted ciphertext hash with Ed25519 when signing keys are available.
app.key, you may be unable to decrypt or update packages built with that key. Store a secure backup.Packaging
The submission builder recursively includes files from the manifest's source directory, hashes each file, builds a review artifact, and encrypts it to the SecureBin review public key.
node ..\bin\securebin.js submit --review-key review-public.pem --out dist\my-app.sbapp-review.enc.json
The upload envelope contains format, version, app_id, payload_hash, review-key metadata, and ciphertext. The web host can validate and quarantine it, but cannot read the source.
securebin package still exists for legacy private distribution, but public marketplace upload rejects those opaque .sbapp packages because they cannot be reviewed before publication.
Publishing and Updates
- Test locally
Run
devand verify the app without depending on undeclared capabilities. - Build a review envelope
Run
submit --review-key review-public.pemand upload the generated.sbapp-review.enc.json. - Owner review
SecureBin reviews the decrypted source in the restricted review dashboard before any marketplace publishing step.
- Publish after approval
Only the trusted publisher converts approved review content into an official signed
.sbapp. Developers do not upload signed transports directly. - Update an existing app
Submit a new
.sbapp-review.enc.jsonfor the replacement version. The marketplace should not accept direct legacy package replacement.
Icons, screenshots, pricing, descriptions, and App Store listing permissions are entered separately on the website and are bound to the review record.
In-App Purchases
In-app purchases are available for approved marketplace apps. Developers can define one-time or subscription products on the app upload/edit page. Apps can request a checkout session and check whether the signed-in user has active access to a product.
Each product is defined with an id, name, and type of either one_time or subscription. One-time products take a flat price; subscription products take price_monthly and price_yearly.
[
{"id":"pro","name":"Pro unlock","type":"one_time","price":4.99},
{"id":"plus","name":"Plus","type":"subscription","price_monthly":2.99,"price_yearly":19.99}
]
Apps should start checkout through the SecureBin in-app checkout launcher. This creates a SecureBin-controlled checkout session and opens the integrated checkout UI:
<script src="/assets/js/securebin-iap.js"></script>
<button data-securebin-iap data-app-slug="your-app-slug" data-product-id="pro">
Unlock Pro
</button>
Apps can also call the launcher directly after a button or link click:
SecureBinIAP.openCheckout({
appSlug: "your-app-slug",
productId: "pro"
});
For native or advanced integrations, apps can request a checkout session from SecureBin with:
POST /assets/php/create_in_app_checkout.php
{ "app_slug": "your-app-slug", "product_id": "pro" }
The response contains a SecureBin-controlled checkout_url and checkout_session. The checkout session is bound to the signed-in user, app, product, product type, expected price, and a short expiration window.
Purchase and subscription records are completed only by the integrated checkout callback. Direct app-side calls to the record endpoints are rejected with integrated_checkout_required.
Controlled checkout flow
App button or link click
-> SecureBin creates checkout session
-> SecureBin opens hosted checkout
-> Payment completes inside the integrated checkout
-> Signed checkout callback records the purchase or subscription
-> App checks access through check_in_app_access.php
-> Revenue dashboard includes the transaction
The integrated checkout callback must include a valid HMAC signature header. Configure the shared callback secret with SECUREBIN_IAP_CALLBACK_SECRET or the securebin_settings key in_app_checkout_callback_secret.
X-SecureBin-IAP-Signature: sha256=<hmac_sha256_raw_json_body>
One-time products are tracked in in_app_purchases; subscription products are tracked in in_app_subscriptions. Both are included in developer revenue totals and payout balance.
Apps can check whether the signed-in user currently has access to a product with:
GET /assets/php/check_in_app_access.php?app=your-app-slug&product=pro
Troubleshooting
| Error | Resolution |
|---|---|
| Node command is unavailable | Install Node.js 20 or newer and reopen the terminal. |
| Missing package key | Run keygen in the project or provide SECUREBIN_APP_KEY. |
| Manifest validation failed | Check the ID format, semantic version, HTML entry filename, and supported permissions. |
| Entry file not found | Ensure entry exists inside the configured source directory. |
| Upload rejected | Upload a valid .sbapp-review.enc.json envelope generated by securebin submit --review-key review-public.pem, not a legacy .sbapp or renamed HTML file. |
| Port already in use | Run dev --port 0 or choose another available port. |