We ship a lot of software. Some of it is our own SaaS; a lot of it is work we run for clients. And nearly every piece of it has the same unglamorous requirement sitting in front of the good part: someone has to log in.
For a long time, every login was its own little project. A new product meant a new set of OAuth apps registered in the Google, Microsoft, and LinkedIn developer consoles, a new pile of client secrets copied into a new environment file, and a new set of redirect URIs to keep straight. The friction wasn’t only ours, either. It landed on the client standing at a signup form, deciding whether creating yet another password was worth it. So we built one front door for all of it: a central OAuth broker at auth.champlinenterprises.com. This is what it does and why it was worth building.
The hidden tax of per-app OAuth
Adding “Sign in with Google” to one app is a pleasant afternoon. Adding it to ten apps is a second job. Each product needs its own registered application in each provider’s console, its own client ID and secret, and its own list of approved redirect URIs. Every time you spin up a new product, you do the whole dance again — and every time a secret rotates or a provider changes a requirement, you do it once per app.
Two problems compound quietly. The first is blast radius: provider credentials end up scattered across a dozen environment files on a dozen deploys, so the surface you have to protect grows with every launch. The second is onboarding friction. “Create an account and choose a password” is one of the most reliable places to lose a person who was otherwise ready to use the thing you built. Multiply both by a growing catalog of products and the cost of not centralizing gets real.
One front door: a central OAuth broker
The fix is an architecture that treats authentication as shared infrastructure instead of a per-app feature. The broker holds every provider credential in exactly one place. Every provider console points at a single redirect URI — auth.champlinenterprises.com/auth/<provider>/callback — no matter how many products sit behind it.
The important design choice is what the broker deliberately does not do: it owns no user accounts. It is an assertion mint, not an identity store. When someone finishes a social login, the broker signs a short-lived (120-second) RS256 JWT that says “this verified email just authenticated,” and hands it back to the product. The product verifies that assertion against the broker’s public keys, published at a standard JWKS endpoint, and then does whatever it wants with its own users. Every product keeps its own accounts table and its own auth guard. A thin client package handles the verification so no product has to reimplement JWT validation.
This is the same instinct behind keeping tenant data isolated in a multi-tenant SaaS architecture: shared plumbing, independent state. The broker centralizes the credentials and the provider handshake; it does not centralize the users.
Why the broker owns no accounts
Keeping the broker out of the identity business is a security decision as much as an architectural one. If one of the products behind it is ever compromised, the attacker gets that product’s users — not the keys to every product we run. The provider secrets never leave the broker, and they never touch a product’s environment.
The assertions themselves are built to be low-value if intercepted. They expire in seconds, they’re bound to a specific product, and replays are rejected. Signing keys rotate with a single command, and because sites validate against the live JWKS rather than a hardcoded key, a rotation doesn’t require redeploying every product. The single redirect URI matters here too: the set of places the broker is allowed to send a user back to is a small, exact-match allowlist, which keeps the open-redirect surface auditable instead of sprawling across a dozen configs.
What “the barrier went away” actually means
Here’s the payoff, and it’s the reason we did this. Wiring social login into a new product now looks like this:
AUTH_HUB_URL=https://auth.champlinenterprises.com
AUTH_HUB_CLIENT_ID=your-product
Install the client package, add those two environment variables, and register the site in the broker’s allowlist. That’s the whole integration. No provider credentials ever touch the product — there is nothing to leak because the secrets aren’t there. A new app goes from “set aside a day for OAuth console wrangling” to a few minutes of wiring.
For the person on the other side, the barrier is gone in the way that actually moves numbers: they click once, with an account they already have, and they’re in. No new password, no verification email to go hunt for, no form to abandon. When the first thing a product asks of someone is “one click,” far more of them take it — and that’s the difference between a login screen that costs you users and one that doesn’t.
The tradeoffs we took on
Centralizing anything means the center matters more, and we’d be lying if we called it free. A shared broker is a critical path: if it’s down, social login is down everywhere at once, so it gets its own uptime attention rather than riding along as one feature among many. We also cache the client allowlist aggressively — that allowlist is the open-redirect defense, so it’s read on the hot path — which means “I just registered a new product” isn’t live until the caches flush. That gotcha bit us once; now the flush is part of the wiring script instead of a thing to remember. Getting operational lessons like that into the tooling is the same discipline we bring to observability — fix it once, in a place the next person inherits for free.
The last tradeoff is a policy one. For open consumer products, a first-time social login can create an account on the spot. For gated or invite-only products, the broker attaches a social login to an existing account matched by verified email and turns everyone else away, so an OAuth button can never quietly manufacture access to something it shouldn’t. One broker, but the account policy still belongs to each product.
We built the broker because we run enough of our own software to feel the tax every time we shipped, and removing it made every future launch cheaper and every login friendlier. If you’re curious what sits behind that front door, the products we build and run are the reason it exists.





