So the CTO read a blog post and decided our little internal tool needed "enterprise-grade identity." That's how we ended up piloting Auth0 for ~100 users. Not gonna lie, I was more worried about the cloud bill for the tool itself than the Auth0 invoice. But oh, the lessons we learned... and the peculiar line items we saw.
Let's start with the setup. The developer experience is, admittedly, pretty slick. We had a basic OIDC flow wired up in an afternoon. The dashboard is a labyrinth, but you find your way. Our configuration looked something like this in our app's config:
```javascript
// auth0-config.js
export const auth0Config = {
domain: 'our-company.us.auth0.com',
clientId: 'REDACTED',
audience: 'https://api.internal-tool.com',
scope: 'read:reports write:data',
// The critical part everyone misses at first:
useRefreshTokens: true,
cacheLocation: 'localstorage'
};
```
The first month's bill arrived. It wasn't the user count that stungβit was the **Machine-to-Machine (M2M) tokens**. Our backend service calls another internal API? That's an M2M token. Every cron job, every worker? M2M token. They bill per "authentication," and those service accounts are chatty little things. We saw ~85,000 authentications for 100 human users. The bill was... illuminating.
Hereβs the breakdown of our "aha" moments and subsequent fixes:
* **The M2M Tsunami:** We were requesting new tokens on every API call. The fix? Implement aggressive token caching. We moved from in-memory cache to a shared Redis store for tokens, slashing those M2M calls by 90%.
* **Rule Overhead:** We wrote a few fancy Rules (Auth0's serverless functions) for custom claims. They're powerful, but remember: they execute on *every* login. Keep them lean. We had one doing a verbose log that was just costing us execution time for zero runtime benefit.
* **The "Log Streaming" Siren Song:** We hooked up logs to Datadog via their log streaming. It's fantastic for debugging, but for a 100-user tool? Overkill. The volume was low, but it was another config to manage and another potential point of failure. We scaled back to periodic exports for audit purposes only.
* **Reserved Capacity? Not really.** Unlike AWS RIs, you can't exactly "reserve" users. You're on a per-authentication, per-active user model. Your main lever is architectural efficiency (see: token caching).
The final verdict? It works, and works well. The security and features are top-tier. But for a small internal tool, the complexity and cost vectors feel like using a Formula 1 car to get groceries. You'll learn a lot about identity, and you'll also learn to scrutinize a billing line item called "M2M Non-Interactive Authentication" with a sardonic smile.
Your cloud bill is too high.
Yep, the M2M tax hits everyone. Those "authentications" aren't just user logins, they're every token refresh. Your backend service might request a token with a 24-hour expiry, but if it checks every 5 minutes for a new one, that's 288 billable events per day for one service.
We ended up implementing a shared, in-memory token cache at the application level to cut down on the repetitive calls. Also, max out those token lifetimes in the dashboard.
Wait until you see the line item for "Actions" if you start customizing login flows.
Build once, deploy everywhere