Skip to main content

Provider Management

Overview​

Provider Management allows admins to globally enable or disable platform providers (Twitch, YouTube, Kick, Discord, Spotify) with granular controls per connection type. Each provider has a kill-switch that disables everything, plus sub-flags for the connection types it actually supports - login, channel, and/or bot. The specific mix of sub-flags varies per platform:

  • Twitch, YouTube, Kick - login + channel + bot.
  • Discord - login + bot (no channel: Discord is used for auth + the bot, not per-channel OAuth streams).
  • Spotify - channel only (per-account OAuth for music/event integration; there is no Spotify login and no Spotify chat bot). The public enabledPlatforms GraphQL query filters platforms down to those with an enabled :login or :bot sub-flag, so Spotify is intentionally excluded from the "Supported Platforms" list on pricing cards while still being usable as a per-account music integration.

Capability registry​

apps/api/src/platforms.rs (PLATFORMS) is the single source of truth for what each platform can do. It declares four booleans - has_login, has_channel, has_bot, has_integration - and both the admin Providers page and the capability-aware GraphQL guards read it:

PlatformLoginChannelBotIntegration
twitchxxx
youtubexxx
kickxxx
discordxxx
spotifyx
shopifyx

Shopify is registry-only: it has no login, channel or bot capability, so GET /v1/admin/providers and adminProviders filter it out and it never appears on the Provider Management page. Its enablement lives on the integration:shopify feature flag instead. Discord's integration capability covers discord_guild_connections, which is managed on its own screens, not through the sub-flag toggles.

Feature Flag Hierarchy​

Each provider has a kill-switch and sub-flags for different connection types:

platform:twitch <- Kill-switch (disables everything)
+-- platform:twitch:login <- Login via Twitch
+-- platform:twitch:channel <- Channel Connection
+-- platform:twitch:bot <- Bot Connection

The seeded flags (seed_default_feature_flags in apps/api/src/db/admin.rs) are the five provider kill-switches plus: :login for twitch/youtube/kick/discord, :channel for twitch/youtube/kick/spotify, and :bot for twitch/youtube/kick/discord.

Resolution Logic​

  1. If the kill-switch (platform:{provider}) is disabled -- everything is blocked
  2. If the kill-switch is enabled -- check the sub-flag:
    • platform:{provider}:login -- controls login availability
    • platform:{provider}:channel -- controls channel connections
    • platform:{provider}:bot -- controls bot connections
  3. If a sub-flag doesn't exist -- denied. Resolution is fail-closed: FeatureService::is_enabled treats a key that is absent from the global cache as disabled, and get_enabled_providers skips any platform whose platform:{p}:{subtype} key is missing. An unseeded combination (e.g. platform:spotify:bot) is therefore never "allowed by default".

Both levels also honour per-account overrides, so is_provider_enabled(platform, subtype, Some(account_id)) can differ from the global answer.

The global flag cache is refreshed on a 5-minute cycle, but every admin provider toggle calls refresh_global_cache() inline, so a toggle takes effect immediately.

Soft-Block Behavior​

When a provider or sub-flag is disabled:

  • New connections/logins are blocked
  • Existing connections continue working
  • Token refresh continues
  • Global bots keep running
  • Per-account overrides are possible via the admin panel

Architecture​

Backend​

  • Platform registry (apps/api/src/platforms.rs) -- PLATFORMS capability table plus lookup(), used to validate the {platform} path segment (an unknown slug returns 400 Unknown platform: …) and to decide which sub-flag toggles exist.
  • FeatureService (apps/api/src/services/feature_service.rs) -- Core service with is_provider_enabled(platform, subtype, account_id) for two-level flag checks, get_enabled_providers(subtype) for listing enabled platforms per connection type, get_enabled_platforms() for kill-switch-level queries, and get_streaming_platforms() backing enabledPlatforms.
  • GraphQL (apps/api/src/graphql/connections.rs, apps/api/src/graphql/admin.rs) -- enabledProviders(connectionType), enabledPlatforms, connectionStatuses, and the admin adminProviders query with its four set/toggle mutations. Primary path used by all frontend apps.
  • REST (apps/api/src/routes/features.rs) -- Public GET /v1/providers/enabled?type={login|channel|bot} endpoint, kept for external SDK consumers (CLIs, bots, scripts). Frontend apps do not call this - they route through the GraphQL resolver via serverGqlSSR to keep the "Frontend → Next.js proxy → GraphQL" pattern consistent.
  • Admin REST (apps/api/src/routes/admin.rs) -- Admin endpoints for provider stats, enable/toggle, and account connection management.

Frontend​

  • ID App -- SSR login page (apps/id/src/app/login/page.tsx) and signIn callback (apps/id/src/auth.ts) call enabledProviders(connectionType: "login") via serverGqlSSR to gate login buttons.
  • Web App -- Connection flow checks provider enablement before showing connect options.
  • Admin App -- Dedicated Provider Management page for toggling flags and viewing stats.

Admin Management​

Provider Page​

The admin panel includes a dedicated Provider Management page at /providers (apps/admin/src/app/(admin)/providers/), gated on providers:read. Admins can:

  • Toggle the kill-switch per platform
  • Toggle individual sub-flags (Login / Channel / Bot) - only the toggles the platform's capabilities declare are rendered
  • View system credential status (system_credentials_configured) with a link to configure credentials when unset
  • View connection counts (login_connection_count, channel_connection_count, bot_connection_count, integration_count)
  • Connect or disconnect the global bot for platforms with has_bot, which requires system credentials to be configured first

Account Connections​

On the account detail page, admins can:

  • View and delete channel connections
  • View and delete bot connections
  • View and delete StreamElements tokens

User Login Connections​

On the user detail page, admins can delete individual login connections.

API​

Public Endpoints​

MethodPathPermissionDescription
GET/v1/providers/enabled?type={login|channel|bot}none (public)List enabled providers

Admin Endpoints​

MethodPathPermissionDescription
GET/v1/admin/providersproviders:readList all providers with stats (integration-only platforms filtered out)
PATCH/v1/admin/providers/{platform}/enabledproviders:editSet the kill-switch to an explicit value; returns the refreshed provider stats
PATCH/v1/admin/providers/{platform}/{subtype}/enabledproviders:editSet a sub-flag to an explicit value; returns the refreshed provider stats
PATCH/v1/admin/providers/{platform}/togglefeatures:editFlip the kill-switch; returns the raw feature flag
PATCH/v1/admin/providers/{platform}/{subtype}/togglefeatures:editFlip a sub-flag; returns the raw feature flag
GET/v1/admin/accounts/{id}/connectionsaccounts:readList channel connections
DELETE/v1/admin/accounts/{id}/connections/{platform}accounts:editDelete channel connection
GET/v1/admin/accounts/{id}/bot-connectionsaccounts:readList bot connections
DELETE/v1/admin/accounts/{id}/bot-connections/{platform}accounts:editDelete bot connection
GET/v1/admin/accounts/{id}/se-tokensse-tokens:readList SE tokens
DELETE/v1/admin/accounts/{id}/se-tokens/{token_id}se-tokens:deleteDelete SE token
DELETE/v1/admin/users/{id}/login-connections/{provider}users:editDelete login connection

The /enabled and /toggle variants both exist and act on the same feature flags. /enabled is idempotent (you send the target state) and is what the admin UI uses; /toggle flips the current value and is guarded by the broader features:edit rather than providers:edit.

GET /v1/admin/accounts/{id}/connections carries no utoipa::path annotation, so it is absent from apps/api/openapi.json even though the route is live.

GraphQL​

TypeNameGuardDescription
QueryenabledProviders(connectionType: String!): [String!]!noneList enabled providers for login / channel / bot
QueryenabledPlatforms: [String!]!noneKill-switch-enabled platforms that also have an enabled :login or :bot sub-flag. Used by the public pricing page.
QueryconnectionStatuses: [ConnectionStatus!]!connections:readPlatform statuses with enabled field
QuerybotConnectionStatuses: [BotConnectionStatus!]!bot-connections:readBot platform statuses with enabled field
QueryadminProviders: [ProviderInfo!]!providers:read (admin)Providers with capabilities, connection counts and flag status - the query the admin page uses
MutationadminSetProviderEnabled(platform, enabled): Boolean!providers:edit (admin)Set the kill-switch to an explicit value
MutationadminSetProviderSubtypeEnabled(platform, subtype, enabled): Boolean!providers:edit (admin)Set a sub-flag to an explicit value
MutationadminToggleProvider(platform): ProviderInfo!providers:edit (admin)Flip the kill-switch, return refreshed ProviderInfo
MutationadminToggleProviderSubtype(platform, subtype): ProviderInfo!providers:edit (admin)Flip a sub-flag, return refreshed ProviderInfo

Admin mutations use AdminPermissionGuard (admin-role permissions), not the account-scoped PermissionGuard.

WebSocket​

Provider enablement has no WebSocket channel - there is no providers arm in channel_gate_for. Clients pick up a flag change on their next query; the server-side cache is refreshed inline on every toggle.

Per-Account Overrides​

Admins can override provider flags per account using the existing account feature override system. On the account detail page, toggle any platform:* or platform:*:* flag in the Feature Overrides tab.

Key Files​

PathDescription
apps/api/src/services/feature_service.rsCore feature flag resolution logic
apps/api/src/routes/features.rsPublic providers REST endpoint
apps/api/src/routes/admin.rsAdmin provider management endpoints
apps/api/src/db/admin.rsFeature flag DB operations and seed data
apps/api/src/graphql/connections.rsGraphQL queries with provider enablement
apps/api/src/platforms.rsPLATFORMS capability registry (login / channel / bot / integration)
apps/api/src/graphql/admin.rsadminProviders + the four admin provider mutations
apps/admin/src/app/(admin)/providers/provider-management.tsxAdmin Provider Management UI

See Also​