Most web applications require some form of authentication to verify the identity of the user. The best web authentication method depends on the security requirements of the app. Which are the best?
What is authentication and how does it differ from authorization?
When we talk about authentication, we’re referring to the process of verifying someone is who they say they are. In turn, authorization is the process of verifying that person has the right to do something.
Authentication (AuthN) is the process of verifying the identity of a user. You can do that in many ways, but the most common methods are username- and password-based authentication, two-factor authentication, or biometric authentication.
Users can also validate themselves with a certificate or hardware token. When an authentication process fails, the service responds with the HTTP Response Code “401 Unauthorized”.
Authorization (AuthZ) is the process of verifying the permissions of a user. In a standard setting, a failed authorization receives the HTTP Response Code “403 Forbidden”.
Different types of authentication mechanisms
The first step in authenticating a user against a service requires them to provide their credentials. The requested credentials can take multiple forms. We think of a username and password as the most popular credential type, but the user can also present a hardware token or a certificate.
And nowadays, we increasingly use biometric characteristics and OTPs (one-time passwords). Here are a couple of ways users can submit credentials to an application:
HTTP Basic Authentication (RFC 1945)
It’s the simplest form of authentication. It uses a standard header to send the username and password, which are then encoded using Base64.
The advantage of this method is that it’s easy to implement; the disadvantage is the credentials are sent in plain text, so it’s not suitable for applications with high-security requirements.
Digest Authentication (RFC2617)
This type of authentication offers more secure access control than Basic Authentication. Instead of sending the credentials in plain text, they’re encoded using a one-way hashing algorithm.
Even if the credentials are intercepted, they can’t be decoded. However, not all user agents support Digest Authentication, so it’s not suitable for all applications.
This is the most common form of web authentication. It uses an HTML form to collect the username and password, which are then submitted to the server. The advantage of this method is it’s simple to implement and supported by all browsers.
However, the disadvantage is the credentials are sent in plain text, so it’s not suitable for applications with high-security requirements.
This one is more secure than the above-mentioned methods. Either a mutual authentication or a client certificate authentication is implemented, depending on requirements, and the communication is held over a secure access HTTPS channel.
WebAuthn is a modern passwordless open standard that uses asymmetric public key cryptography instead of password-based authentication. This strong authentication method involves a private key and a public key and is considered a type of multi-factor authentication.
Passwordless authentication is supported by all main browsers, user agents, and operating systems. Indeed, many believe we’re heading toward a passwordless future.
Once the user presents their credentials through whatever means configured, the service proceeds with the next steps in the authentication flow. There are two main types of authentication flows: stateful and stateless.
The following sections dive deeper into the technical details of these processes, highlighting the differences, use cases, and pros and cons of each.
Stateful authentication is a more traditional method, relying on storing information about the user's login status on the server. This means that with each request, the server validates to see if the user is still logged in and has the right to access the requested resource. For example, a stateful authentication is using a session cookie.
Once the server receives the user's credentials, it creates a session and stores the data in configured storage via three main ways:
- Server memory
- Cache (for example, Redis or Memcached)
- Database (for example, MongoDB or Postgres)
The server then sends the sessionID back to the user. Typically, it’s sent as a value of a cookie – also referred to as an opaque reference. That means the information about the user can’t be extracted by any party other than the server. SessionID is a random string, and only the server can map it back to the user’s data.
Not only that, but the cookie containing the sessionID is protected, signed with a secret stored by the server. Additionally, the session cookie is protected with appropriate flags. For more information on the security of a cookie, please see RFC6265 (Chapter 8).
Stateful authentication is most commonly used in SSR (server-side rendering) web applications, frameworks such as Spring, and scripting languages.
On the other hand, stateless authentication doesn’t rely on the server to keep track of the user's login status. Instead, it uses a token that’s passed with each request for credentials. This token contains all the information the server needs to verify the user's identity.
The most common stateless authentication methods are OAuth and OpenID.
- OAuth is a popular authentication protocol that allows users to authenticate with a third-party service such as Facebook or Google. This method is very secure, because the credentials are never sent to the server. However, it can be complicated to implement.
- OpenID is an authentication protocol that allows users to authenticate with a third-party service such as Facebook or Google. It’s very easy to implement, but isn’t as secure as OAuth, because the credentials are sent to the server.
With this type of authentication, instead of keeping track of the sessionID and storing the session information on the application server, all information regarding the user’s session is stored in a token. The token is kept on the client side and sent with each user request. The standard is that the token is sent as a value in the HTTP Authorization header.
The difference in the flow compared to stateful authentication is that once the server receives the user’s credentials, it generates a token and sends it back to the user. The server isn’t responsible for remembering the token in any way – this is the client's remit.
The token is self-contained, meaning it contains all the necessary information to validate the user. This has the advantage of reducing the number of database lookups, but a major disadvantage is it’s prone to XSS attacks.
Stateless authentication is most commonly used in SPAs (single-page applications), web APIs, and mobile apps.
JWT (JSON Web Token) is the most commonly used implementation of authentication via a token. JWT is an open standard that provides a compact, self-contained, and URL-safe token that’s signed with either a symmetric or an asymmetric key.
It’s quite easy to implement and has multiple ways of ensuring proper security for your application. For more details, please refer to RFC7519.
Benefits and drawbacks of different authentication methods
The benefits of stateful authentication are it's typically more secure and less complicated to implement. Security is enforced with the proper configuration of cookie flags (i.e. HTTPOnly, SameSite).
The drawbacks? It can be slow and doesn't scale well, because the server must keep data on each user session. Also, there’s concern about CSRF (cross-site request forgery) attacks, and the application has to be secured against this attack vector.
Meanwhile, the benefits of stateless authentication are that it's typically faster and more scalable. The downsides? It's less secure (prone to XSS attacks) and more complicated to implement.
And you must remember that even though the session data isn’t stored on the server, it still has to maintain a database of tokens that were invalidated or revoked.
Regardless of the chosen authentication mechanism, ensure your web application is well protected against cross-site scripting attacks. These can compromise user credentials by leaking them from localStorage or intercepting the session with AJAX requests.
As such, proper implementation of HTTP security headers and TLS encryption are a must.
The authentication method you choose depends on your specific needs. But hopefully, this overview has given you a better understanding of how authentication works and the options available to you.