Like most other developer tools, Clerk's SDKs are configured with two "keys," one for the backend and one for the frontend.
And we share the same core requirements:
- The backend key must have significantly random so it cannot be guessed
- The frontend key is public, so it only needs to be a unique identifier
Although there's no security benefit in doing so, many tools have their frontend key mirror the format and length of their backend key. Take Stripe, for example:
But as an authentication company, Clerk has an extra requirement for our frontend key, and it meant that mirroring our secret key would cause performance issues.
Wait, what? How could a key cause performance issues?
The purpose of a frontend key is to be a unique identifier when interacting with a frontend-facing API. Here's an example of how Stripe's SDK uses the publishable key:
Notice how this request is being sent to a stripe.com domain? Stripe SDKs always make requests to stripe.com, even if you're embedding their elements into your own website.
But since Clerk runs an authentication API and since we're responsible for maintaining sessions, we can't securely do the same. We need to set HttpOnly cookies from a first-party context, which means our API needs to be accessible through our customers' domains. (Developers configure this by setting a CNAME in their DNS records.)
When we launched, our frontend key was simply the hostname where our frontend API is hosted. Developers configured it like this in their React apps:
By passing the API hostname directly, we avoided making an extra, waterfalled API request to exchange a traditional random key with the hostname. This led to faster overall loading speeds.
But we hit an unexpected problem with this strategy: it really confused developers. It was a common complaint in friction logs, and when we watched developers integrate Clerk we could see the confusion wash over their face.
A hostname as a frontend key is completely unfamiliar, and no matter what we tried with design and naming, we couldn't get over the hurdle.
So this week, we finally threw in the towel. Our new frontend API keys look just like Stripes:
But we refuse to exchange developer experience for performance, so there's a not-so-secret subtlety to our new publishable key. Take a closer look:
Now, base64-decode the part after
Indeed, we just base64-encoded the old value and started calling it a publishable key. We added a $ as a simple stop character so we can detect when keys are malformed.
As a final step, we changed the prop name for React:
Quick, dirty, and a little silly – but it works! We haven't sacrificed performance and our new publishable key feels much more familiar. Developers have stopped raising their eyebrows and breeze through initial setup.