Active OAuth connections with encrypted token storage.
Stores OAuth connections with multi-tenant isolation, token lifecycle management, and automatic refresh capabilities. All sensitive tokens are encrypted at rest.
Summary
Functions
Whether the provider has rejected these credentials enough times to expire them
Checks if connection can be refreshed
Creates a changeset for connection management
Clears a rejection streak after the credentials authenticate again.
Creates connection from OAuth token response
Extracts the raw access token string for API usage
Checks if token needs refresh
Records the provider rejecting the stored credentials.
Records a failed refresh attempt
Updates connection after successful token refresh
Types
@type t() :: %Tango.Schemas.Connection{ __meta__: term(), access_token: binary() | nil, auth_failures: non_neg_integer(), auto_refresh_enabled: boolean(), connection_config: map(), expires_at: DateTime.t() | nil, granted_scopes: [String.t()] | nil, id: integer() | nil, inserted_at: NaiveDateTime.t() | nil, last_auth_failure: String.t() | nil, last_refresh_failure: String.t() | nil, last_used_at: DateTime.t() | nil, lock_version: integer(), metadata: map(), next_refresh_at: DateTime.t() | nil, provider: Tango.Schemas.Provider.t() | Ecto.Association.NotLoaded.t() | nil, provider_id: integer() | nil, raw_payload: map(), refresh_attempts: non_neg_integer(), refresh_exhausted: boolean(), refresh_token: binary() | nil, status: :active | :revoked | :expired, tenant_id: String.t() | nil, token_type: :bearer | :token | nil, updated_at: NaiveDateTime.t() | nil }
Functions
Whether the provider has rejected these credentials enough times to expire them
Checks if connection can be refreshed
Creates a changeset for connection management
Clears a rejection streak after the credentials authenticate again.
Keeps the count consecutive: without this, unrelated rejections spread over months would accumulate to the threshold and expire a working connection.
Creates connection from OAuth token response
Extracts the raw access token string for API usage
Checks if token needs refresh
Records the provider rejecting the stored credentials.
Consumers report a provider's own rejection — an HTTP 401 or 403 answering an
API call — which this library cannot observe for itself. The connection is
expired once the rejections reach opts[:max_failures] (default
3), after which get_connection_for_provider/2
stops handing it out and the consumer can treat the connection as gone.
The threshold is per call rather than library-wide because a Tango deployment serves many providers, each called on its own cadence — and the count is a number of rejections, not a duration. A consumer polling a provider every few seconds reaches a given ceiling within seconds of a transient outage, while one sweeping twice an hour takes days to reach the same count; each caller passes the threshold that matches how often it hits that provider.
A rejection is not a refresh failure and leaves the refresh counters alone.
The two are independent: a connection carrying no refresh token and no expiry
is never eligible for refresh, so its credentials can be rejected forever
while refresh_attempts stays at zero.
Only an :active connection is moved to :expired; a terminal status is
kept, since :revoked and :expired rows age out on different schedules.
Raises ArgumentError when opts[:max_failures] is not a positive integer.
Records a failed refresh attempt
Updates connection after successful token refresh