Offbeat Software Solutions
Back/Home/Blogs/Integrating a Legacy System with Modern APIs: The Pattern That Actually Holds Up

Integrating a Legacy System with Modern APIs: The Pattern That Actually Holds Up

The integration pattern that keeps working as systems change: put a boundary in front of the legacy system instead of handing it direct credentials to whatever it needs to reach.

9/7/2026
4 min read

Article

Most "integration" problems aren't really about APIs - they're about what a legacy system was never designed to do. A ten-year-old application built around direct database access or a single SMTP connection doesn't have a concept of "authenticate as a service, get a scoped token, call an endpoint." Bolting modern integration onto it usually goes one of two ways: give the legacy system broad, long-lived credentials to whatever it needs to reach, or put a real boundary between the two systems. Only one of those holds up over time.

Why direct credentials are the wrong default

The easy path is also the one that creates the most risk: give the legacy application a service account, a shared SMTP login, or a database connection string with more access than the actual task needs, and let it talk directly to whatever it's connecting to. It works immediately. It also means that credential now lives inside a codebase nobody fully understands, with no record of what it was actually used for, and no way to revoke access to one integration without breaking every other thing using the same credential.

We hit this directly on a project where several internal applications - including a legacy program with no modern authentication story - needed to send email through an organization's Office 365 SMTP relay. The obvious approach was giving each application its own SMTP credentials. Instead, we built a serverless middleware layer: Amazon Cognito issues short-lived tokens, API Gateway validates every request against Cognito before it goes anywhere, and a stateless Lambda function handles the actual send. The legacy program - and every other client app - never touches an SMTP credential directly. Every send is logged to an audit trail in RDS, so there's a real answer to "what did this system actually send" instead of a shared login with no accountability.

Assessment before integration, not instead of it

The pattern above only works if you actually understand what the legacy system is doing first. A four-year engagement extending a multi-tenant GIS platform's integration surface - connecting it to Esri ArcGIS for mapping and reporting, and building an automated geocoding pipeline so property addresses didn't need manual lat/lon entry - only worked because the assessment phase mapped what the existing system actually depended on before any new integration touched it. Undocumented schema dependencies, ad hoc queries, and tightly coupled logic are exactly what an integration project needs to find before it connects anything new, not after something breaks.

What this looks like in practice

  • Map what the legacy system actually does before deciding how to connect it - reading the code and tracing data flows, not relying on documentation that's usually missing or wrong.
  • Put an API boundary in front of it rather than giving it direct database or service credentials to the system on the other side.
  • Scope access to the specific task, not blanket permissions - a geocoding pipeline needs address data, not full database access.
  • Log what actually happens at the integration boundary, so there's a real audit trail instead of a shared credential with no record of use.
  • Treat the legacy side as fixed unless there's a reason to touch it - the goal is usually connecting systems, not rewriting the older one as a side effect.

When this gets harder

Some legacy systems don't have a clean seam to put a boundary at - the "API" is a shared database table, or a file drop, or a scheduled export nobody remembers setting up. That's still solvable, but it means the assessment phase takes longer and the integration approach has to work around constraints a modern system wouldn't have. That's normal, not a sign the project is a bad fit - it just means the plan has to be honest about what the legacy side can and can't do before committing to an architecture.

For a broader look at integration patterns beyond this specific security angle - adapter layers, protocol mismatches, and the Anti-Corruption Layer pattern - see Connecting Legacy Applications to Modern APIs.

Need Help With Engineering?

Building business applications, SaaS products, integrations and mobile/eCommerce systems from the ground up.