Skip to content

feat(twitch): Add Twitch token refresh#144

Merged
jamiepine merged 2 commits into
spacedriveapp:mainfrom
Nebhay:Twitch-RefreshToken
Feb 22, 2026
Merged

feat(twitch): Add Twitch token refresh#144
jamiepine merged 2 commits into
spacedriveapp:mainfrom
Nebhay:Twitch-RefreshToken

Conversation

@Nebhay

@Nebhay Nebhay commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR integrates Twitch token refreshing into Spacebot using twitch-irc’s RefreshingLoginCredentials, adds persistent storage of Twitch access/refresh tokens,

The end result:

  • Twitch bot connects to chat using a user access token that can expire.
  • Access tokens are automatically refreshed while Spacebot is running.
  • Updated access/refresh tokens are persisted to disk so Spacebot can restart without re-auth.
  • Twitch config can be managed entirely via the Spacebot UI (username, client id, client secret, access token, refresh token).

Details

Twitch token storage and refreshing

  • Implemented TwitchTokenStorage in interface/src/components/ChannelEditModal.tsx as a TokenStorage for RefreshingLoginCredentials:

    • Stores:
      • access_token: String
      • refresh_token: String
      • token_path: Option<PathBuf>
    • load_token():
      • If token_path is set and the file exists, read twitch_token.json and load:
        • access_token
        • refresh_token
        • created_at: Option<DateTime<Utc>>
        • expires_at: Option<DateTime<Utc>>
      • If no file or parse fails, fall back to in-memory values (from config/UI).
      • Always writes back a TwitchTokenFile to twitch_token.json containing:
        • access_token
        • refresh_token
        • created_at (either the stored time or now)
        • expires_at (if known)
      • Returns a UserAccessToken with those fields.
    • update_token():
      • Called by twitch-irc when refresh succeeds.
      • Updates in-memory access_token/refresh_token and timestamps from UserAccessToken.
      • Overwrites twitch_token.json with the new values.
  • Switched Twitch IRC client creation to RefreshingLoginCredentials<TwitchTokenStorage>:

    • Extracts the initial access token from config (strips oauth: prefix if present).
    • Seeds TwitchTokenStorage with:
      • access_token from config
      • refresh_token from config/UI or twitch_token.json
      • token_path pointing at ~/.spacebot/twitch_token.json for the active instance dir.
    • Uses RefreshingLoginCredentials::init(client_id, client_secret, storage) to let twitch-irc:
      • Use the refresh token + client_id/client_secret to call Twitch’s /oauth2/token.
      • Refresh tokens automatically when they are invalid/expired.
      • Persist new tokens via our update_token() implementation.
  • Extended TwitchTokenFile to include timing metadata:

    • created_at: Option<DateTime<Utc>>
    • expires_at: Option<DateTime<Utc>>
    • Allows us to keep a stable creation timestamp across restarts and optionally track expiry if Twitch returns it.

Adapter construction and token file path

  • Standardized the token file name and path:

    • All Twitch adapter entry points now use:
      • token_path = instance_dir.join("twitch_token.json")
    • This is wired in:
      • Daemon startup (src/main.rs)
      • API messaging toggle path (src/api/messaging.rs)
      • Bindings hot-start (src/api/bindings.rs)
      • Config file watcher hot-start (src/config.rs)
  • Updated TwitchAdapter::new signature and all call sites to pass:

    1. username
    2. oauth_token
    3. client_id
    4. client_secret
    5. refresh_token
    6. token_path (Some(instance_dir.join("twitch_token.json")))
    7. channels
    8. trigger_prefix
    9. permissions (Arc<ArcSwap<TwitchPermissions>>)

Config and API wiring

  • Extended Twitch config model to support the new credentials:
    • TOML / config:
      • [messaging.twitch] now supports:
        • username
        • oauth_token
        • client_id
        • client_secret
        • refresh_token
        • channels = ["..."]
        • trigger_prefix
    • API types and handlers:
      • platform_credentials for Twitch now includes:
        • twitch_username
        • twitch_oauth_token
        • twitch_client_id
        • twitch_client_secret
        • twitch_refresh_token
      • When Twitch is configured via the UI, the backend:
        • Writes these fields into the Spacebot config.
        • Ensures the Twitch adapter is enabled/started with the correct token path.

UI updates (Twitch credentials)

  • Updated ChannelEditModal Twitch section in interface/src/components/ChannelEditModal.tsx:
    • New fields:
      • Bot Username
      • Client ID
      • Client Secret (password input)
      • OAuth Access Token (password input)
      • OAuth Refresh Token (password input)
    • handleSaveCredentials() populates platform_credentials with:
      • twitch_username
      • twitch_oauth_token
      • twitch_client_id
      • twitch_client_secret
      • twitch_refresh_token
    • Helper text explains:
      • Tokens should come from the user’s Twitch application.
      • chat:read and chat:write scopes must be enabled.
      • Tokens are stored in the Spacebot instance and refreshed automatically while running.

@jamiepine
jamiepine merged commit 734c4de into spacedriveapp:main Feb 22, 2026
0 of 3 checks passed
rktmeister pushed a commit to rktmeister/spacebot that referenced this pull request Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants