working on botTokens
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
@@ -20,16 +20,21 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
_ = godotenv.Load()
|
||||||
|
|
||||||
log.Println("OAuth server started on port 8080")
|
log.Println("OAuth server started on port 8080")
|
||||||
|
|
||||||
botUsername := os.Getenv("nz_chatterbot")
|
botUsername := os.Getenv("BOT_USERNAME")
|
||||||
botOAuth := os.Getenv("BOT_OAUTH")
|
botAccess := os.Getenv("BOT_ACCESS_TOKEN")
|
||||||
channel := os Getenv("brycefromnz101")
|
botRefresh := os.Getenv("BOT_REFRESH_TOKEN")
|
||||||
|
channel := os Getenv("CHANNEL")
|
||||||
clientID := os.Getenv("TWITCH_CLIENT_ID")
|
clientID := os.Getenv("TWITCH_CLIENT_ID")
|
||||||
clientSecret := os.Getenv("TWITCH_CLIENT_SECRET")
|
clientSecret := os.Getenv("TWITCH_CLIENT_SECRET")
|
||||||
|
channelAccess := os.Getenv("STREAMER_ACCESS_TOKEN")
|
||||||
|
channelRefresh := os.Getenv("STREAMER_REFRESH_TOKEN")
|
||||||
botChannel := botUsername
|
botChannel := botUsername
|
||||||
|
|
||||||
if botUsername == "" || botOAuth == "" || channel == "" || clientID == "" || clientSecret == "" {
|
if botUsername == "" || botAccess == "" || channel == "" || clientID == "" || clientSecret == "" {
|
||||||
log.Fatal("Please set Bot_Username, Bot_OAuth, Channel, Twitch_Client_ID, and Twitch_Client_Secret env vars")
|
log.Fatal("Please set Bot_Username, Bot_OAuth, Channel, Twitch_Client_ID, and Twitch_Client_Secret env vars")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
go.mod
5
go.mod
@@ -7,4 +7,7 @@ require (
|
|||||||
github.com/nicklaw5/helix v1.25.0
|
github.com/nicklaw5/helix v1.25.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
require (
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
|
github.com/joho/godotenv v1.5.1 // indirect
|
||||||
|
)
|
||||||
|
2
go.sum
2
go.sum
@@ -3,5 +3,7 @@ github.com/gempir/go-twitch-irc/v4 v4.2.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/j
|
|||||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M=
|
github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M=
|
||||||
github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw=
|
github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw=
|
||||||
|
@@ -39,6 +39,7 @@ func StartOAuthServer(addr string) error {
|
|||||||
|
|
||||||
http.HandleFunc("/", handleIndex)
|
http.HandleFunc("/", handleIndex)
|
||||||
http.HandleFunc("/callback", handleCallback)
|
http.HandleFunc("/callback", handleCallback)
|
||||||
|
http.HandleFunc("/refresh", handleRefresh)
|
||||||
|
|
||||||
log.Printf("OAuth server listening on %s", addr)
|
log.Printf("OAuth server listening on %s", addr)
|
||||||
return http.ListenAndServe(addr, nil)
|
return http.ListenAndServe(addr, nil)
|
||||||
@@ -46,7 +47,7 @@ func StartOAuthServer(addr string) error {
|
|||||||
|
|
||||||
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
authURL := fmt.Sprintf(
|
authURL := fmt.Sprintf(
|
||||||
"https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s",
|
"https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s&force_verify=true",
|
||||||
url.QueryEscape(clientID),
|
url.QueryEscape(clientID),
|
||||||
url.QueryEscape(redirectURI),
|
url.QueryEscape(redirectURI),
|
||||||
url.QueryEscape(strings.Join(scopes, " ")),
|
url.QueryEscape(strings.Join(scopes, " ")),
|
||||||
@@ -77,10 +78,26 @@ func handleCallback(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jsonData, _ := json.MarshalIndent(token, "", " ")
|
jsonData, _ := json.MarshalIndent(token, "", " ")
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/ijson")
|
||||||
w.Write(jsonData)
|
w.Write(jsonData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleRefresh(w http.ResponseWriter, r *http.Request) {
|
||||||
|
refresh := r.URL.Query().Get("refresh_token")
|
||||||
|
if refresh == "" {
|
||||||
|
http.Error(w, "Missing refresh_token parameter", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tr, err := ExchangeRefreshToken(refresh)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Refresh failed: "+err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, _ := json.MarshalIndent(tr, "", " ")
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
func exchangeCodeForToken(code string) (*TokenResponse, error) {
|
func exchangeCodeForToken(code string) (*TokenResponse, error) {
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
data.Set("client_id", clientID)
|
data.Set("client_id", clientID)
|
||||||
@@ -110,3 +127,31 @@ func exchangeCodeForToken(code string) (*TokenResponse, error) {
|
|||||||
|
|
||||||
return &tokenResp, nil
|
return &tokenResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refresh tokens programtically
|
||||||
|
func ExchangeRefreshToken(refreshToken string) (*TokenResponse, error) {
|
||||||
|
form := url.Values{}
|
||||||
|
form.Set("client_id", clientID)
|
||||||
|
form.Set("client_secret", clientSecret)
|
||||||
|
form.Set("grant_type", "refresh_token")
|
||||||
|
form.Set("refresh_token", refreshToken)
|
||||||
|
|
||||||
|
resp, err := http.Post(
|
||||||
|
"https://id.twitch.tv/oauth2/token",
|
||||||
|
"application/x-www-form-urlencoded",
|
||||||
|
strings.NewReader(form.Encode()),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("refresh failed: %s", resp.Status)
|
||||||
|
}
|
||||||
|
var tr TokenResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&tr); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tr, nil
|
||||||
|
}
|
||||||
|
@@ -5,10 +5,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
helix "github.com/nicklaw5/helix"
|
helix "github.com/nicklaw5/helix"
|
||||||
|
oauthsrv "streambot_twitch/internal/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
api *helix.Client
|
api *helix.Client
|
||||||
|
refreshToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(clientID, clientSecret string) (*Client, error) {
|
func NewClient(clientID, clientSecret string) (*Client, error) {
|
||||||
@@ -29,6 +31,29 @@ func NewClient(clientID, clientSecret string) (*Client, error) {
|
|||||||
return &Client{api: apiClient}, nil
|
return &Client{api: apiClient}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set User Tokens - Oauth and Refresh
|
||||||
|
func (c *Client) SetUserTokens(accessToken, refreshToken string, expiresIn int) {
|
||||||
|
at := strings.TrimPrefix(accessToken, "oauth:")
|
||||||
|
c.api.SetUserAccessToken(at)
|
||||||
|
c.accessToken = at
|
||||||
|
c.refreshToken = refreshToken
|
||||||
|
if expiresIn > 0 {
|
||||||
|
c.expiry = time.Now().Add(time.Duration(expiresIn) * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use /refresh endpoint to renew tokens
|
||||||
|
func (c *Client) RefreshIfNeeded() error {
|
||||||
|
if time.Until(c.expiry) < 5*time.Minute {
|
||||||
|
tr, err := oauthsrv.ExchangeRefreshToken(c.refreshToken)
|
||||||
|
if err 1= nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.SetUserTokens(tr.AccessToken, tr.RefreshToken, tr.ExpiresIn)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Twitch API helpers
|
// Twitch API helpers
|
||||||
|
|
||||||
func (c *Client) GetUserID(login string) (string, error) {
|
func (c *Client) GetUserID(login string) (string, error) {
|
||||||
|
Reference in New Issue
Block a user