Week 007 — Login Ships, Stripe Arrives, Whitespace Attacks
The login system shipped on Wednesday. A whitespace character tried to take it down the same day.
Week of November 11, 2024
Progress
Completed the auth layer: session regeneration on login via session_regenerate_id(true), proper logout that redirects back to index.php, and a login check added to the header that reroutes unauthenticated users to sign-in. The front door is locked now.
Immediately after, started Stripe. Created an account, embedded a pricing table, and had a functioning subscribe page by mid-week. The Stripe CLI took some effort to authenticate — it opens a browser login and requires selecting the specific account, and the first attempt pointed at the wrong one. Once that was sorted, a local webhook listener was running and receiving test events. By end of week, the webhook was responding correctly to both CLI-triggered events and actual test subscriptions.
The Hard Part
A critical bug appeared within hours of login shipping: saving a user profile without making any changes would corrupt the stored email address, making the user unable to log in afterward.
The cause: whitespace embedded in the PHP/HTML template around the email field value. Invisible in the UI, invisible in the source if you weren't looking, but present in the POST data and saved to the database on every profile save. A single trailing space, repeated on every save, accumulating silently until login failed.
The fix was a trim() call before saving. Finding it required noticing that login failures were happening only after a profile save — not randomly. That pattern pointed directly at the save flow.
Decision Made
Stripe Entitlements — a Stripe-managed feature access system that tracks what a subscriber is entitled to — was considered and passed on. The idea is that instead of storing subscription state locally, you call Stripe's API to check what a user has access to. It reduces some bookkeeping, but it ties the application's access control logic to Stripe's data model more tightly than is comfortable. Better to maintain subscription state internally and use Stripe only for the transaction layer. More to build now, easier to reason about and migrate later.
Next Week
Webhooks are receiving events. The next step is processing them — pulling subscription data out of the payload and using it to update the application's internal state, specifically creating a Stripe customer ID for each user so that transactions can be tied back to them.
