Unified.to
All articles

How We Normalize OAuth Across 460+ APIs at Unified.to


June 8, 2025

oauth_unified.to.png

Updated May 2026

OAuth 2.0 is a standard in theory. In practice, it's one of the most fragmented layers in API integrations.

Scopes vary. Token lifecycles behave differently. Redirect flows break in subtle ways. Error responses are inconsistent. The result is the same across every team that scales integrations: each new API adds bespoke OAuth logic, new edge cases, and ongoing maintenance.

OAuth normalization removes that per-API work by turning provider-specific authentication into a single, consistent interface — one your application learns once and reuses across every integration.

This article breaks down where OAuth diverges across APIs, why it creates real engineering drag, and how Unified.to abstracts it so that you never have to read a third-party provider's authentication documentation again.

When OAuth normalization matters

You start to feel OAuth pain when:

  • You integrate with more than a handful of third-party APIs
  • Your product depends on scaling integrations across many customers
  • You want a consistent authentication experience across integrations
  • Your team is spending time debugging token, scope, or redirect issues

If you're integrating a single API, native OAuth handling is fine. At scale, it becomes a liability — every integration you add multiplies the auth surface you maintain.

Why OAuth is fragmented

OAuth 2.0 defines a framework, not a strict implementation. Each API interprets it differently across:

  • Grant types (authorization_code, client_credentials, legacy patterns)
  • Scope naming and structure
  • Token formats, expiry, and refresh behavior
  • Redirect URI handling
  • Error formats (JSON vs HTML, inconsistent status codes)

In practice, this means OAuth is not portable. Each integration introduces new edge cases:

  • One API expires refresh tokens silently; another rotates them on every use
  • One uses contacts.read; another uses read_people; a third uses read_contacts
  • One returns structured JSON errors; another returns an HTML page on an expired token
  • Refresh strategies differ: refreshing the access token, refreshing the refresh token, time-based and activity-based expiries, re-consent windows

At Unified.to, across the integrations we support, we've found and handle more than 70 variations of the OAuth 2 "standard." Multiply those across dozens of integrations and OAuth becomes a significant, recurring source of engineering complexity — most of it maintenance, not initial build.

What is OAuth normalization?

OAuth normalization standardizes authentication flows, scopes, token handling, and error responses across different APIs, so developers interact with one consistent model instead of provider-specific logic.

It removes:

  • Per-API grant-type handling
  • Provider-specific scope strings
  • Manual token storage, expiry tracking, and refresh logic
  • Inconsistent, provider-specific error formats

And it lets you scale integrations without scaling authentication complexity.

Approaches to OAuth handling

ApproachDescriptionTradeoff
Native OAuth per APIImplement OAuth separately for each integrationFull control, high maintenance
Partial abstractionShared logic with provider-specific overridesReduced complexity, still fragmented
Fully normalized OAuthSingle interface across integrationsLowest complexity, abstraction layer required

The mental model: one connection ID, not per-provider auth state

Before the mechanics, the shift that matters most: with normalized OAuth, you stop tracking per-provider tokens, scopes, and refresh cycles in your own code. You hold a single connection ID.

That connection ID is the only artifact your application needs. It works for every API call, for webhook creation, and for MCP access — for the life of the connection. Token exchange, refresh, expiry, and provider-specific quirks happen behind it. Your application's job is reduced from "manage OAuth for each integration" to "hold an ID and make calls."

This is the right way for teams to think about authentication at scale: the integration layer owns the auth complexity, and your code owns a reference to it.

The following sections describe how Unified.to delivers that.

How Unified.to normalizes OAuth

Unified.to was built to remove OAuth fragmentation across integrations.

1. Grant type normalization

Unified.to supports authorization_code, client_credentials, password and refresh_token flows. We also support API key/token-based authorization where applicable. For each integration, we define the required grant type and credentials internally. Developers only need to call connect() in our SDK.

Under the hood, we initiate the appropriate flow, handle redirects, and capture tokens. We then make those tokens available to your infrastructure via secure storage, or store them encrypted and scoped per connection.

2. Unified redirect URIs

We use a single redirect URI across all integrations: https://api.unified.to/oauth/code (plus EU and AU versions). Integrations are configured to use that during app registration.

That means no environment-specific redirects, no per-integration callback configuration, and fewer deployment issues. One endpoint handles all OAuth code exchanges.

3. Unified scope abstraction

Instead of asking developers to memorize each integration's scope strings, we maintain a library of unified scopes (e.g. crm_contact_read, storage_file_write, calendar_event_read).

In the Unified.to SDK or dashboard, you select these abstract scopes. We map them to integration-specific scopes under the hood.

Need a custom scope? You can pass provider-native scope strings too. Unified.to merges and handles them.

4. Token management and refresh

Once tokens are obtained, Unified.to:

  • Stores them encrypted, or in your own customer-managed secret store
  • Tracks expiration
  • Refreshes access tokens, and where needed refresh tokens, automatically
  • Handles integration-specific quirks (rolling refresh, re-consent windows)

This removes the need for manual token refresh logic, scheduled refresh jobs, and provider-specific expiry handling. Automatic refresh runs until the underlying refresh token itself is invalidated by the source — through revocation, an admin policy, or inactivity — at which point the connection is flagged for reauthorization rather than failing silently.

For teams with stricter requirements, customer-managed secrets are available on the Scale tier: store OAuth credentials in your own AWS Secrets Manager, Azure Key Vault, Google Cloud Secret Manager, or HashiCorp Vault rather than in Unified.to's database.

5. Standardized error surfacing

Every integration returns errors differently. Unified.to standardizes them:

  • 401 Unauthorized: Token expired or revoked
  • 403 Forbidden: Missing scope or permission
  • 400 Bad Request: Invalid configuration or payload

In every OAuth failure — auth rejection, scope issue, redirect error — we surface an error object in a consistent format. Your application handles one known set of error responses across all integrations instead of one per integration.

6. Connections are tested before you ever receive them

When a connection is created, Unified.to tests it to confirm it actually has access to the data your requested permissions cover. If it doesn't, a 403 is returned and the connection is not created.

The practical effect: you never receive a broken connection. A connection handed to your application has already been verified against the permissions you asked for.

7. Connection health and change events

Connection health is dynamic and can change with each API call — a customer revokes access, an admin restricts scopes, an API key entered in a non-OAuth flow turns out to be wrong.

Rather than polling for this, you subscribe to connection events. Set a notifications webhook URL in your workspace, and your backend receives a POST whenever a connection's health or authorization state changes — for example, when tokens expire, permissions are revoked, or a reconnect is required. These events let you react to revoked access, unhealthy connections, or required reauthorization without polling. (See the docs for the full list of event types.)

8. One SDK, one interface

Our SDK provides a single connect() method for initiating OAuth and a getConnection() method for retrieving status and metadata.

Each connection object includes:

  • Connection ID
  • Status (healthy, unhealthy, needs_reconnect)
  • Scopes granted
  • Refresh history
  • Error state if present

This simplifies both frontend UI and backend logic. No per-integration auth code required.

9. Pre-built authorization UI

Getting your customers to authorize access to their accounts is often the hardest part of an integration — and the person doing it frequently isn't technical. To make that step straightforward, we provide UI components you can drop into your application with one line of code:

  1. Pre-built components for React, Angular, Vue, Svelte, and JavaScript
  2. Fork our publicly available source code and redesign it however you like
  3. Or call our API to get a list of activated integrations — each with a logo URL, name, and authorization URL — and style and display them however you like, even alongside your existing internally-built integrations

The authorization flow is multilingual by default, adapting to the end user's browser language, and includes step-by-step instructions for non-technical end users who need to locate and enter their own credentials.

Why this matters

OAuth fragmentation isn't just a developer inconvenience. It slows feature delivery, introduces hard-to-debug failures, and increases long-term maintenance cost. Most teams underestimate how much time goes into auth edge cases until they try to scale integrations — and the cost is recurring, because source APIs change their auth behavior over time.

Normalization turns OAuth into something you configure once and reuse:

  • One connect() method and one connection ID across every integration
  • One redirect URI, one scope vocabulary, one error format
  • Token refresh, health monitoring, and reauthorization handled for you
  • No per-API auth logic to write or maintain

That's the larger promise behind it: our customers use Unified.to's documentation and never have to read a third-party integration's authentication docs to ship and maintain a connection. OAuth flows are handled internally and surfaced through a single consistent interface, so connecting 460+ integrations feels like connecting one.

Explore Unified.to's OAuth docs

All articles