Skip to content

fix: fallback without auth if twitch token is invalid#1083

Merged
Zibbp merged 1 commit intomainfrom
token-fallback
Feb 25, 2026
Merged

fix: fallback without auth if twitch token is invalid#1083
Zibbp merged 1 commit intomainfrom
token-fallback

Conversation

@Zibbp
Copy link
Owner

@Zibbp Zibbp commented Feb 24, 2026

Fixes #1068

@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

Walkthrough

Added authentication-aware GraphQL request flow with retry logic and improved error handling. Introduced new TwitchGQLError type and extended TwitchGQLPlaybackAccessTokenResponse with error fields. Updated token retrieval flow to support both authenticated and unauthenticated requests with retry mechanism.

Changes

Cohort / File(s) Summary
GraphQL Request and Retry Logic
internal/platform/twitch_gql.go
Added twitchGQLRequestWithAuth() with configurable auth inclusion and 3-attempt retry logic using 300ms backoff. Treats server errors and 429 status codes as retryable. Updated twitchGQLRequest() to delegate to new function with auth enabled. Extended headers to include Client-ID, Content-Type, Origin, Referer, Sec-Fetch-Mode, Sec-Fetch-Site, User-Agent, and conditional Authorization.
Error Handling and Token Validation
internal/platform/twitch_gql.go
Introduced TwitchGQLError type with Message field and extended TwitchGQLPlaybackAccessTokenResponse with Errors array. Added parsePlaybackAccessTokenResponse() to unmarshal responses, validate token fields (Value, Signature), and surface GraphQL errors. Enhanced TwitchGQLGetPlaybackAccessToken() to attempt authenticated requests first with fallback to unauthenticated flow and warning logs on auth failure.
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No pull request description was provided by the author. Add a description explaining the motivation, implementation details, and how the token fallback mechanism works.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing fallback behavior when Twitch token authentication fails.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch token-fallback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/platform/twitch_gql.go (1)

155-208: Token is re-read from config on every retry attempt.

config.Get() at line 179 reads the config file from disk (per the implementation in internal/config/config.go). Inside the retry loop, this means up to 3 disk reads per call. More importantly, the caller (TwitchGQLGetPlaybackAccessToken) already reads the token at line 290 to decide whether to use auth—but the actual token applied to the request is read independently at line 179, so the two could diverge if config changes between calls.

Consider accepting the token as a parameter instead of re-reading config internally. This would eliminate redundant I/O and the consistency gap:

♻️ Suggested approach
-func twitchGQLRequestWithAuth(body string, includeAuth bool) ([]byte, error) {
+func twitchGQLRequestWithAuth(body string, twitchToken string) ([]byte, error) {
 	client := &http.Client{}
 	const maxAttempts = 3
 
 	var lastErr error
 	for attempt := 1; attempt <= maxAttempts; attempt++ {
 		...
-		twitchToken := config.Get().Parameters.TwitchToken
-		if includeAuth && twitchToken != "" {
+		if twitchToken != "" {
 			req.Header.Set("Authorization", fmt.Sprintf("OAuth %s", twitchToken))
 		}
 		...

The original twitchGQLRequest wrapper would become:

 func twitchGQLRequest(body string) ([]byte, error) {
-	return twitchGQLRequestWithAuth(body, true)
+	return twitchGQLRequestWithAuth(body, config.Get().Parameters.TwitchToken)
 }

And in TwitchGQLGetPlaybackAccessToken:

 	twitchToken := config.Get().Parameters.TwitchToken
 	if twitchToken != "" {
-		respBytes, err := twitchGQLRequestWithAuth(body, true)
+		respBytes, err := twitchGQLRequestWithAuth(body, twitchToken)
 		...
 	}
-	respBytes, err := twitchGQLRequestWithAuth(body, false)
+	respBytes, err := twitchGQLRequestWithAuth(body, "")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/platform/twitch_gql.go` around lines 155 - 208, The function is
re-reading the Twitch token from disk inside the retry loop (config.Get() in
twitchGQLRequestWithAuth), causing redundant I/O and potential inconsistency
with the caller (TwitchGQLGetPlaybackAccessToken). Change the API to accept the
token from the caller (e.g., add a token string parameter to
twitchGQLRequestWithAuth or to twitchGQLRequest and update the wrapper
twitchGQLRequest to match), remove the config.Get() call from inside
twitchGQLRequestWithAuth, and use the passed token when building the
Authorization header; then update TwitchGQLGetPlaybackAccessToken to read the
token once and pass it into the request call. Ensure includeAuth handling still
works by checking the passed token and the includeAuth flag, and keep the retry
logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/platform/twitch_gql.go`:
- Around line 155-208: The function is re-reading the Twitch token from disk
inside the retry loop (config.Get() in twitchGQLRequestWithAuth), causing
redundant I/O and potential inconsistency with the caller
(TwitchGQLGetPlaybackAccessToken). Change the API to accept the token from the
caller (e.g., add a token string parameter to twitchGQLRequestWithAuth or to
twitchGQLRequest and update the wrapper twitchGQLRequest to match), remove the
config.Get() call from inside twitchGQLRequestWithAuth, and use the passed token
when building the Authorization header; then update
TwitchGQLGetPlaybackAccessToken to read the token once and pass it into the
request call. Ensure includeAuth handling still works by checking the passed
token and the includeAuth flag, and keep the retry logic unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06b5f53 and 30d0a55.

📒 Files selected for processing (1)
  • internal/platform/twitch_gql.go

@Zibbp Zibbp merged commit fb43fa1 into main Feb 25, 2026
8 checks passed
@Zibbp Zibbp deleted the token-fallback branch February 25, 2026 23:55
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.

Failed to get stream: error decoding m3u8

1 participant