Tango (tango v0.1.2)

Copy Markdown View Source

OAuth2 integration library for Elixir applications.

Provides OAuth2 Authorization Code Flow with PKCE support, multi-tenant token management, and provider configuration.

Ready-to-Use API

For Phoenix applications, Tango provides a complete OAuth API that can be mounted with a single line:

# In your Phoenix router
scope "/api/oauth" do
  pipe_through :api
  forward "/", Tango.API.Router
end

See Tango.API for complete setup and usage documentation.

Direct Library Usage

You can also use Tango's functions directly in your application code:

Summary

Functions

Generates OAuth authorization URL with PKCE support.

Cleans up expired OAuth sessions.

Creates a new provider.

Creates provider from Nango configuration.

Creates OAuth session for provider and tenant.

Soft deletes a provider.

Exchanges authorization code for access token.

Gets connection for provider and tenant.

Gets provider by name.

Gets provider by ID.

Gets OAuth session by token.

Lists active connections for a tenant.

Lists active OAuth providers.

Marks connection as used (updates timestamp).

Records the provider rejecting a connection's credentials.

Clears a connection's rejection streak after a call authenticates again.

Refreshes an OAuth connection's access token.

Refreshes connections about to expire.

Revokes a connection for a tenant.

Updates a provider.

Functions

authorize_url(session_token, opts \\ [])

Generates OAuth authorization URL with PKCE support.

Examples

iex> Tango.authorize_url("session_token", redirect_uri: "https://app.com/callback")
{:ok, "https://provider.com/oauth/authorize?..."}

cleanup_expired_sessions()

Cleans up expired OAuth sessions.

Examples

iex> Tango.cleanup_expired_sessions()
{:ok, 5}  # 5 sessions cleaned up

create_provider(attrs)

Creates a new provider.

Examples

iex> Tango.create_provider(%{name: "custom", display_name: "Custom OAuth"})
{:ok, %Tango.Schemas.Provider{}}

create_provider_from_nango(name, nango_config, opts \\ [])

Creates provider from Nango configuration.

Examples

iex> Tango.create_provider_from_nango("github", nango_config, client_id: "abc", client_secret: "xyz")
{:ok, %Tango.Schemas.Provider{}}

create_session(provider_name, tenant_id, opts \\ [])

Creates OAuth session for provider and tenant.

Returns session that can be used to generate authorization URL.

Examples

iex> Tango.create_session("github", "user-123")
{:ok, %Tango.Schemas.OAuthSession{}}

iex> Tango.create_session("nonexistent", "user-123")
{:error, :provider_not_found}

delete_provider(provider)

Soft deletes a provider.

Examples

iex> Tango.delete_provider(provider)
{:ok, %Tango.Schemas.Provider{active: false}}

exchange_code(state, code, tenant_id, opts)

Exchanges authorization code for access token.

Validates session state, exchanges code with provider, and creates connection with multi-tenant isolation.

Examples

iex> Tango.exchange_code("state", "code", "tenant-123", redirect_uri: "https://app.com/callback")
{:ok, %Tango.Schemas.Connection{}}

get_connection_for_provider(provider_name, tenant_id)

Gets connection for provider and tenant.

Examples

iex> Tango.get_connection_for_provider("github", "user-123")
{:ok, %Tango.Schemas.Connection{}}

iex> Tango.get_connection_for_provider("github", "user-123", auto_refresh: true)
{:ok, %Tango.Schemas.Connection{}}  # Automatically refreshed if needed

get_connection_for_provider(provider_name, tenant_id, opts)

See Tango.Connection.get_connection_for_provider/3.

get_provider(name)

Gets provider by name.

Examples

iex> Tango.get_provider("github")
{:ok, %Tango.Schemas.Provider{}}

get_provider_by_id(id)

Gets provider by ID.

Examples

iex> Tango.get_provider_by_id(provider_id)
{:ok, %Tango.Schemas.Provider{}}

get_session(session_token)

Gets OAuth session by token.

Examples

iex> Tango.get_session("session_token")
{:ok, %Tango.Schemas.OAuthSession{}}

list_connections(tenant_id, opts \\ [])

Lists active connections for a tenant.

Examples

iex> Tango.list_connections("user-123")
[%Tango.Schemas.Connection{}, ...]

list_providers()

Lists active OAuth providers.

Examples

iex> Tango.list_providers()
[%Tango.Schemas.Provider{}, ...]

mark_connection_used(connection)

Marks connection as used (updates timestamp).

Examples

iex> Tango.mark_connection_used(connection)
{:ok, %Tango.Schemas.Connection{}}

record_auth_failure(connection, error_reason, opts \\ [])

Records the provider rejecting a connection's credentials.

Call this when a provider rejects the connection's credentials outright — an HTTP 401, or a 403 whose provider-specific error body confirms an invalid or revoked token rather than a policy, scope, or quota denial. Tango cannot see the calls made with the tokens it issues, so a revoked credential stays :active until a consumer reports the rejection. The connection is expired once the rejections reach opts[:max_failures] (default 3), after which get_connection_for_provider/2 returns {:error, :not_found}. Pass a threshold matched to how often the caller hits that provider — the count is a number of rejections, not a duration.

Accepts a connection, or a connection id together with opts[:tenant_id]. Only active connections accept a report.

Examples

iex> Tango.record_auth_failure(connection, "http_401")
{:ok, %Tango.Schemas.Connection{auth_failures: 1}}

iex> Tango.record_auth_failure(connection_id, "http_401", tenant_id: "user-123", max_failures: 10)
{:ok, %Tango.Schemas.Connection{auth_failures: 1}}

record_auth_success(connection, opts \\ [])

Clears a connection's rejection streak after a call authenticates again.

Pairs with record_auth_failure/3 to keep its count consecutive. Accepts a connection, or a connection id together with opts[:tenant_id].

Examples

iex> Tango.record_auth_success(connection)
:ok

refresh_connection(connection)

Refreshes an OAuth connection's access token.

Examples

iex> Tango.refresh_connection(connection)
{:ok, %Tango.Schemas.Connection{}}

refresh_expiring_connections()

Refreshes connections about to expire.

Examples

iex> Tango.refresh_expiring_connections()
{:ok, 3}  # 3 connections refreshed

revoke_connection(connection, tenant_id)

Revokes a connection for a tenant.

Examples

iex> Tango.revoke_connection(connection, "user-123")
{:ok, %Tango.Schemas.Connection{status: :revoked}}

update_provider(provider, attrs)

Updates a provider.

Examples

iex> Tango.update_provider(provider, %{display_name: "New Name"})
{:ok, %Tango.Schemas.Provider{}}