How should multiple SaaS services share OAuth credentials without refresh-token synchronization issues? [closed]

How should multiple SaaS services share OAuth credentials without refresh-token synchronization issues?

I am building a multi-tenant SaaS platform that combines several independently deployed services:

  • Chatwoot for customer communication

  • Postiz for social-media publishing

  • A custom CRM

  • A Next.js frontend

  • A central Django API gateway

Each tenant/company has an isolated Chatwoot account or instance, Postiz workspace, and CRM workspace. Users access these services through our frontend and internal proxy.

The problem

Chatwoot, Postiz, and the CRM may all need access to the same third-party providers, such as:

  • Google Calendar, Meet, Drive, Sheets, Contacts, Gmail, and YouTube

  • Facebook Pages

  • Instagram Business accounts

  • X/Twitter

  • LinkedIn

  • Zoom

Currently, each application can perform its own OAuth flow and store its own access and refresh tokens.

This creates a synchronization problem.

For example:

  1. A tenant connects a Google or Meta account.

  2. The same credentials are copied into Chatwoot, Postiz, and the CRM.

  3. Postiz refreshes the token.

  4. The provider rotates the refresh token.

  5. Chatwoot and the CRM still hold the old refresh token.

  6. Their next refresh attempt fails with an error such as invalid_grant.

We want the user to connect an external account once from our central frontend and then use that connection across all authorized internal services.

Proposed architecture

We are considering a central OAuth and integration service inside the Django gateway.

The central service would be the only component allowed to:

  • Perform OAuth authorization-code exchanges

  • Store access and refresh tokens

  • Refresh or rotate tokens

  • Revoke connections

  • Track scopes, expiry, and connection health

  • Discover provider resources such as Facebook Pages, Instagram accounts, Google Calendars, and YouTube channels

The internal services would store only a central connection_id.

Possible consumption models are:

Option 1: Token broker

Each service requests a current access token when needed:

POST /internal/oauth/token-lease
Authorization: Bearer <service-token>

{
  "tenant_id": "tenant-123",
  "connection_id": "connection-456",
  "required_scopes": [
    "https://www.googleapis.com/auth/calendar.events"
  ]
}

The broker returns a valid access token but never returns the refresh token.

Option 2: Provider API proxy

Internal services never receive provider tokens.

Instead, they call normalized internal APIs such as:

POST /integrations/google/calendar/events
POST /integrations/meta/messages
POST /integrations/instagram/posts
POST /integrations/x/posts

The central integration service refreshes the token if required and calls the external provider.

Option 3: Synchronized local token copies

The central service refreshes tokens and publishes events such as:

{
  "type": "oauth.token.refreshed",
  "connection_id": "connection-456",
  "token_version": 12,
  "expires_at": "2026-08-05T12:00:00Z"
}

Adapters then update token copies inside Chatwoot and Postiz.

This appears easier for compatibility, but it still creates eventual-consistency and token-rotation risks.

Questions

What is the production-ready architecture for this kind of system?

More specifically:

  1. Should there be exactly one token owner per provider authorization grant?

  2. Is a token broker an acceptable design, or should provider API calls always go through a central proxy?

  3. How should existing applications such as Chatwoot and Postiz be integrated when they expect to store and refresh their own tokens?

  4. Is there any safe way to synchronize rotated refresh tokens across multiple services, or should refresh tokens never be copied?

  5. Should one provider account have one combined authorization grant, or separate grants for capabilities such as messaging, publishing, email, calendar, and storage?

  6. How should concurrent token refresh attempts be handled across multiple workers?

  7. What failure-recovery patterns should be used for refresh-token rotation, event delivery, and partial database updates?

Вернуться на верх