Urgent.News

What's breaking now, across thousands of outlets.

Tech

The hard part of an internal tool isn't the API. It's the second user.

Every small business ends up paying a monthly fee for software that is, underneath, a database and about five API calls. You know this because you have looked at it and thought I could build that . You are right. You are also wrong about which part is hard. I built the thing. It runs in a 239 MB container, costs $0.000627 per item processed , and talks to a vendor API I am not going to describe…

Every small business pays for software with a database and a handful of API calls. You've undoubtedly built something similar, and realized the real difficulty lies not in the API, but in the second user. I constructed this tool, which processes photos, conducts research, and generates a priced draft for review. While ready-made products exist for this purpose, they charge per user, per month, and store your data on their infrastructure.

This became a problematic trade-off for me when I was already running several independent systems on my own hardware. Consequently, I decided to build the glue connecting these systems instead.

The architecture of the tool is designed to be minimal and adaptable. It contains no model weights, browser, or search index within the container, making it lightweight at only 239 MB. The container relies solely on Python, SQLite, and templates to function. Data remains on the local network, with photos only leaving the network when necessary through a single API. Dependencies can be easily swapped by changing the URL.

The transition to multi-user functionality is a critical aspect that is often overlooked. When a tool transitions from having a single user to accommodating multiple users, security, isolation, and audit requirements become essential. The naive approach of using a tenant_id column and making promises about WHERE clauses often fails when additional queries are introduced.

To prevent this, the API's shape must be carefully designed, requiring a book object to be created with a tenant specified. This ensures that an unscoped accessor cannot be used to forget the filter on.

In the initial implementation, a default tenant was set as "default," which seemed harmless at first. However, this default posed a significant security risk. An unauthenticated request would result in the default tenant's data being accessed. This security flaw was exacerbated by an OAuth callback route, allowing attackers to replay a callback with no session cookie, effectively attaching the default tenant's refresh token to their account.

A simple fix involved setting the tenant to an empty string, with a comment explaining its importance.

There are three authentication modes in this application, each designed for specific use cases: Mode 1 involves nobody authenticating when used solo; Mode 2 utilizes signin with scrypt and session rows for one person; and Mode 3 leverages a forward-auth proxy for several people, without Single Sign-On (SSO). When building internal tools, it's crucial to remember that open defaults with no authentication can lead to silent failures and pose significant security risks.

When users access the tool through a proxy, the Remote-User header should be used to authenticate, ensuring that only requests reaching the port through the proxy are considered valid. If the port cannot be firewalled, the proxy mode should not be used, as it is a promise and not a feature to be switched on.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

More from Monday 7 September →