StreamElements Tokens
Overview
The SE Tokens module manages StreamElements JWT tokens used for receiving tip/donation events via the StreamElements WebSocket API. Tokens are stored encrypted at rest and scoped per account+platform. Creating a token automatically starts a StreamElements WebSocket worker; deleting the last token for an account stops it.
Supported platforms: Twitch, YouTube, Kick, Trovo.
Architecture
Dashboard UI
|
v
Next.js API Proxy (/api/se-tokens)
|
+---> REST API (GET/POST/DELETE /v1/se-tokens)
| |
| +--> WorkerManager (start/stop SE WebSocket worker)
|
+---> GraphQL (SeTokenQuery / SeTokenMutation)
|
v
db::se_tokens (PostgreSQL, encrypted token storage)
Token Lifecycle
- Create -- User provides their StreamElements JWT token and platform. The token is encrypted with AES using a derived key from
auth.token_encryption_keyand stored via upsert (one token per account+platform). - Worker Start -- The REST layer starts a
StreamElementsConfigworker viaWorkerManager, passing the unencrypted token for the WebSocket connection. - List -- Returns tokens with masked hints (first 4 + last 4 chars, middle replaced with
***). The actual token value is never returned. - Delete -- Removes the token. If no tokens remain for the account, the SE worker is stopped via
WorkerManager.stop_platform_worker. - Boot Recovery --
list_all_accounts_with_tokensis used at server startup to auto-start SE workers for all accounts with stored tokens.
Token Masking
Tokens returned to clients show only a hint: eyJh***ab12. If the token is 8 characters or shorter, or decryption fails, **** is returned instead.
API
REST Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET | /v1/se-tokens | List all SE tokens (masked) | se-tokens:read |
POST | /v1/se-tokens | Create/update an SE token | se-tokens:create |
DELETE | /v1/se-tokens/{id} | Delete an SE token | se-tokens:delete |
POST /v1/se-tokens
{
"platform": "twitch",
"token": "eyJhbGciOiJI...",
"label": "My SE Token"
}
Validation:
platformmust be one of:twitch,youtube,kick,trovotokenmust not be empty
Response (201): Returns the created token with masked hint and starts the SE worker.
GraphQL Queries
| Query | Args | Returns | Permission |
|---|---|---|---|
seTokens | -- | [SeToken] | se-tokens:read |
GraphQL Mutations
| Mutation | Args | Returns | Permission |
|---|---|---|---|
createSeToken | platform: String, token: String, label?: String | SeToken | se-tokens:create |
deleteSeToken | id: UUID | Boolean | se-tokens:delete |
Note: The GraphQL layer does not have access to WorkerManager, so worker lifecycle is handled exclusively by the REST endpoints.
GraphQL Types
type SeToken {
id: UUID!
platform: String!
tokenHint: String!
label: String
createdAt: String!
updatedAt: String!
}
Permissions
| Permission | Description |
|---|---|
se-tokens:read | List SE tokens |
se-tokens:create | Create/update SE tokens |
se-tokens:delete | Delete SE tokens |
Included in: Owner, Administrator roles.
Database
Table: se_tokens
| Column | Type | Description |
|---|---|---|
id | UUID (PK) | Token ID |
account_id | UUID (FK) | Owning account |
platform | TEXT | Platform identifier |
token | TEXT | Encrypted JWT token |
label | TEXT | Optional user label |
created_at | TIMESTAMPTZ | Creation timestamp |
updated_at | TIMESTAMPTZ | Last update timestamp |
Unique constraint: (account_id, platform) -- one token per platform per account.
DB Functions
| Function | Description |
|---|---|
list_tokens | List all tokens for an account, ordered by platform |
upsert_token | Insert or update on (account_id, platform) conflict |
delete_token | Delete by ID with account ownership check |
has_tokens | Check if an account has any tokens |
list_all_accounts_with_tokens | Boot-time recovery: all accounts grouped with their tokens |
Key Files
| File | Purpose |
|---|---|
apps/api/src/graphql/se_tokens.rs | GraphQL queries and mutations |
apps/api/src/routes/se_tokens.rs | REST endpoints with worker lifecycle management |
apps/api/src/db/se_tokens.rs | Database CRUD operations |
crates/lo-auth/src/rbac.rs | Permission constants (se-tokens:read/create/delete) |