Commit500a3b75Recorded25 Mar 2026Repositorysigil-twitch
Add sigil-oauth integration for OAuth token management
Message
Add (twitch oauth) module providing: - twitch-oauth-config: Twitch preset with stream/chat/analytics scopes - twitch-oauth-client: build twitch-client from oauth-tokens + client-id - twitch-ensure-client: auto-refresh with token persistence - Token storage wrappers (twitch-save/load/clear-tokens) - Re-exports of core sigil-oauth symbols for convenience
Add sigil-oauth, sigil-crypto, sigil-log as dependencies. Update README with OAuth usage examples.
Changed
README.md | 27 +++++++++++++++++++++++++++
dev-redirects.sgl | 5 ++++-
package.sgl | 6 +++++-
src/twitch/oauth.sgl | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+), 2 deletions(-)Diff
README.mdmodified
@@ -27,6 +27,7 @@ interaction, and EventSub real-time events.
27
| `(twitch analytics)` | Followers, subscribers, clips, VODs, extension/game analytics | 28
| `(twitch chat)` | Chat messages, chatters, settings, announcements | 29
| `(twitch eventsub)` | EventSub WebSocket message parsing, subscription management |+30
| `(twitch oauth)` | OAuth 2.0 integration via sigil-oauth (token management, auto-refresh) | 31
32
## Usage 33
@@ -47,6 +48,30 @@ interaction, and EventSub real-time events.
48
base-url: "http://localhost:8080/mock")) 49
``` 50
+51
### OAuth 2.0 Token Management+52
+53
```scheme+54
(import (twitch oauth))+55
+56
;; Create an OAuth config for Twitch+57
(define config+58
(twitch-oauth-config "your-client-id" "your-client-secret"))+59
+60
;; Load stored tokens (from ~/.config/sigil/twitch/tokens.json)+61
(define tokens (twitch-load-tokens))+62
+63
;; Build a client with auto-refresh+64
(let-values (((client fresh-tokens)+65
(twitch-ensure-client config tokens (current-second))))+66
;; client is ready to use with both Client-Id and Bearer headers+67
(twitch-channel-info client "141981764"))+68
+69
;; Run the full authorization flow (opens browser, starts callback server)+70
(define tokens+71
(oauth-run-authorization-flow config (current-second)))+72
(twitch-save-tokens tokens)+73
```+74
75
### Channel Info 76
77
```scheme@@ -203,4 +228,6 @@ sigil test
228
- sigil-http 229
- sigil-json 230
- sigil-socket+231
- sigil-crypto 232
- sigil-log+233
- sigil-oauthdev-redirects.sglmodified
@@ -3,4 +3,7 @@
3
repos: (list 4
(for-repo 5
url: "codeberg:sigil/sigil"−6
use: (from-path dir: "../sigil"))))+6
use: (from-path dir: "../sigil"))+7
(for-repo+8
url: "codeberg:sigil/sigil-oauth"+9
use: (from-path dir: "../sigil-oauth"))))package.sglmodified
@@ -4,6 +4,7 @@
4
;;; chat interaction, and EventSub real-time events. 5
6
(define sigil-repo "codeberg:sigil/sigil")+7
(define oauth-repo "codeberg:sigil/sigil-oauth") 8
9
(package 10
name: "sigil-twitch"@@ -30,7 +31,10 @@
31
(from-git url: sigil-repo package: "sigil-tls") 32
(from-git url: sigil-repo package: "sigil-http") 33
(from-git url: sigil-repo package: "sigil-json")−33
(from-git url: sigil-repo package: "sigil-socket"))+34
(from-git url: sigil-repo package: "sigil-socket")+35
(from-git url: sigil-repo package: "sigil-crypto")+36
(from-git url: sigil-repo package: "sigil-log")+37
(from-git url: oauth-repo package: "sigil-oauth")) 38
39
tasks: (list 40
(tasksrc/twitch/oauth.sgladded
@@ -0,0 +1,153 @@
+1
;;; (twitch oauth) - OAuth 2.0 integration for sigil-twitch.+2
;;;+3
;;; Provides convenience functions for creating Twitch clients+4
;;; with OAuth token management via sigil-oauth. Uses the Twitch+5
;;; provider preset with configurable scopes.+6
;;;+7
;;; This module adds OAuth support alongside the existing manual+8
;;; token-passing API — callers can still construct a twitch-client+9
;;; directly with client-id and access-token strings.+10
+11
(define-library (twitch oauth)+12
(import (sigil core)+13
(sigil dict)+14
(sigil struct)+15
(sigil oauth)+16
(sigil oauth store)+17
(twitch))+18
+19
(export ;; Config helpers+20
twitch-oauth-config+21
+22
;; Client construction from tokens+23
twitch-oauth-client+24
+25
;; Auto-refresh: config + tokens + time → client + tokens+26
twitch-ensure-client+27
+28
;; Token storage helpers+29
twitch-save-tokens+30
twitch-load-tokens+31
twitch-clear-tokens+32
+33
;; Re-exported from (sigil oauth) for convenience+34
oauth-config+35
oauth-config?+36
oauth-config-client-id+37
oauth-config-client-secret+38
oauth-config-auth-url+39
oauth-config-token-url+40
oauth-config-scopes+41
oauth-config-redirect-uri+42
oauth-config-extra-params+43
oauth-tokens+44
oauth-tokens?+45
oauth-tokens-access-token+46
oauth-tokens-refresh-token+47
oauth-tokens-expires-at+48
oauth-tokens-token-type+49
oauth-tokens-scopes+50
oauth-ensure-valid-token+51
oauth-token-expired?+52
oauth-authorization-url+53
oauth-generate-state+54
oauth-generate-pkce+55
oauth-exchange-code+56
oauth-refresh-token)+57
+58
(begin+59
+60
;; Default Twitch scopes for stream management + analytics + chat.+61
(define twitch-default-scopes+62
(list "channel:manage:broadcast"+63
"channel:manage:schedule"+64
"channel:read:stream_key"+65
"clips:edit"+66
"moderator:read:followers"+67
"channel:read:subscriptions"+68
"user:read:chat"+69
"user:write:chat"+70
"analytics:read:games"))+71
+72
(define twitch-service-name "twitch")+73
+74
;; ---------------------------------------------------------------+75
;; Config+76
;; ---------------------------------------------------------------+77
+78
;;; Create an oauth-config for Twitch OAuth2.+79
;;;+80
;;; client-id: Twitch application client ID+81
;;; client-secret: Twitch application client secret+82
;;;+83
;;; Optional keyword args via opts dict:+84
;;; scopes: list of scope strings (default: twitch-default-scopes)+85
;;; redirect-uri: override redirect URI+86
(define (twitch-oauth-config client-id client-secret . rest)+87
(let ((opts (if (null? rest) #{} (car rest))))+88
(let ((scopes (dict-ref opts scopes: twitch-default-scopes)))+89
(oauth-twitch-config client-id client-secret scopes+90
(if (dict-ref opts redirect-uri: #f)+91
#{ redirect-uri: (dict-ref opts redirect-uri:) }+92
#{})))))+93
+94
;; ---------------------------------------------------------------+95
;; Client construction+96
;; ---------------------------------------------------------------+97
+98
;;; Build a twitch-client from an oauth-tokens record.+99
;;;+100
;;; client-id is required because Twitch requires it in every+101
;;; API request header alongside the Bearer token.+102
(define (twitch-oauth-client client-id tokens)+103
(twitch-client+104
client-id: client-id+105
access-token: (oauth-tokens-access-token tokens)))+106
+107
;; ---------------------------------------------------------------+108
;; Auto-refresh+109
;; ---------------------------------------------------------------+110
+111
;;; Ensure tokens are valid (refreshing if needed) and return+112
;;; both a ready-to-use twitch-client and the (possibly updated)+113
;;; oauth-tokens record.+114
;;;+115
;;; config: oauth-config from twitch-oauth-config+116
;;; tokens: current oauth-tokens record+117
;;; current-time: unix timestamp (from current-second)+118
;;;+119
;;; Optional keyword args via opts dict:+120
;;; save?: whether to persist refreshed tokens (default: #t)+121
;;;+122
;;; Returns: (values twitch-client oauth-tokens)+123
(define (twitch-ensure-client config tokens current-time . rest)+124
(let* ((opts (if (null? rest) #{} (car rest)))+125
(save? (dict-ref opts save?: #t))+126
(fresh-tokens (oauth-ensure-valid-token config tokens current-time))+127
(client (twitch-oauth-client+128
(oauth-config-client-id config)+129
fresh-tokens)))+130
;; Persist if tokens were refreshed+131
(if (and save?+132
(not (eq? fresh-tokens tokens)))+133
(twitch-save-tokens fresh-tokens))+134
(values client fresh-tokens)))+135
+136
;; ---------------------------------------------------------------+137
;; Token storage (thin wrappers)+138
;; ---------------------------------------------------------------+139
+140
;;; Save Twitch OAuth tokens to persistent storage.+141
(define (twitch-save-tokens tokens)+142
(oauth-save-tokens twitch-service-name tokens))+143
+144
;;; Load Twitch OAuth tokens from persistent storage.+145
;;; Returns oauth-tokens or #f if not found.+146
(define (twitch-load-tokens)+147
(oauth-load-tokens twitch-service-name))+148
+149
;;; Clear stored Twitch OAuth tokens.+150
(define (twitch-clear-tokens)+151
(oauth-clear-tokens twitch-service-name))+152
+153
))