How It Works
- Your extension has a secret (obtained from the Twitch Developer Console or via
GetExtensionSecrets) - Your Extension Backend Service (EBS) creates and signs a JWT using that secret
- The JWT is passed as the Bearer token in API requests
Creating an Extension JWT
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
func CreateExtensionJWT(extensionSecret, userID, channelID string) (string, error) {
claims := jwt.MapClaims{
"exp": time.Now().Add(time.Minute * 3).Unix(),
"user_id": userID, // Your extension's owner user ID
"role": "external", // "external" for EBS calls
"channel_id": channelID, // Target channel (if applicable)
"pubsub_perms": map[string][]string{
"send": {"broadcast", "global"},
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(extensionSecret))
}
JWT Claims
| Claim | Description |
|---|---|
exp |
Expiration time (Unix timestamp). Max 3 minutes from now. |
user_id |
The user ID making the request (typically extension owner). |
role |
Set to "external" for EBS calls. |
channel_id |
The target channel ID (required for channel-specific operations). |
pubsub_perms |
PubSub permissions object (required for PubSub messages). |
Auth Type Comparison
| Auth Type | Used For |
|---|---|
| Extension JWT | Extension-specific endpoints (config, PubSub, secrets, chat) |
| App Access Token | Public extension data (Bits products, transactions) |
| User Access Token | User-authorized actions |
Example Usage
// Create JWT
secret := "your-extension-secret"
token, err := CreateExtensionJWT(secret, "12345", "67890")
if err != nil {
log.Fatal(err)
}
// Use with client
client := helix.NewClient("client-id", token)
resp, err := client.GetExtensionConfigurationSegment(ctx, &helix.GetExtensionConfigurationSegmentParams{
ExtensionID: "your-extension-id",
Segment: []string{"broadcaster"},
BroadcasterID: "67890",
})