AtlatestRenderedmarkdown
Readme

sigil-oauth

OAuth 2.0 client library for Sigil — shared auth for YouTube, Twitch, Wise, and other API clients.

Modules

(sigil oauth) — Core OAuth2 client

Records, authorization URL generation with PKCE, token exchange, token refresh, token validation, and provider presets.

(sigil oauth store) — Token persistence

Save and load tokens as JSON files under ~/.config/sigil/<service>/tokens.json.

(sigil oauth server) — Local callback server

Temporary localhost HTTP server that captures the OAuth redirect, exchanges the authorization code for tokens, and shuts down.

Quick Start

(import (sigil oauth)
        (sigil oauth store)
        (sigil oauth server))

;; 1. Create a provider config
(define config
  (oauth-google-config
    "your-client-id"
    "your-client-secret"
    '("https://www.googleapis.com/auth/youtube")))

;; 2. Run the full authorization flow (opens browser, waits for callback)
(define tokens
  (oauth-run-authorization-flow config (current-second)))

;; 3. Save tokens for later
(oauth-save-tokens "youtube" tokens)

;; 4. Load tokens in a future session
(define tokens (oauth-load-tokens "youtube"))

;; 5. Ensure token is valid before making API calls (auto-refreshes if expired)
(define tokens (oauth-ensure-valid-token config tokens (current-second)))

Manual Flow

For more control over the authorization flow:

;; Generate state and PKCE
(define state (oauth-generate-state))
(define pkce (oauth-generate-pkce))

;; Build the authorization URL
(define auth-url
  (oauth-authorization-url config state #{ pkce: pkce }))

;; Display URL for user to visit...
;; Then start the callback server to capture the redirect:
(define tokens
  (oauth-start-callback-server config state (current-second)
    #{ pkce-verifier: (oauth-pkce-verifier pkce) }))

Provider Presets

Google / YouTube

(oauth-google-config client-id client-secret scopes)
(oauth-google-config client-id client-secret scopes #{ redirect-uri: "..." })

Sets access_type=offline and prompt=consent automatically to ensure refresh tokens are issued.

Twitch

(oauth-twitch-config client-id client-secret scopes)
(oauth-twitch-config client-id client-secret scopes #{ redirect-uri: "..." })

Custom Provider

(oauth-config
  client-id:     "..."
  client-secret: "..."
  auth-url:      "https://provider.com/oauth2/authorize"
  token-url:     "https://provider.com/oauth2/token"
  scopes:        '("scope1" "scope2")
  redirect-uri:  "http://localhost:8085/callback"
  extra-params:  #{ custom_param: "value" })

Token Management

;; Check if a token has expired (with 60s grace period)
(oauth-token-expired? tokens (current-second))

;; Custom grace period (300 seconds)
(oauth-token-expired? tokens (current-second) 300)

;; Refresh manually
(define new-tokens
  (oauth-refresh-token config (oauth-tokens-refresh-token tokens) (current-second)))

;; Auto-refresh: returns existing tokens if valid, refreshes if expired
(define valid-tokens
  (oauth-ensure-valid-token config tokens (current-second)))

;; Validate against a provider endpoint
(oauth-validate-token tokens "https://id.twitch.tv/oauth2/validate")

Token Storage

Tokens are stored as JSON in ~/.config/sigil/<service-name>/tokens.json:

(oauth-save-tokens "youtube" tokens)           ;; default path
(oauth-save-tokens "youtube" tokens "/custom/path.json")  ;; custom path

(oauth-load-tokens "youtube")      ;; returns oauth-tokens or #f
(oauth-clear-tokens "youtube")     ;; returns #t if deleted, #f if missing

Dependencies

  • sigil-stdlib
  • sigil-http
  • sigil-json
  • sigil-log

Building

sigil deps install
sigil build
sigil test