DEV Community

Cover image for How to Secure the Web: A Comprehensive Guide to Authentication Strategies for Developers
Mahmoud Abbas
Mahmoud Abbas

Posted on • Updated on

How to Secure the Web: A Comprehensive Guide to Authentication Strategies for Developers

Introduction

As the digital world continues to expand, ensuring the security of web applications and protecting user data has become more crucial than ever. One key aspect of web development security is authentication, which involves verifying the identity of users accessing web applications.

With a plethora of authentication strategies available, such as token and session authentication, OAuth, OIDC, and standards like SAML and JWTs, and more, it can be overwhelming for developers to navigate the landscape of options.

In this comprehensive guide, we will delve into various authentication strategies, discussing their strengths and weaknesses, best practices, and practical implementation tips. Whether you're a seasoned developer or just starting out, this guide aims to provide you with a comprehensive overview of authentication strategies to help you secure the web and protect user data effectively.

What is Authentication?

Authentication is the process of verifying the identity of users accessing web applications. This is done by asking users to provide credentials, such as a username and password, to prove that they are who they say they are.
When users provide their credentials, they are typically authenticated by a server, which verifies the credentials and either grants or denies access to the application.

Authentication vs. Authorization

authentication vs authorization
While Authentication makes sure that the users are who they say they are, Authorization determines what they are allowed to do once they are authenticated.

For example, a user may be authenticated as an administrator, but may not be authorized to access certain parts of the application.

Another example is, a user can only have permissions to access and modify their own data, but not other users' data.

Authentication Strategies:

Session-based Authentication

session-based authentication

Session-based authentication has been one of the most common authentication strategy used and was the default way of authentication for a long time. It involves the use of cookies to store session information on the client side.

When a user logs in, the server creates a session and stores it in a database. This means that the connection is stateful. The server then sends a session ID to the client in the form of a cookie.

When the user makes a request to the server, that session ID is included in the request, then the server verifies the session ID in the cookie and grants access to the application if the session is valid. If not, the user/client is denied from access and probably redirected to the main/login page.

When the user logs out, the session is destroyed and the cookie is deleted.

Pros:

  • Easy to implement
  • Small size
  • Long lifespan

Cons:

  • Not scalable, as the server needs to store session information in a database. This means that the server needs to handle a lot of traffic and requests, which can be expensive and time consuming.
  • Not secure, as the session ID is stored in a cookie, which is prone to XSS and CSRF attacks.

Token-based Authentication

token-based authentication

Token-based authentication is very similar to session-based authentication, but instead of storing session information in a database, the server generates a unique JWT token that is sent to the client that and stored in a cookie. This means that the connection is stateless and we don't have the overhead of storing session information in a database.

A JWT token is a string that contains a JSON object that is encoded using Base64. It is signed using a secret key, which is used to verify the token.

When the user makes a request to the server, the token is included in the request in the Authorization header prefixed with the word "Bearer ", then the server verifies the token and grants access to the application if the token is valid. If not, the user/client is denied from access and probably redirected to the main/login page.

When the user logs out, the cookie is destroyed.

Pros:

  • Scalable, as it's not saved in a database.
  • Secure, as the token is signed using a secret key, which is used to verify the token.
  • You can save info about the user in the token, such as the user's role, permissions, etc.

Cons:

  • Not easy to implement natively, as you need to implement a lot of logic to verify the token and handle errors. but you can use an external library to make it easier.
  • Shorter lifespan.
  • Data overhead, as it's generally bigger than a session id and the more data you save in the token, the bigger the token will be.
  • Is still vulnerable to XSS and CSRF attacks, as the token is stored in a cookie.

What should you do to protect your cookies from XSS and CSRF attacks?

  • Use the HttpOnly flag, which prevents the cookie from being accessed by JavaScript. This means that the cookie can only be accessed by the server.
  • Use the Secure flag, which ensures that the cookie is only sent over HTTPS. This means that the cookie can only be accessed by the server over HTTPS.
  • Set the SameSite flag to Strict, which ensures that the cookie is only sent with requests originating from the same site.
  • if you are willing to go the extra mile, you can use a refresh token and an access token. which is the way I prefer to do it.

OAuth

OAuth stands for "Open Authorization" which is a standard for authorization, commonly used as a way for users to grant websites or applications access to their information on other websites but without giving them the passwords. This mechanism is provided by companies such as Facebook, Twitter, and Google to permit the users to share information about their accounts with third party applications or websites.

OAuth 1.0 vs. OAuth 2.0

OAuth 1.0 and OAuth 2.0 are two different versions of the OAuth protocol. While both versions serve the same fundamental purpose, they have some differences in their implementation and features.

Here's a brief comparison between OAuth 1.0 and OAuth 2.0:

OAuth 1.0:

  • Signature-based: uses a signature-based authentication method, where each request from the client includes a signature based on a shared secret and a timestamp. This makes it secure and reliable for authentication.

  • Token and Secret: uses both a token and a secret to authenticate the client and access protected resources.

  • Complex Flow: uses a three-legged authentication flow, which involves obtaining a request token, user authorization, and then exchanging the request token for an access token.

OAuth 2.0:

  • Simpler Flow: uses a simpler two-legged authentication flow, which involves obtaining an access token directly from the authorization server.

  • Token-based: uses a token-based authentication method, where the client presents an access token in each request to access protected resources.

  • Multiple Grant Types: supports multiple grant types, including authorization code, implicit, password, and client credentials, providing more flexibility in authentication scenarios.

  • Scopes: uses scopes to specify the permissions requested by the client, which can be coarse-grained or fine-grained, depending on the implementation.

  • Widely Adopted: has gained widespread adoption and is widely used by popular web services and APIs for authentication and authorization.

In summary, OAuth 1.0 is a signature-based, complex flow with granular permissions, while OAuth 2.0 is a token-based, simpler flow with support for multiple grant types, flows, and scopes. OAuth 2.0 is more widely adopted, but the choice between OAuth 1.0 and OAuth 2.0 depends on the specific requirements of the application and the level of security and complexity desired.

OAuth 2.0 flow

OAuth flow

The most commonly used OAuth 2.0 flow is the Authorization Code Flow. Here's a step-by-step overview of the Authorization Code Flow:

  1. User initiates the authorization process: The user clicks a "Login with (Client Application)" button or takes some other action to initiate the authorization process in the client application.

  2. Client redirects user to authorization server: The client application redirects the user to the authorization server with a request that includes the client ID, redirect URI, and desired scope of access.

  3. User authenticates with the authorization server: The user is prompted to authenticate with the authorization server, providing their credentials (e.g., username and password) to prove their identity.

  4. User grants authorization: After successful authentication, the user is presented with a consent screen where they can review and grant or deny the client's request for access to their protected resources.

  5. Authorization server redirects user back to client: If the user grants authorization, the authorization server redirects the user back to the client application's redirect URI with an authorization code included in the URL.

  6. Client exchanges authorization code for access token: The client application sends a request to the authorization server to exchange the authorization code for an access token. This request includes the authorization code, client ID, client secret, and redirect URI.

  7. Authorization server validates and issues access token: The authorization server validates the authorization code, client ID, client secret, and redirect URI. If they are valid, the authorization server issues an access token and optionally a refresh token to the client.

  8. Client uses access token to access protected resources: The client can then use the received access token to make authorized requests to the protected resources on behalf of the user. The access token serves as proof of authorization.

The Authorization Code Flow is widely used in web applications. However, it also adds additional complexity due to the multiple steps involved, making it more suitable for server-side applications.

OpenID Connect (OIDC)

OpenID Connect is an authentication layer on top of the OAuth 2.0 protocol.

It adds an additional JWT token called an ID token to the Authorization Code Flow. The ID token contains information about the user, such as their name and email address. This information can be used to personalize the user experience and establish an identity for the user.

SAML

Security Assertion Markup Language (SAML) is an XML-based standard for exchanging authentication and authorization data between security domains. It is used by companies to allow their employees to access applications and services from multiple vendors using a single set of credentials. Providing what is known as a single sign-on (SSO) experience for users.

WebAuthn

Web Authentication (WebAuthn) is a new W3C standard for passwordless authentication on the web. It allows users to authenticate to websites using biometric authentication, such as fingerprint or facial recognition, or security keys, such as Yubikeys.

It works by using a public key cryptography system to generate a unique cryptographic key pair for each user.
The private key is stored on the user's device, while the public key is encrypted and stored on the server.

When the user attempts to log in, the server sends a challenge to the user's device, which the user then signs with their private key.
The server then verifies the signature using the public key, and if it's valid, the user is authenticated.

Which one should you use?

For complex applications with multiple users, I would recommend using OIDC. It's more secure and widely adopted.

For web applications only, I would recommend using Token-based authentication with the precautions stated above.

SAML is your best bet if you are building an enterprise application, but sometimes it can be a bit much to handle.

WebAuthn is another great option for web applications, but it's still in its early stages and not widely adopted yet. and it introduces one new challenge - what if the user loses the authenticator.

In my opinion, you can't go wrong with OAuth/OIDC. It's a bit more complex than some other options, especially for smaller applications, but it's secure and widely adopted.

There are other ways to authenticate users, such as 2 factor authentication, One Time passwords, etc. but these are usually used in conjunction with one of the methods mentioned above.

I hope this was helpful. If you have any questions, feel free to contact me.

References

Top comments (12)

Collapse
 
pilcrowonpaper profile image
pilcrowOnPaper

If you're using JWTs, please please please be aware that you cannot revoke existing tokens. This is a major issue if users can change passwords or privileges. In general, sessions will likely be a better choice and most (if not all) major sites use sessions.

Also, using Bearer tokens as stated here:

When the user makes a request to the server, the token is included in the request in the Authorization header prefixed with the word "Bearer ", then the server verifies the token and grants access to the application if the token is valid.

isn't possible if you're storing it with http-only cookies.

if you are willing to go the extra mile, you can use a refresh token and an access token. which is the way I prefer to do it.

Using 2 types of tokens won't make your application more secure if you're storing both of them inside cookies. An attacker will likely have access to the refresh token if they can steal the access token.

Every auth strategy will be susceptible to CSRF and/or XSS since you're storing something onto to browser. Setting same-site to strict means your users won't be logged in if they access your website via a link. This isn't an issue for websites for say banks, but will likely make UX worse for most sites. Check the Origin header for CSRF protection or use traditional CSRF tokens instead.

Collapse
 
fjones profile image
FJones • Edited

Using 2 types of tokens won't make your application more secure if you're storing both of them inside cookies. An attacker will likely have access to the refresh token if they can steal the access token.

Yes, this is true. However, refresh tokens are supposed to be used with short-lived authorization tokens and (importantly) invalidated when reused. This limits the attack potential to at worst two authorization tokens' lifetimes - the originally-hijacked one, and the one fetched with the refresh token, until the real user tries to redeem the refresh token (at which they must be required to re-authenticate, and none of the refresh tokens issued up to this point must be valid anymore).

Obviously this all matters very little if the attack vector is persistent, and authorization tokens should indeed be used as Bearer tokens rather than cookies, but refresh tokens do serve a security purpose.

Collapse
 
nosherwan profile image
Nosh Ghazanfar

Totally agree with you. That is why I have clearly stated those things in the article itself here: dev.to/nosherwan/effective-securit...

Collapse
 
ma7moud3bas profile image
Mahmoud Abbas

Thanks for sharing this.

Will look more into it and update the article accordingly.

Collapse
 
ma7moud3bas profile image
Mahmoud Abbas

These are some good points. thanks for sharing them.

You gotta admit that every one of these approaches has a downside.

Collapse
 
cubiclesocial profile image
cubiclesocial

There's one authentication type you missed: WebAuthn.

In my experience, SAML is a nightmare. When it works, it's a solid SSO solution for the end-user. When it doesn't work, it can take several hours of staring at the configuration on the enterprise side to spot the one thing that was overlooked. In an enterprise setting, there's at least one major SAML related problem every day for some random user. There's no particularly good enterprise alternative to SAML though as it is baked into ADFS, which makes it the de facto standard.

Collapse
 
ma7moud3bas profile image
Mahmoud Abbas

Thanks for sharing this 🙏

I've edited the article to include WebAtuhn.

Also take in mind that this article is just an introduction to the most popular types of auth standerds.

Collapse
 
vdelitz profile image
vdelitz

Great article and easy to understand! Would be cool to see WebAuthn as another standard here as well :)

Collapse
 
ma7moud3bas profile image
Mahmoud Abbas • Edited

Thank you 🙏

I tried to include the ones that are used the most.

Will definitely add more in the future

Collapse
 
kongwoojeong profile image
Zayden

hello I'm a front-end engineer.
I really like your article and would like to translate it, is it possible?

Collapse
 
ma7moud3bas profile image
Mahmoud Abbas

go ahead by all means.

Just share a link to it when you are done.

Collapse
 
simondoll23 profile image
simondoll23

Hi, such a fine sharing I will follow this for my gastric bypass surgery website. Surely, this will help in growing my site as well.