Authentication & Authorization in Web Apps
April 2nd, 2020 | By Karan Gandhi | 9 min read
Most modern web apps require individuals to verify their identity.
Authentication is the process of verifying the identity of an individual. A user can interact with a web application using multiple actions. Access to specific resources can be restricted by using user levels.
Authorization is the process of controlling user access via assigned roles and privileges.
Today, we will approach some Authentication and Authorization concepts and security recommendations.
Authentication
Authentication is the process of verifying identity. A unique identifier is associated with a user, which is the username or user ID.
Traditionally, we combine username and password to authenticate a user. The authentication logic has to be maintained locally. So we will term it local authentication. Apart from local authentication, we can use OpenID, OAuth, and SAML as authorization providers. Let's cover them step by step.
Local Authentication
The most common authentication technique is using a username and password. The usual flow while implementing is the following:
The user registers using an identifier like a username, email, or mobile.
The application stores user credentials in the database.
The application sends a verification email or message to validate the registration.
After successful registration, the user enters credentials for logging in.
On successful authentication, the user is allowed access to specific resources.
The user state is maintained via Sessions or JWT.
OpenID or OAuth
OpenID is an authentication protocol to authenticate users without using a local authentication system. In such a scenario, a user has to be registered with an OpenID provider, and the same provider should be integrated with our authentication flow.
To verify the details, we forward the authentication requests to the provider. On successful authentication, we receive a success message and profile details, with which we can execute the necessary flow.
OAuth is an authorization mechanism that allows our application's users access to a provider. On successful responses, we receive a token with which we can access certain APIs on behalf of a user.
OAuth is convenient if your business use case requires certain user-facing APIs, like access to Google Drive or sending tweets on your behalf.
Most OAuth 2.0 providers can be used for pseudo-auth. Thus, it can get pretty complicated if you use multiple OAuth providers to authenticate users on top of the local authentication system.
Multi-Factor Authentication
Users are generally recommended to have different passwords for different websites or use password managers to secure their identity. However, in reality, a major chunk of people reuse their passwords. This makes them vulnerable to credential sniffing (as this XKCD comic brilliantly explains).
If an attacker has access to unsalted passwords from a dump of breached applications, he can use them to log in to our application.
To reduce the risk, we can implement multi-factor authentication in our application.
Multi-Factor authentication is when a user is authenticated using two or more factors as authentication methods. The factors are listed below.
Factor | Example |
---|---|
Something You Know | Passwords, PINs, TAN, and security questions |
Something You Have | USB keys, Software tokens, certificates, email, SMS, and phone calls |
Something You Are | Biometrics (fingerprints/iris scans, Facial Recognition), typing speed, key pattern interval |
Location | Source IP ranges and geolocation |
The common second factors implemented in applications are:
Email
OTP via SMS / Phones
TOTP (Time-based OTP) apps like Google Authenticator / Authy
x.509 certificates
The location-based factor is used to implement geographical restrictions. IP addresses can be used to allow/block users from certain countries. This is common practice in streaming and banking applications. It's easier to access geographical data from a mobile phone or any GPS-enabled device.
FIDO2-compliant biometric devices and USB keys can leverage the WebAuthn API to handle the authentication. WebAuthn is a new browser API that makes it easier to implement a second factor for authentication.
Mobile Device User Authentication vs User Authentication
This is a somewhat newer scenario. Under most circumstances, we login to our mobile phones using our Google or iCloud accounts.
As a device user, the account can store our private data, have access to multiple apps with persistent logins, and is associated with multiple payment providers. There can be a case where our application user and the device user can be different.
While executing a critical transaction, we would like to associate a device owner with our application user OR we would like a device owner to authenticate the application users. In such cases, we have to add an extra layer of security.
On Android, we can use biometric auth and keyguard manager. On iOS, we can use Local Authentication to verify the device user.
Authentication Libraries
Let’s take a look at common Node.JS authentication libraries.
PassportJS
PassportJS is one of the most popular auth libraries for Express. Apart from Local Authentication, Passport has support for OpenID, OAuth 1.0, SAML, and OAuth 2.0.
There are around 500 providers/strategies which can be used with Passport. You can check our recent tutorial which covers Passport.
Grant
Grant is another auth library. It has support for Express, Hapi, and Koa. Like Passport, the grant supports OpenID connect OAuth 1.0a & OAuth 2.0. There are currently 180 supported providers.
Firebase Authentication
Firebase Auth has limited OAuth providers (Facebook, Github, Twitter, Google, Apple, Microsoft). However, it does provide Auth for email login, anonymous login, and phone number login.
A full authentication workflow is provided by the Firebase Auth API. Also, we can link Multiple OAuth users to a single user.
Coupled with other Firebase products (Push, Database, Storage, Hosting, Crashlytics, Functions), this can be a very good fit for small projects.
Authentication through OWASP's Lens
Broken Authentication is ranked #2 in OWASP Top 10 and #4 in OWASP Mobile Top 10. From OWASP itself:
Confirmation of the user’s identity, authentication, and session management is critical to protect against authentication-related attacks.
There may be authentication weaknesses if the application:
Permits automated attacks such as credential stuffing, where the attacker has a list of valid usernames and passwords.
Permits brute force or other automated attacks.
Permits default, weak, or well-known passwords, such as “Password1” or “admin/admin“.
Uses weak or ineffective credential recovery and forgot-password processes, such as “knowledge-based answers”, which cannot be made safe.
Uses plain text, encrypted, or weakly hashed passwords (see A3:2017-Sensitive Data Exposure).
Has missing or ineffective multi-factor authentication.
Exposes Session IDs in the URL (e.g., URL rewriting).
Does not rotate Session IDs after successful login.
Does not properly invalidate Session IDs. User sessions or authentication tokens (particularly single sign-on (SSO) tokens) >* aren’t properly invalidated during logout or a period of inactivity.
Taking these points into account, we can strengthen our application by:
Hashing and salting the passwords - plaintext passwords are a huge security risk. Use libraries like bcrypt to implement hashes with the maximum rounds your CPU can afford (also, check this blog post for further reading on hashing algorithms);
Using password strength estimators like owasp-password-strength-test to enforce a strong password policy;
Not truncating the passwords;
Notifying users to update passwords regularly;
Reauthenticating users while performing a critical transaction like payment or account update;
Transmitting passwords over TLS (HTTPS) only;
Not leaking any information in error messages. Login failed. The password for user Karan is wrong is a bad message. Login failed: Invalid user or password is a good message.
For resetting passwords, we will take the following points into consideration:
Send an email to the user;
Create a temporary session for a password reset;
Do not display user credentials on the screen;
Verify the user using security questions / TOTP codes;
Redirect the user to a form;
Change the password in the same session.
So far, we have covered some techniques and best practices associated with Authentication. Now, let's look at Authorization.
Authorization
Authorization is a process by which we can allow or restrict resources. Depending on the business logic, the requirement for user authorization can vary.
Let's take a CMS as an example. Blog readers can read content without authentication. To create a post in the blog, a user will have to sign up as an author.
To publish a post, the user must have editor privileges. To make site-wide changes he must have Administrator privileges.
In this example, user authentication is not required to read a post but it's required to publish one.
For the sake of this example let’s define & assign some routes.
The reader role has access to /blog routes & can read all published posts. The author role has access to /blog/post routes & can write a post. The editor role has access to /blog/editor routes & can publish posts. The administrator role has access to /blog/admin routes & can do whatever he wants.
Let's assume the business expands and there is a requirement for separate Security & JS editors.
Now, in an enhanced role:
Security Editor has access to /blog/editor but can only publish posts marked with a security tag. JS Editor has access to /blog/editor but can only publish posts marked with a js tag. Global Editor has access to /blog/editor and can publish posts with all tags.
Let's expand the scenario further. A chief editor is chosen from 10 editors. One of the additional duties of the chief editor is to create reports for the authors. This action is usually assigned to administrators.
The developer creates a custom action and adds the privilege to a user. The chief editor can now create reports using the /blog/reports route.
Post registration, a user can be assigned certain roles like Author or Editor. The author role doesn't have access to /posts/editor, so he is authenticated but not authorized.
In enhanced role management, two new sub-roles were created which had authorization levels of an editor but with restrictions placed with the help of tags. This is roughly the basis of any authorization scenario:
Create defined roles as per specific use cases.
Extend or restrict certain roles depending on use cases
Assign custom actions to a user to fine-grain.
Implementing Authorized Routes (Express / Angular)
Consider a function Auth which checks user authentication.
function Auth(){
...
return auth.role;
}
We can implement Auth middleware in express using:
function checkAuth(res, req, next){
if(Auth() === 'Editor')
return next();
res.redirect('/blog')
}
app.get('/blog/editor', checkAuth, function(req, res) {
res.send('Success');
});
Angular has the CanActivate interface which acts as a Route Guard. First, we define an AuthRouteGuard class:
import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
@Injectable()
export class AuthRouteGuard implements CanActivate {
constructor() {}
canActivate() {
return this.Auth();
}
Auth(){
...
return auth.editor.status;
}
}
In Route config, we define:
import { Routes, CanActivate } from '@angular/router';
import { EditorPage } from './angular/editor-page';
import { AuthRouteGuard } from './auth-route-guard';
export const ROUTES: Routes = [
{
path: 'protected',
component: ProtectedPage,
canActivate: [AuthRouteGuard]
},
{ path: '**', redirectTo: '' }
];
When CanActivate returns true, the user can activate the route. We have to define auth logic in the Auth() or in a separate service.
In the Express snippet, we are blocking disallowed access to a specific user role (Editor). In the Angular snippet, we have assumed a boolean editor.status which is a custom privilege assigned to every user.
Authorization through OWASP's Lens
The most common attack associated with Authorization is privilege escalation. An example of this would be an author discovering a vulnerability and publishing Java tutorials on a JavaScript blog.
Broken Access Control in OWASP Top Ten and Insecure Authorization in OWASP Mobile Top Ten are the risks associated with Authorization.
As OWASP puts it:
Access control enforces a policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification or destruction of all data, or performing a business function outside of the limits of the user. Common access control vulnerabilities include:
Bypassing access control checks by modifying the URL, internal application state, or the HTML page, or simply using a custom API attack tool.
Allowing the primary key to be changed to another’s users' record, permitting viewing or editing someone else’s account.
Elevation of privilege. Acting as a user without being logged in, or acting as an admin when logged in as a user.
Metadata manipulation, such as replaying or tampering with a JSON Web Token (JWT) access control token or a cookie or hidden field manipulated to elevate privileges, or abusing JWT invalidation
CORS misconfiguration allows unauthorized API access.
Force browsing to authenticated pages as an unauthenticated user or privileged pages as a standard user. Accessing API with missing access controls for POST, PUT and DELETE.
To strengthen Authorization, we should:
Use the Reject-All strategy for everything except public routes.
Implement logging for all privileged actions
Invalidate sessions & tokens after logout/timeout.
Final Thoughts
We have covered some concepts of Authentication & Authorization. Authentication is still a major security risk. OWASP features it as an A2 risk in the OWASP Top Ten Web Application Security Risks.
As a developer, it's important to invest in secure coding practices. Web attacks are growing and extra efforts have to be made to secure Web apps.
Besides the topics we covered here today, another important security practice in web apps is protecting their JavaScript source code.
See our tutorials on protecting React, Vue, React Native, Ionic, and NativeScript.
Jscrambler
The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.
View All ArticlesMust read next
Vue.js Authentication System with Node.js Backend
In this tutorial, we'll explore different authentication types for JavaScript applications and build a Vue authentication system with a Node.js backend.
October 18, 2018 | By Lamin Sanneh | 17 min read
How To Integrate Firebase Authentication With an Expo App
In this tutorial, let's take a look at how as a mobile developer building applications using Expo SDK, you can integrate and use Firebase Authentication.
July 1, 2021 | By Aman Mittal | 14 min read