Connections
Overview
The Connections module manages platform OAuth connections for Lumio accounts. It handles two layers of credentials: app credentials (client_id/client_secret for the user's own Twitch/YouTube/Spotify/etc. app) and channel connections (OAuth access/refresh tokens for the specific channel). The module supports the full OAuth flow with PKCE, CSRF protection via Redis-stored state parameters, automatic token refresh, and encrypted credential storage. All secrets are encrypted at rest using AES-256 derived from a master key.
Architecture
Backend
- GraphQL (
apps/api/src/graphql/connections.rs) -- Queries for listing credentials, channel connections, and connection status. Mutations for saving/deleting credentials, initiating OAuth authorization, and disconnecting channels. - REST (
apps/api/src/routes/connections.rs) -- REST endpoints for credential CRUD, channel connection listing, OAuth authorization initiation, OAuth callback handling, and code exchange. REST routes provide the full OAuth flow with redirect handling. - Crypto (
apps/api/src/crypto.rs) -- AES-256 encryption/decryption for client_id, client_secret, access_token, and refresh_token. Key derived fromconfig.auth.token_encryption_key. - Platforms (
apps/api/src/platforms.rs) -- Platform registry with OAuth configuration (authorize URL, token URL, scopes, extra params) per platform.SUPPORTED_PLATFORMSconstant andis_valid_platform()validation.
Frontend
- Connection settings page with cards per platform showing connection status.
- App credential form for entering client_id/client_secret.
- "Connect" button initiates OAuth flow, redirects to platform, callback saves tokens.
API
GraphQL Queries
| Query | Permission | Description |
|---|---|---|
appCredentials | connections:read | List app credentials for the account. Secrets are masked; only last 4 chars of client_id shown as hint. |
channelConnections | connections:read | List channel connections for the account. Tokens are never exposed. Shows platform, channel ID, channel name, scopes, expiry. |
connectionStatuses | connections:read | Connection status overview for all supported platforms (has_credentials, is_connected, channel_name, enabled) |
enabledProviders(connectionType) | Public (no auth) | List enabled provider slugs for a given connection type (login, channel, or bot) |
GraphQL Mutations
| Mutation | Permission | Description |
|---|---|---|
saveAppCredentials(input: SaveCredentialsInput) | connections:create | Save (upsert) app credentials for a platform. Encrypts client_id and client_secret before storage. |
deleteAppCredentials(platform) | connections:delete | Delete app credentials and disconnect the channel connection |
authorizeChannel(platform) | connections:create | Start OAuth authorization flow. Generates a state parameter (stored in Redis with 10-min TTL), builds the authorization URL with scopes, and returns the redirect URL. |
disconnectChannel(platform) | connections:delete | Disconnect a channel connection (keeps app credentials) |
REST Endpoints
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /v1/connections/credentials | connections:read | List all app credentials |
PUT | /v1/connections/credentials/{platform} | connections:create | Save app credentials |
DELETE | /v1/connections/credentials/{platform} | connections:delete | Delete app credentials + stop platform worker |
GET | /v1/connections/channel | connections:read | List all channel connections |
DELETE | /v1/connections/channel/{platform} | connections:delete | Disconnect a channel |
GET | /v1/connections/channel/{platform}/authorize | connections:create | Initiate OAuth flow (redirect URL) |
GET | /v1/connections/channel/{platform}/callback | -- | OAuth callback handler |
POST | /v1/connections/channel/{platform}/exchange | -- | Exchange OAuth code for tokens |
Permissions
| Permission | Description |
|---|---|
connections:read | View credentials (masked) and channel connections |
connections:create | Save app credentials, initiate OAuth flows |
connections:edit | Edit connection settings |
connections:delete | Delete credentials, disconnect channels |
Database
| Table | Database | Description |
|---|---|---|
app_credentials | PostgreSQL | id, account_id, platform, client_id (encrypted), client_secret (encrypted), created_at, updated_at. Unique on (account_id, platform). |
channel_connections | PostgreSQL | id, account_id, platform, platform_channel_id, channel_name, access_token (encrypted), refresh_token (encrypted), scopes (text array), expires_at, created_at, updated_at. Unique on (account_id, platform). |
Data Flow
OAuth Connection Flow
- User enters app credentials (client_id/client_secret) for a platform.
- Credentials are encrypted with AES-256 and stored in
app_credentials. - User clicks "Connect" which calls
authorizeChannel(platform). - Server generates a CSRF state parameter (
account_id:uuid), stores it in Redis with 10-minute TTL. - Server builds the OAuth authorization URL with the platform's authorize endpoint, scopes, redirect URI, and state.
- Client redirects to the platform's authorization page.
- User authorizes on the platform. Platform redirects back to the callback URL with
codeandstate. - Callback handler validates the state against Redis, exchanges the code for tokens via the platform's token endpoint.
- Access token and refresh token are encrypted and stored in
channel_connections. - Platform worker is started for the new connection.
Security
- Encryption at rest: All client_id, client_secret, access_token, and refresh_token values are encrypted using AES-256 with a key derived from
config.auth.token_encryption_key. - CSRF protection: OAuth state parameter stored in Redis with 10-minute TTL.
- Secret masking: Client secrets and tokens are never exposed in API responses. Only a 4-character hint of the client_id is shown.
- Spotify localhost workaround: For development, Spotify requires
127.0.0.1instead oflocalhostin redirect URIs.
Key Files
| Path | Description |
|---|---|
apps/api/src/graphql/connections.rs | GraphQL queries and mutations |
apps/api/src/routes/connections.rs | REST endpoints including OAuth callback/exchange |
apps/api/src/crypto.rs | AES-256 encryption/decryption utilities |
apps/api/src/platforms.rs | Platform OAuth configuration registry |
apps/api/src/db/connections.rs | Database operations for credentials and connections |