There are many blog posts floating around about “adding authentication to your application”, be it written in Node.js, ASP.NET, Java with Spring Boot, JS in the browser talking to a JSON-based Web API on the server, etc. Most of them handle the login page and password storage, and sometimes logout and a user registration page. But authentication is actually much more than that!
Don't get me wrong, it's great that we can describe in a single blog post how to do such things, but everyone should be aware that this is actually just the beginning of the journey, and most of the time those blog posts don't have any such warnings.
So here are some things to think about when “adding authentication to your application”:
- are you sure you store passwords securely? and verify them securely?
- is your logout secure? (ideally cannot be abused by tricking you just clicking a link on a mail or random site)
- are passwords robust?
- put a lower bound on password length (NIST recommends a minimum of 8 characters); don't set an upper bound, or if you really want to make sure it's high enough (NIST recommends accepting at least 64 characters)
- if possible, check passwords (at registration or change) against known compromised passwords (use Pwned Passwords or similar)
- how well do you handle non-ASCII characters? For example, macOS and Windows encode diacritics differently, so make sure that someone who signed up on one device will be able to sign in on another (put differently, use Unicode normalization on inputs; NIST recommends using NFKC or NFKD)
- do you have a form to securely change the password? (when already authenticated)
- are your forms actually compatible with password managers?
- do you protect against brute-force attacks? if you do (e.g. by locking out accounts, or even just throttling), do you somehow protect legitimate users against DDoS?
- once authenticated, how do you maintain the authenticated state (sessions; btw don't use JWTs)? and is this secure? (in other words, do you protect against session fixation? cross-site request forgery?)
- how long are your sessions? There's a balance between short and long sessions regarding security and convenience, but a choice needs to be made.
- do you have a mechanism to ask for re-authentication before sensitive actions?
- what do you do if a user forgot their password? Password recovery generally requires an email address, do you have one? how can you make sure that the user didn't mistype it and you will actually be able to use it when they need it? Put differently: you need a secure email verification process before you can have a secure password reset process. Implementing those processes securely go beyond the scope of this post, but let's just say we've just come from one single blog post explaining how to “add authentication to your application” to a series of blog posts.
- by the way, now that you store an email address for password reset purpose, how can the user securely update it? and by that I also mean, how do you handle the case where the account got breached and the attacker changes the email address? There's unfortunately no simple answer to that, because there are a handful of cases to handle: the user may have lost access to the previous email, an attacker may have gained access to the previous email, the user may still have access to the previous email but have mistyped the new email, etc.
- speaking of changing passwords, do you make it easier for password managers? (spoiler: through a
/.well-known/change-password
URL) - do you handle multi-factor authentication? do you plan on handling it in the future? If you use SMS to send one-time codes, can the device autofill the form?
- how about passkeys?
That being said, I don't think I ever implemented all of the above perfectly. There are always tradeoffs. But these are things to think about and make choices, and sometimes deliberate choices to postpone things (or just not implement them, after pondering the risks). Unfortunately, I did however see big mistakes in implementations of the various processes hinted above.
Most of the time nowadays, I prefer offloading this to an identity provider, using OpenID Connect or soon Federated Credential Management (FedCM), even if that means shipping an identity provider as part of the deliverables (I generally go with Keycloak, with keycloak-config-cli to provision its configuration). I'm obviously biased though as I work in IT services, developping software mainly for intranets/extranets, and companies now increasingly have their own identity providers or at a minimum have that in their roadmap. So YMMV.
And we've only talked about authentication, not even authorization!
Some resources to go farther:
- NIST SP 800-63-3
- OWASP:
- Troy Hunt's Everything you ever wanted to know about building a secure password reset feature
- Google: