Kartik Kant / All lessons Chapter 2 · Building it
Lesson 2.4

Logins, and why they're harder than they look

A login screen has two boxes and a button. It looks like the easiest thing in the app.

It's one of the few places where a mistake gets genuinely serious, because it's the wall between one person's data and everyone else's. That's the reason nobody sensible writes their own from scratch any more.

Use somebody else's

Handling passwords properly means storing them in a way that survives your database being stolen, resisting people trying millions of guesses, managing sessions, doing password resets without opening a hole, and keeping up with all of it as the advice changes.

This has been solved. Supabase Auth, Clerk, Auth0 and the rest do it for a living, usually free at your size.

Writing your own login is the software equivalent of building your own front door lock. Possible, educational, and the wrong place to be creative.

What actually happens when someone logs in

Worth understanding even though you're not building it.

Someone types email and password. The service checks them, and if they match it hands back a token, which is a long string that essentially says "this person is who they claim to be, until this date."

Your app stores that token. Every time it asks the server for something, it sends the token along, and the server checks it before answering. Logging out throws the token away.

That's the mechanism. Sessions, JWTs and refresh tokens are all variations on "hold onto proof of who you are."

The states nobody builds

Most people build one path: correct email, correct password, logged in.

Real users produce many more situations, and each one that isn't handled looks like your app is broken.

Someone's never signed up. Someone typed the wrong password. Someone forgot it entirely. Someone's session expired while they were away for a week. Someone's logged in on their phone and their laptop and does something in both. Someone deleted their account and comes back.

None of these are exotic. All of them happen on any normal day with a hundred users. The nastiest is the expired session, because if you don't handle it your app shows a blank screen or an error nobody can act on, and the user has no idea they simply need to log in again.

Asking for all of these when you build the login screen costs one sentence. Discovering them one at a time, from confused users, costs considerably more.

Tying data to the person

Once you have logins, every piece of data needs an owner, and the server needs to check it.

The mistake to know about: checking permission only in the app's own screens. Hiding a button doesn't protect anything, because the server is still willing to answer if somebody asks it directly. That's not an obscure hacker technique, it's opening the browser's developer tools.

The rule is that permission gets checked where the data lives, on the server, not in the interface. Tools like Supabase have this built in, where you write a rule saying "people can only read rows they own" and the database enforces it no matter who's asking.

Do you even need accounts?

Genuinely worth asking before you build any of this.

Accounts add friction. Every field between someone and the thing they came for loses you people, and the signup form is usually the biggest single drop in the whole funnel.

Some apps need them from the start, anything where data must follow a person across devices. Plenty of first versions don't. If everything can live on the person's own device, you can skip accounts entirely for v1 and add them when there's a reason.

There's a middle option some apps use: let people in immediately with a temporary anonymous account, and only ask them to sign up properly when they'd lose something by not doing it. They get to the good part first and the account arrives when it's obviously worth it.

A quick story. My app used anonymous accounts to start, so someone could open it and begin immediately without a signup form. They could attach a real identity later if they wanted their progress to survive a new phone.

That part worked well. The part I underestimated was how many states this creates. Anonymous, anonymous-then-linked, signed in on a second device, signed out, deleted. Each one is a path through the app, and each one needs to do something sensible.

The login screen took an afternoon. Everything around the login screen took considerably longer, and that ratio seems to hold generally.

If you want help planning auth

Work this chapter with Claudea prompt to run on your own project
I'm adding logins to my app. I'm new to this, so explain the concepts as we go and don't assume I know the terminology. What my app does: [describe it] How I'd like people to sign in: [email and password, Google, "not sure"] Please: 1. Recommend a service to handle this rather than building it myself, and say why that one. 2. Walk me through every state I need to handle, including the ones beginners forget, like expired sessions and account deletion. 3. Show me how to make sure people can only see their own data, enforced on the server rather than just hidden in the interface. 4. Tell me honestly whether my app needs accounts at all for a first version.
Open Claude ↗

That last question is worth asking sincerely. The answer is no more often than people expect, and skipping accounts for v1 removes a lot of work and a lot of friction at the same time.


Next: Why some apps just look better →

Go deeper: Chapter 21, Authentication and Identity

Useful? Share this lesson