How We Normalize OAuth Across 360+ APIs at Unified.to
June 8, 2025

OAuth is inconsistent across APIs due to differences in scopes, token handling, redirect flows, and error responses. Normalizing OAuth means abstracting these differences into a single interface, so developers can authenticate across integrations without handling provider-specific logic.
OAuth 2.0 is a standard, but implementations vary widely across APIs. This article explains how OAuth differs across providers, what it means to normalize OAuth, and how Unified.to abstracts authentication across integrations into a consistent developer interface.
When does OAuth normalization matter?
OAuth normalization is important if:
- You integrate with multiple third-party APIs
- You want a consistent authentication flow across providers
- You need to avoid handling provider-specific scope, token, and refresh logic
- Your product depends on scaling integrations across many customers
If you are integrating with a single API, native OAuth handling may be sufficient. As integration count grows, normalization reduces complexity and maintenance overhead.
What is OAuth normalization?
OAuth normalization is the process of standardizing authentication flows, scopes, token handling, and error responses across different APIs. Instead of implementing provider-specific OAuth logic, developers interact with a single interface that handles differences internally.
This allows applications to scale integrations without increasing authentication complexity.
OAuth handling approaches
| Approach | Description | Tradeoff |
|---|---|---|
| Native OAuth per API | Implement OAuth separately for each provider | Full control, high complexity |
| Partial abstraction | Shared logic with provider-specific overrides | Reduced complexity, still fragmented |
| Fully normalized OAuth | Single interface across integrations | Lowest complexity, abstraction layer required |
Why is OAuth inconsistent across APIs?
OAuth is a standard, but each API implements it differently, including variations in scopes, token formats, redirect flows, and refresh behavior. These differences create inconsistencies that require custom handling for each integration. As a result, developers often need to manage provider-specific edge cases despite using the same underlying protocol.
Why OAuth Fragmentation Slows Teams Down
If you've ever built integrations with multiple third-party APIs, you've probably encountered:
- One provider using
client_credentials, anotherauthorization_code, a third relying on legacy tokens - Scope naming collisions:
read_contactsvs.contacts.readvs.read_people - Redirect URI mismatch errors due to minor differences in path formatting
- HTML errors instead of JSON on expired tokens
- Varying token formats, expiration policies, and re-consent behaviors
- So many refresh strategies; refreshing access token, refreshing the refresh token, time-based and activity-based expiries, re-authentication expiries, …
Each new integration adds more code paths, more exception handling, and more time spent maintaining brittle OAuth logic. In fact, at Unified.to, we've found (and support) more than 70 variations of the OAuth2 'standard'.
Our Design Goals
Unified.to was built to abstract this away. We focused on:
- Supporting all major OAuth grant types & flows
- Standardizing redirect URIs across every integration
- Mapping provider scopes to a unified set
- Handling token exchange, refresh, and revocation uniformly
- Surfacing OAuth errors in a consistent way
- Giving developers a single method to initiate and monitor authorization flows
The following sections describe how OAuth is standardized 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 unified.connect() in our SDK.
Under the hood, we initiate the appropriate flow, handle redirects, and capture tokens. We also expose these tokens 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). Providers are configured to use that during app registration.
That means no environment-specific redirects, no per-provider callback config, and fewer deployment issues. This one endpoint handles all OAuth code exchanges.
3. Unified Scope Abstraction
Instead of asking developers to memorize each provider'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 provider-specific scopes under the hood.
Need a custom scope? You can pass provider-native scope strings too. Unified.to will merge and handle them.
4. Token Management and Refresh
Once tokens are obtained, Unified.to:
- Stores them encrypted or in your own AWS Secrets Manager
- Tracks expiration
- Refreshes access tokens and, if needed, refresh tokens automatically
- Handles provider-specific quirks (e.g. rolling refresh, re-consent windows)
This removes the need for manual token refresh logic, background jobs, and provider-specific expiry handling. If a refresh fails, Unified.to flags the connection and surfaces a consistent 401error and sends your server an event notification.
5. Standardized Error Surfacing
Every provider returns errors differently. Unified.to standardizes them:
401 Unauthorized: Token expired or revoked403 Forbidden: Missing scope or permission400 Bad Request: Invalid config or payload
The authorization also will test the newly created connection to ensure that it has access to the data that your permissions requested. If it doesn't then a 403 error is returned and the connection is not created.
In every OAuth failure (auth rejection, scope issue, redirect error), we surface an error object in a consistent format. Developers handle a consistent set of error responses across all integrations.
6. One SDK, One Interface
Our SDK exposes 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 frontend UI and backend sync logic. No per-integration code required.
7. Pre-build Authorization UI
To make it dead-simple to get your customers to authorize access to their accounts, we've built UI components that you can use directly inside your application with just 1 line of code.
- We have pre-build components for React, Angular, VueJS, Svelte and Javascript.
- Plus you can fork our publicly available source code and redesign it however you like.
- If that isn't enough customization, then just use our API to get a list of activated integrations which will include a logo URL, name, and authorization URL, which you can then style and display however you like (even alongside your existing internally-built integrations).
Key takeaways
- OAuth implementations vary significantly across APIs
- Differences include scopes, token formats, refresh behavior, and error responses
- OAuth normalization standardizes these differences into a single interface
- This reduces integration complexity and maintenance overhead
- Unified.to provides a consistent authentication model across integrations
Why It Matters
OAuth fragmentation isn't just a developer inconvenience. It slows down feature delivery, introduces hard-to-debug issues, and increases risk. Unified.to makes OAuth something you can configure once and scale across all integrations.
You don't have to manage per-API edge cases. You get a unified abstraction for scopes, redirects, errors, token refresh, and storage.
OAuth flows are handled internally, but provided through a consistent interface. Unified.to makes it feel like one integration.