You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow only publishable key prefixes in browser clients #14
Following your suggestion in gatepost-dev/js#9, I would like to agree the browser key rule in
client.md before changing the client or field code.
The guard now handles white space correctly, but it still refuses only the two known secret
prefixes. If a new secret prefix were introduced, that key could pass the guard. I favour
allowing only the documented publishable prefix, nipost_pk_, when a browser client has a key.
This is a check of the key's kind, not proof that the gateway will accept it.
Proposed behaviour
With no apiKey, keep the existing behaviour: the client sends no X-API-Key header. The field
still makes no request without a key.
Classify a supplied browser key after trimming surrounding white space, as the current fix
does. Allow nipost_pk_ keys, including the test and live forms used in the docs and fixtures.
Reject both known secret prefixes and any unrecognised prefix before sending a request.
The client should raise a TypeError without including the key in the message.
Keep server clients unchanged. Secret keys remain valid there, including in the PHP client.
Compatibility and wording
This would reject browser keys with arbitrary prefixes that the current guard lets through.
Mock transports and applications using custom gateways may rely on that behaviour, so the
change needs a clear release note and an agreed release level.
For the field, should an unrecognised key use the existing secret_key state and message, or
should the spec distinguish an unsupported key from a known secret? Calling every unrecognised
key a secret would be misleading. I would like to settle that before extending the field rule.
If this direction is acceptable, I can prepare the wording in client.md and SEC-1, plus any
needed wording in field.md. The implementation can then cover publishable, absent, known secret,
unrecognised and whitespace-padded keys with synthetic fixtures only.
I used Codex to help draft this proposal and check the current docs.
The direction is agreed: in a browser, a client accepts only a key with the publishable prefix nipost_pk_, and refuses everything else before it sends a request. An allow list fails safely if a new secret prefix appears, and the packages are still alphas, so this is the cheap time to change it.
Answers to your points:
Client
No key: unchanged. No X-API-Key header.
Trim, then classify. nipost_pk_ passes. Anything else throws a TypeError before any request, and the message never holds the key.
Keep two messages, so a developer knows which mistake they made: the existing one for the two known secret prefixes ("A web page must not hold a secret key..."), and a new one for a key that is not a publishable key.
Server clients: unchanged, in both languages. A secret key is valid where no document exists.
Field
Keep secret_key for the two known secret prefixes. You are right that calling an unknown key a secret would mislead.
Add one error code, unsupported_key, for a key that is neither publishable nor a known secret. It behaves as secret_key does today: no request, no location button, the state error, one console error for the developer that never holds the key, and the event error in place of each lookup or reverse call that was due.
The person filling in the form does not need to know which kind of key the page holds. So the text on screen can be the same sentence as secret_key shows today. It still needs its own key in the catalogue (unsupported_key), because each state names its message.
Where the wording goes
standards/CODING_STANDARDS.md, SEC-1: client-side code accepts only publishable keys.
client.md: the browser rule is not written there today. It lives only in SEC-1 and in the js client. Add it, with the two refusals and the trim.
field.md: the Interface row of the error event, the Lookups and Location rules, the Failures table (two new rows, for a lookup and for reverse), the States table and the Messages table.
messages/field_en.arb: the new key.
The doc tests in scripts/tests/ pin most of these lines, so they change in the same pull request.
Release level
It adds a public error code, so the spec goes to 0.4.0, as a minor change. Say in the change notes that a browser key with any other prefix now stops working, with the mock and custom gateways named as the cases to check.
Order: the spec pull request first. Then js moves its spec pointer and changes the client, the field and the React wrapper's types, with a change file for each package. The PHP package only moves its pointer and version.
Fixtures
fixtures/keys.json already has publishable and secret mock keys. An unrecognised key in a test can be any made-up string that no gateway issues, such as abc. No real key anywhere.
If you take the spec wording, open the pull request against main and I will review it there. Thank you for settling the rule before the code.
Activity
MobileMage commentedon Oct 4, 2026
The direction is agreed: in a browser, a client accepts only a key with the publishable prefix
nipost_pk_, and refuses everything else before it sends a request. An allow list fails safely if a new secret prefix appears, and the packages are still alphas, so this is the cheap time to change it.Answers to your points:
Client
X-API-Keyheader.nipost_pk_passes. Anything else throws aTypeErrorbefore any request, and the message never holds the key.documentexists.Field
secret_keyfor the two known secret prefixes. You are right that calling an unknown key a secret would mislead.unsupported_key, for a key that is neither publishable nor a known secret. It behaves assecret_keydoes today: no request, no location button, the stateerror, one console error for the developer that never holds the key, and the eventerrorin place of each lookup orreversecall that was due.secret_keyshows today. It still needs its own key in the catalogue (unsupported_key), because each state names its message.Where the wording goes
standards/CODING_STANDARDS.md, SEC-1: client-side code accepts only publishable keys.client.md: the browser rule is not written there today. It lives only in SEC-1 and in the js client. Add it, with the two refusals and the trim.field.md: the Interface row of theerrorevent, the Lookups and Location rules, the Failures table (two new rows, for a lookup and forreverse), the States table and the Messages table.messages/field_en.arb: the new key.scripts/tests/pin most of these lines, so they change in the same pull request.Release level
jsmoves its spec pointer and changes the client, the field and the React wrapper's types, with a change file for each package. The PHP package only moves its pointer and version.Fixtures
fixtures/keys.jsonalready has publishable and secret mock keys. An unrecognised key in a test can be any made-up string that no gateway issues, such asabc. No real key anywhere.If you take the spec wording, open the pull request against
mainand I will review it there. Thank you for settling the rule before the code.feat: accept only publishable keys in a browser (#16)