Badly designed authorization is technical debt

Published by Alex Olivier on December 06, 2022

This article was available first on Hackernoon - read it here.

As software engineers, we often think about authorization in terms of access control and authentication. We design our systems with a combination of user-friendly signup flows and secure logins. However, we don't consider the authorization of users once they're inside our application.

Legacy code usually doesn't have a clean and consistent way to authorize users. Most times, developers will use hard-coding access controls like email address domains or whitelist user IDs to determine who can do what in their application. This means that if you change the database schema or need to open up to a different user group, you'll need to change all those hard-coded values.

Hard coding access controls are bad for reusability. In a monolithic application, it may be manageable to keep all the authorization logic contained in a single file, library, or module, but more often than not this logic is going to be spread across different, disconnected parts of the codebase. Whenever the requirements change, a developer is going to have to go back, find all the places where the logical checks are made, decipher how it was implemented, and then update it - in every location.

This problem is amplified in applications designed in a microservices architecture where business logic is spread across a variety of different code bases - this gets even more painful when the services are written in different languages and you need to implement the logic multiple times and hope that is correct.

Ultimately, this hard-coded authorization leads to technical debt. As your application grows, it becomes harder to maintain this hard-coded logic as they are spread out across different parts of your codebase. If you're lucky enough not to have any bugs or security vulnerabilities in your legacy codebase, then at least it will be difficult for new developers to make changes without breaking other parts of the system.

There's a better way to handle authorization than hard coding access controls. Complicated business logic around who can do what can be extracted out of the application code itself and located in a central service that makes the authorization decisions - essentially decoupling the permissions business logic from the application codebase.

With the business logic extracted, it means that the rules around who can do what can evolve independently of the codebase without having to raise a ticket with a developer. Usually, these requirements sit with a product or security team anyway rather than developers and so should ideally be managed by them.

Cerbos is an implementation of exactly this model, where the logic is decoupled from the codebase and defined as easy-to-understand policy configuration files rather than code. This removes the technical debt of all the authorization logic spread across the codebase and replaces it will a simple ALLOW/DENY conditional check - where the logic itself is provided by a policy decision point running inside your infrastructure.

This article was available first on Hackernoon - read it here.

Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team