Refining Fortify: A Fresh Look at Authentication

Cover Image for Refining Fortify: A Fresh Look at Authentication

In my last post, I highlighted a few glaring issues: a registration form that felt like an interrogation, an AuthForm component doing far too much heavy lifting, and a lack of fallbacks for when things go wrong. This phase was all about diving back into the code to fix those problems, and I ended up learning quite a bit more than I anticipated along the way.

The Initial Strategy

I started with a clear roadmap: break down the AuthForm into four specific components, redesign the signup as a multi-step process with test data, and introduce a guest mode to keep the app functional even if a session drops. Most of this went as expected, but one part of the plan changed completely once I saw the code in front of me.

Two of those goals stayed on track, one shifted entirely once I understood the logic better, and one is still on the to-do list for a very good reason.

Reworking the Signup Flow

This is where I spent the bulk of my time. The original signup was just one long, overwhelming list of fields. I’ve since converted it into a two-step wizard. It uses a Zod schema that’s split across the steps and then validated all at once during submission.

I also added a few features that weren’t in the original notes: a real-time password checklist, a progress bar, and the removal of a bulky header image that didn’t serve much purpose. These weren’t technical requirements, but they made the user experience feel much more approachable and less like a chore.

As the file count grew, it became obvious that the signup logic needed its own space, so I moved SignUpForm and its supporting pieces into a dedicated folder. It’s a small organizational win that makes a big difference in maintainability.

Adapting to the Data Flow

During the build, I had to pivot on when to create the Dwolla account. I initially thought I’d handle it much later, but as I was wiring the steps together, it became clear that creating the Dwolla and Plaid accounts simultaneously was much more efficient. This insight only came once I was actually looking at how the data moved through the app.

This changed my step structure significantly. It’s the kind of decision you can’t really make from the sidelines; you have to be in the code to see why one path is better than the other.

I also hit a minor snag with my UI components. Somewhere along the line, a config change broke the styling for my buttons. It was a quick fix, but it served as a good reminder that even small changes can have unexpected downstream effects.

Questioning the Plan: The AuthForm Split

This was the most interesting part of the refactor for me. It’s where the work itself actually convinced me that my original plan was flawed.

My plan was to split the four auth states into four distinct components. I successfully pulled out the signup logic, but when I looked at the remaining three—signin, forgot-password, and reset-password—I realized they were fundamentally the same. They shared the same layout, the same skeleton, and the same fields.

My instinct was that this was unfinished — that I'd done half the job and needed to go back and finish splitting out the other three. So I asked Claude Code to look at the actual structure of those three states and tell me honestly whether further splitting was worth it.

Splitting them into separate files would have just resulted in three copies of the same code. Instead, I moved their logic into a shared config file. I learned a better rule: refactor where the structure diverges, not just where the name changes. Signup earned its own component because it was truly different; the others didn’t need that level of separation.

This principle is much more useful than my starting point, and I only found it by spending enough time in the code to notice the pattern.

What’s Next?

I haven’t built the guest mode yet. Right now, the app has the branching logic—asking if you want to link a bank now or later—but both paths lead to a temporary dashboard. Neither flow is fully functional yet.

I’m holding off on guest mode for now because it’s a significant piece of work. It needs to be a convincing, data-rich experience without using real sensitive information, so it deserves its own dedicated development cycle and post.

Advice for Future Refactors

My biggest takeaway is to have a plan, but be ready to scrap it. Some problems only reveal their true shape once you start building the solution. Whether it was the timing of account creation or realizing that certain components shouldn't be split, the most important decisions were made while I was deep in the implementation, not during the planning phase.

In the next update, I’ll be tackling Plaid bank linking—the OAuth flow, the quirks of the sandbox environment, and what it takes to get it production-ready.

Let’s Build the Future Together

I’m currently seeking a full-time engineering role where I can contribute to secure, logic-driven systems. If you're looking for a disciplined developer to join your team, I’d love to hear from you.