Authorization Middleware

March 17, 2024

Overview

Authorization Middleware is code that sits at the very front of an application between the entrypoint and before any data is accessed. In this context, entrypoint refers to the lines in a codebase where requests are handled by the server.

Authorization Middleware receives scrutiny during an application's App Sec review.

Become familiar with authorization vs authentication.

Table of Contents

Use Cases
RBAC (Role-Based Access Control)
ABAC (Attribute-Based Access Control)
With REST
With GraphQL
Usage
Server Libraries
Cloud Functions
Testing
Design
Propagation
Blocking Request
Conclusion

Use Cases
^

Authorization takes various forms. Two of the most common are:

RBAC (Role-Based Access Control)
^

With RBAC authorization, you simply ascertain a user's role after they've been authenticated. This role is then asserted to be equal (or not) against one or more allow-listed roles for the data that is requested.

ABAC (Attribute-Based Access Control)
^

With REST
^

Implementing Attribute-Based Access Control with REST is simple given that each resource is represented by one endpoint.

With GraphQL
^

Given that GraphQL requests and responses are represented as abstract syntax trees (requests may not be represented this way from the client-side, but the server does convert it), implementing Attribute-Based Access Control requires writing a tree traversal algorithm unless you're working with a library (see Usage below) that provides some entrypoint for checking each node. Note that it should go without saying that Authorization Middleware should be placed on the request-side rather than the response-side (to prevent unnecessary data queries).

Usage
^

Server Libraries
^

Server libraries may provide an entrypoint to provide custom Authorization Middleware through one of their libraries. In this context, entrypoint refers to an Inversion of Control mechanism. For example, Python's Graphene (a GraphQL library) provides a parameter when executing queries to provide custom authorization middleware.

Alternatively, server libraries may accept an argument (to the function responsible for starting the server) that defines a request handler. Python's http.server library is a good example of this.

Cloud Functions
^

Cloud functions (e.g. AWS Lambda) are basically just functions. As such, simple wrapper functions can be used:

const authWrapped = (handler) => {
  return async (event, context) => {
    checkAuthorization(event, context);
    return await handler(event, context);
  }
}

This wrapper function would reside in a common location and be imported into each cloud function (or other serverless codebase). Its usage would be like so:

exports.handler = authWrapped(handler);

Testing
^

Authorization Middleware is one of the most critical components to test thoroughly with maximum coverage. This is not only to assure correct functionality of the existing code, but it's also to prevent regressions as the code evolves.

Learn more about Testing in Software Engineering.

Design
^

There are two primary ways to access the current state of permissions to validate authorization to data:

Propagation
^

One service responsible for changes in permissions can also push any new changes to the other service that is responsible for authorizing users. Alternatively, it could update a shared database. In smaller systems, it may be acceptable for multiple services to share the same database, especially if a common library is created to encapsulate any relational or other data dependencies. In larger systems, a 1-to-1 relationship between database and service is advisable. A push mechanism could be implemented via message queue (producer/consumer pattern), or client-server pattern where the service responsible for authorizing incoming external requests listens for internal requests to update permissions.

Blocking Request
^

The service responsible for authorizing the incoming request makes a blocking request to the service where permission changes are made. This is very common for its simplicity despite the performance impact of necessitating a blocking request for verifying authorization.

Conclusion
^

Authorization Middleware is among the most important components of an application with access control.