Authentication
How 0Bit uses publishable keys, secret keys, client secrets, webhook secrets, idempotency keys, and environment modes.
0Bit authentication is built around organization credentials and product entitlements. A credential identifies your organization. Product access then depends on entitlements and product-specific configuration such as allowed domains, webhook setup, KYC/KYB state, pool access rows, payout settings, and enabled corridors.
Credential types
| Credential | Shape | Lives | Used for |
|---|---|---|---|
| Publishable key | pk_test_* / pk_live_* | Browser/mobile where allowed. | Bootstrapping hosted or embedded flows. |
| Secret key | sk_test_* / sk_live_* | Server only. | Creating sessions, reading protected records, executing approved writes. |
| Client secret | Product/session scoped, for example gsec_... | Browser-safe for one server-created object. | Binding a hosted/embed flow to that object. |
| Webhook signing secret | whsec_* | Server only. | Verifying inbound webhook authenticity. |
| Idempotency key | Your generated string | Server generated and stored. | Retrying one logical write safely. |
The most common mistake
sk_* and whsec_* never belong in browser code, mobile bundles, logs, analytics tools, or customer-visible configuration. pk_* and client_secret are browser-safe only because their abilities are intentionally limited.
Request authentication
Use Bearer authentication for server calls. The route and object differ by product, but the boundary is the same: sk_* stays on the server, product access is checked after authentication, and state-changing writes should be idempotent.
curl -X POST https://gate-api-sandbox.0bit.app/v1/gate_sessions \
-H "Authorization: Bearer $OBIT_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order_123_create_gate_session" \
-d '{"amount":"100.00","currency":"EUR","return_url":"https://app.partner.example/done"}'| Product | Common server action | Credential pattern |
|---|---|---|
| 0Gate | Create/retrieve/cancel sessions, read capability and transaction state. | Authorization: Bearer sk_*; pk_* for browser/embed bootstrap where allowed. |
| 0Pools | List entitled pools, create quotes, execute quotes, read trade status. | Authorization: Bearer sk_*; product entitlement and pool access must also pass. |
| 0Base | Create payment objects, read ledgers/reports, manage payment links or intents. | Authorization: Bearer sk_*; product enablement and merchant settings must also pass. |
| 0Link | Review routes, quote availability, fallback, and settlement-handling state. | Authorization: Bearer sk_*; route/workflow access must also pass. |
| 0Pools Scan | Read public-safe indexed activity. | Public-safe reads or approved access depending on endpoint. |
The API should treat authentication and product access as separate checks:
| Check | Failure meaning |
|---|---|
| Key format | The key is missing, malformed, wrong type, or sent to the wrong route. |
| Key mode | A test key is sent to live, or a live key is sent to sandbox. |
| Organization state | The key is revoked or not attached to the expected organization. |
| Entitlement | The organization is not enabled for the product. |
| Product config | The organization is enabled but missing product-specific setup. |
| Object/corridor | The requested country, currency, asset, flow, pool, route, or object state is unavailable. |
Publishable key boundary
Publishable keys are safe to expose because they cannot create privileged objects by themselves. They are mainly relevant to hosted or embedded flows such as 0Gate, where they are used alongside a server-created object secret such as a client_secret. Headless product surfaces like 0Pools may not need a browser publishable-key path at all.
import { GateRamp } from '@0bit/gate/browser';
const ramp = new GateRamp({
publishableKey: process.env.NEXT_PUBLIC_OBIT_PUBLISHABLE_KEY!,
clientSecret,
environment: 'sandbox',
});Publishable keys still matter. Protect them with allowed domains, correct environment mode, and product-specific bootstrap checks.
Secret key boundary
Secret keys are equivalent to server credentials. Use them only from trusted backend services.
| Do | Do not |
|---|---|
| Store in a secret manager. | Put in frontend .env public variables. |
Send as Authorization: Bearer sk_*. | Put in a query string. |
| Rotate if exposed. | Log raw headers or config dumps. |
| Scope use through backend routes. | Let the browser decide amount, destination, or quote execution. |
Webhook signature verification
Webhook verification requires the raw request body. Parse JSON only after verification.
import crypto from 'node:crypto';
export function verifyGateSignature(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
const timestamp = Number(parts.t);
const signature = parts.v1;
if (!Number.isFinite(timestamp) || !signature) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'));
}After verification:
- Store the event id before applying business logic.
- If the event id already exists, return 2xx without repeating fulfillment.
- Join the event to your internal record using your reference and the 0Bit object id.
- Apply the state transition only if it is valid for your current record state.
Idempotency
Idempotency protects create and execute calls from duplicate effects during retries. Use one key for one logical operation.
| Operation | Good idempotency key |
|---|---|
| Create 0Gate session for order 123 | order_123_gate_session_create |
Execute pool quote quote_abc once | quote_abc_execute_order_123 |
| Create payment intent for invoice 456 | invoice_456_payment_intent_create |
Do not reuse one key after changing amount, currency, user, quote id, destination, or product.
Key rotation
- Create the replacement key in the approved management surface.
- Deploy the new key to your secret manager or client config.
- Confirm traffic succeeds with the new key.
- Revoke the old key.
- Check logs for any old-key traffic and stale deployment targets.
Rotate webhook secrets with the same discipline. If your webhook worker supports dual-secret verification during a short migration window, record which secret matched and remove the old one after traffic moves.