Secret and publishable
A secret key is lath_live_ or lath_test_ and 43 more characters. It carries the permissions you name and belongs on a server.
A publishable key is lath_live_pk or lath_test_pk and 40 more, so anyone reading a bundle can tell the two apart at a glance.
It holds exactly one permission, auth:public, which reaches only what an end user does for themselves: signing in (auth.signin.start, auth.signin.verify, auth.password.signin, passkeys, the device flow), their own sessions (auth.session.refresh, auth.session.exchange, auth.session.mine, auth.session.signout), their own factors, identities and profile, and the organizations they belong to — 42 operations, each marked auth:public in its reference. The ones that act on an existing account take that user’s access token as proof, so the key is safe in a browser, an app or a CLI.
The kind is fixed when the key is made. There is no call that turns one into the other.
What there is to grant
A permission is a product and a verb: email:write, auth:read, billing:read. The products are account, auth, email, sms, audience, developers and billing, and both verbs exist for each, so the full list is derived rather than written down anywhere.
auth:public is not in that list. It is the publishable key’s built-in permission and is never granted to a secret key by name.
You cannot grant what you do not hold. A key without billing:write cannot create one that has it, and the refusal says so: permission_exceeds_caller.
The plaintext is shown once
developers.key.create returns the key itself in that one response. No operation returns it again — developers.key.list reports the prefix, the permissions and when it was last used, and never a plaintext or a hash.
A publishable key is the exception outside the operations, because it is public by design: the unauthenticated GET /auth/settings/{environmentId} that the hosted pages and components read serves the environment’s publishable key. A secret key is never served anywhere.
Store it before you make the next call. If it is lost, the way back is developers.key.rotate, not a lookup.
Changing a key without replacing it
developers.key.update changes a key’s name and its permissions. The key itself does not change, so nothing holding it has to be redeployed and no request fails while it happens.
That is the one to reach for when a service needs one more scope. Rotation is for a key you no longer trust.
Rotate, and revoke
developers.key.rotate issues a new key with the same name and the same permissions and revokes the old one in the same transaction. The new plaintext is returned once, exactly as create returns it. The old key stops working immediately — there is no overlap window, so deploy the new one promptly.
developers.key.revoke ends a key on its own. It is refused when it is the last key in the environment holding developers:write, because an environment that can no longer manage its own keys cannot be recovered through the API.
Last modified on September 23, 2026