Publishable and secret keys: keeping verification data off the client
Put the publishable key in your app and keep the secret key on your server. A publishable key can start a verification and read minimal status, never identity data, so plan for it to leak and limit what a leak costs.

Charles Archibong, Co-founder
· 6 min read

Key takeaways
- Publishable keys ship in clients and can start verifications and read minimal status, never identity data.
- Secret keys read full results, captured media and every Risk Intelligence endpoint, so they stay on your server.
- Assume any client key will be extracted, and restrict it to your web origins where it runs in a browser.
- Revoking a key takes effect on the next request, so rotate by creating the replacement first.
Myaza Trust gives you two kinds of API key, and the rule for using them is short: the publishable key (pk_) goes in your web page or mobile app, and the secret key (sk_) never leaves your server. A publishable key can start a verification and read a minimal status. It cannot read a name, a date of birth, an ID number or a selfie. A secret key can read all of that.
To restrict a leaked key, you have three levers: an allowlist on the key (web origins for a publishable key, IP addresses or ranges for a secret key), per-service keys so one revocation does not take down everything, and immediate revocation. The rest of this article explains why the split works the way it does and how to use those levers before you need them.
Why does a verification API need two kinds of key?
Because any key you put in a client will eventually be read by someone you did not intend. A mobile app can be decompiled. A web bundle can be opened in developer tools. Treating a client key as secret is a hope, not a control.
So the design assumes the client key leaks and limits what it can do. The table below is taken from the authentication documentation.
Key | Prefix | Where it lives | What it can call |
|---|---|---|---|
Publishable |
| Your frontend or mobile app, inside the SDK | Start a verification ( |
Secret |
| Your backend only | Full verification results and media, plus every Risk Intelligence endpoint under |
A key is its prefix followed by 32 random alphanumeric characters, for example pk_test_aB3dE5fG7hJ9kL1mN3pQ5rS7tU9vW1xY. The prefix tells a human reviewer at a glance which scope and environment they are looking at, which is useful when a key turns up in a log or a pull request.
What can someone do with a leaked publishable key?
They can start verifications against your account and poll their minimal status. They cannot read the result of any verification, yours or theirs, because the full result endpoint refuses a publishable key with 403 secret_key_required.
That is a meaningful limit, but it is not zero. In Production, each completed verification is billed to your credit balance, as the environments documentation sets out. A publishable key copied onto another website could be used to run checks you pay for. That is the risk the origin allowlist below exists to reduce.
What can someone do with a leaked secret key?
Read identity data. A secret key can call GET /api/kyc/verifications/:id for the full result (biodata, the plaintext ID number, the facial match) and GET /api/kyc/verifications/:id/media/:kind for the captured selfie, document images and liveness video. It can also call every Risk Intelligence endpoint.
Treat a secret key like a database password. A leak is a data-exposure incident for your organisation, and your own incident process and legal obligations apply. Those differ by jurisdiction, and this article is general information rather than legal advice.
Where should each key sit in a typical integration?
Here is a common shape for an app that onboards customers:
The app mounts the Myaza SDK with a publishable key. The applicant completes consent, capture and liveness, and the SDK submits the verification.
The app shows a "we are checking your details" screen. If it needs to show progress, it polls the minimal status with the publishable key.
Your backend receives the signed webhook for the verification.
Your backend calls the full result with a secret key, updates the customer record and decides what the app shows next.
The applicant's identity data travels from the device to Myaza and from Myaza to your server. It never needs to come back to the device, and with this layout it cannot, because the only key on the device is not allowed to fetch it.
A frequent mistake is to shortcut step 4 by calling the result endpoint from the app "just for the success screen". That requires a secret key on the device, which defeats the whole design. Send the app the few facts it needs from your own backend instead.
How do environments interact with keys?
Every key belongs to one environment, and data never crosses between them. A pk_test_ key works against Sandbox and a pk_live_ key against Production. Keys, verifications, webhook endpoints and configuration are all scoped to one environment.
Using a key in the wrong place returns 403 environment_mismatch. The practical rule from the documentation is to keep one environment throughout a flow: the SDK's Sandbox mount uses a pk_test_ key, and the backend that reads those results uses an sk_test_ key.
Production keys also depend on your business profile. Until your organisation's business verification (KYB) is approved, production verify and upload requests are rejected with business_not_approved. Sandbox works throughout.
How do you restrict a key before it leaks?
In the dashboard, under Developers → API Keys, each key can carry an allowlist. The type of allowlist follows the key's scope, because that is where each control works.
Key | Restriction | What it stops | What it does not stop |
|---|---|---|---|
Publishable | Allowed web origins, such as | A stolen key reused on another website | Requests that send no |
Secret | Allowed IPs or CIDR ranges, such as | A stolen key used from anywhere other than your servers | Nothing from inside the ranges you listed |
Two points follow from that table.
First, an origin allowlist is a browser control. It is worth setting for a web integration, and it does nothing for a mobile app, because a native app sends no Origin. For mobile, the limit on a leaked publishable key is its scope, not the allowlist.
Second, an IP allowlist is the strongest control you have on a secret key, and it is cheap if your backend has fixed egress addresses. List your servers' public egress IPs. If your backend runs on infrastructure without fixed egress, that is worth knowing before you choose where the secret key lives.
An empty allowlist means the key works from anywhere. Leaving it empty is a choice, so make it deliberately.
What should you do when a key leaks?
Work through this in order:
Revoke the key in Developers → API Keys. Revocation is immediate: the next request with that key returns
401.Create the replacement with the same scope and environment, and deploy it. For a publishable key in a mobile app, that means an app release, so the gap between steps 1 and 2 is real. Plan for it.
Check your audit trail. Key creation and revocation emit the
api_key.createdandapi_key.revokedwebhooks, so your security tooling can record who changed what and when.For a secret key, assess exposure. Establish what the key could reach and for how long, and follow your own incident process.
If the key has not actually leaked and you are rotating on a schedule, reverse steps 1 and 2: create and deploy the new key first, confirm traffic has moved, then revoke the old one. Revoking first would break every request in between.
Which habits keep the blast radius small?
One key per service or environment. If your onboarding service and your reporting job share a secret key, revoking it takes both down. Separate keys let you revoke one.
Store secret keys in a secrets manager at creation. A secret key is shown only once. Afterwards the dashboard shows only its prefix, so there is nothing to copy later.
Keep keys out of repositories. A key committed to a public repository should be treated as leaked, even if the commit is removed.
Use
_test_keys in development and CI. Reserve_live_keys for production traffic.Limit who can manage keys. Creating or revoking a key needs the
api_keys:createpermission. Members without it see keys read-only.
The rule to apply
When you review an integration, ask one question of every place a key appears: could the person holding this device or reading this bundle use this key to read identity data? If the answer is yes anywhere outside your servers, the design is wrong, whatever else is right about it.
Then check three things: the web publishable key has an origin allowlist, each secret key has an IP allowlist where your infrastructure allows one, and your team has rehearsed the revoke-and-replace steps. The developer documentation covers the endpoints each key reaches, and the security page covers how Myaza Trust handles the data on its side.
Sources

Charles Archibong
Co-founder
Charles Archibong co-founded Myaza Trust. He writes about identity verification, financial technology, and the practical work of building trusted digital services.


