Security

Your app talks to Onelo with an API key — but a publishable key ships inside your app, so on its own it isn't a secret. What actually protects the connection is that Onelo binds each key to where and what is allowed to use it, and enforces that server-side on every call. This section covers the model, how you configure it, and the signals Onelo surfaces when something looks wrong.

The model — three layers, two keys

Onelo's client-facing security is three layers. Each one answers a different question about a request:

LayerWhereWhat it proves
Allowed domainsWeb (client)The request came from your own domain — the browser’s Origin is on your verified list.
App identity & attestationNative / desktop (client)The request came from a genuine, unmodified build of your app — App Attest (Apple), codesign, or Play Integrity (Google), against your registered Bundle ID.
Secret keyYour backendThe request came from your server — the real trust boundary. Sensitive work is gated here, not in the client.
The rule of thumb: the client is gated by integrity, but your backend (secret key) is the real boundary. Enforce paid or sensitive actions on your own server — secret key + the user id from a trusted session — and never trust a decision made purely in the client. Client-side gating is, by nature, bypassable.

Two kinds of key

KeyWhere it livesWhat it is
onelo_pk_live_*Compiled into the client appPublishable. Public by design — it identifies the app and ships in the binary; on its own it is not a secret. The layers above are what bind it to your app.
onelo_sk_live_*Your server onlySecret. Grants server trust (SSE stream, identify, verification). Stored only as a hash — never in plaintext; shown once at creation, then only the last few characters. Never ship it to a client.

The init handshake — a different proof per app type

Before the per-request checks, the very first call the SDK makes (fetching its config) is gated by a proof chosen from your app type — set when you create the app. This is what stops a copied publishable key from working somewhere it shouldn't.

App typeMust presentChecked against
Webthe browser's Originyour verified domains — a live web app with none configured is rejected outright.
Serveran X-Client-Secret headerthe app’s client secret, stored only as a hash. Wrong or missing → rejected.
Mobile / desktopa PKCE code_challengea one-time challenge bound to this app, so an intercepted handshake can’t be replayed (the same PKCE behind Onelo’s hosted sign-in).

Only native apps use PKCE — they can't safely hold a secret, so they prove themselves with a one-time challenge. After the handshake, mobile/desktop apps additionally carry per-request attestation.

Explore

A note on one thing you may have read elsewhere: there is no “Secure Mode” to enable. An older HMAC user-id-hash option was retired — the three-layer model above is the whole picture. If you find a userIdHash reference in an old snippet, ignore it.
Security — Onelo Docs