added saving and refreshing token

This commit is contained in:
2025-11-23 22:35:45 +00:00
parent 09106ccb75
commit c6aac050cc
3 changed files with 89 additions and 7 deletions

View File

@@ -3,6 +3,7 @@ package handlers
import ( import (
"net/http" "net/http"
"adam-french.co.uk/backend/services"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/zmb3/spotify/v2" "github.com/zmb3/spotify/v2"
) )
@@ -17,7 +18,7 @@ func (store *Store) CompleteAuth(c *gin.Context) {
return return
} }
store.SpotifyToken = token services.SaveSpotifyToken(services.SPOTIFY_TOKEN_JSON_PATH, token)
client := spotify.New(store.SpotifyAuth.Client(c.Request.Context(), token)) client := spotify.New(store.SpotifyAuth.Client(c.Request.Context(), token))

View File

@@ -3,13 +3,11 @@ package handlers
import ( import (
"github.com/zmb3/spotify/v2" "github.com/zmb3/spotify/v2"
spotifyauth "github.com/zmb3/spotify/v2/auth" spotifyauth "github.com/zmb3/spotify/v2/auth"
"golang.org/x/oauth2"
"gorm.io/gorm" "gorm.io/gorm"
) )
type Store struct { type Store struct {
DB *gorm.DB DB *gorm.DB
SpotifyAuth *spotifyauth.Authenticator SpotifyAuth *spotifyauth.Authenticator
SpotifyToken *oauth2.Token
SpotifyClient *spotify.Client SpotifyClient *spotify.Client
} }

View File

@@ -1,9 +1,15 @@
package services package services
import ( import (
"context"
"encoding/json"
"fmt" "fmt"
"os"
"time"
"github.com/zmb3/spotify/v2"
spotifyauth "github.com/zmb3/spotify/v2/auth" spotifyauth "github.com/zmb3/spotify/v2/auth"
"golang.org/x/oauth2"
) )
type SpotifyConfig struct { type SpotifyConfig struct {
@@ -13,7 +19,58 @@ type SpotifyConfig struct {
ClientSecret string ClientSecret string
} }
func InitSpotifyAuth(config SpotifyConfig) *spotifyauth.Authenticator { const SPOTIFY_TOKEN_JSON_PATH = "spotify_token.json"
func SaveSpotifyToken(path string, tok *oauth2.Token) error {
data := struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
Expiry time.Time `json:"expiry"`
}{
AccessToken: tok.AccessToken,
RefreshToken: tok.RefreshToken,
TokenType: tok.TokenType,
Expiry: tok.Expiry,
}
jsonBytes, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
// 0600 ensures only your user can read/write the file
return os.WriteFile(path, jsonBytes, 0600)
}
func LoadSpotifyToken(path string) (*oauth2.Token, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var saved struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
Expiry time.Time `json:"expiry"`
}
if err := json.Unmarshal(data, &saved); err != nil {
return nil, err
}
tok := &oauth2.Token{
AccessToken: saved.AccessToken,
RefreshToken: saved.RefreshToken,
TokenType: saved.TokenType,
Expiry: saved.Expiry,
}
return tok, nil
}
func InitSpotifyAuth(config SpotifyConfig) (*spotifyauth.Authenticator, *spotify.Client) {
auth := spotifyauth.New( auth := spotifyauth.New(
spotifyauth.WithRedirectURL(config.RedirectURL), spotifyauth.WithRedirectURL(config.RedirectURL),
spotifyauth.WithClientID(config.ClientID), spotifyauth.WithClientID(config.ClientID),
@@ -24,8 +81,34 @@ func InitSpotifyAuth(config SpotifyConfig) *spotifyauth.Authenticator {
), ),
) )
fmt.Println("Authenticate spotify with:") // check if token exists locally
token, err := LoadSpotifyToken(SPOTIFY_TOKEN_JSON_PATH)
if err != nil || token == nil {
fmt.Println("No token saved. Authenticate Spotify with:")
fmt.Println(auth.AuthURL(config.AuthState)) fmt.Println(auth.AuthURL(config.AuthState))
return auth, nil
}
return auth // refresh token and client
client, err := RefreshClient(auth, token)
if err != nil {
fmt.Println("Failed to refresh token. Authenticate Spotify with:")
fmt.Println(auth.AuthURL(config.AuthState))
return auth, nil
}
return auth, client
}
func RefreshClient(auth *spotifyauth.Authenticator, token *oauth2.Token) (*spotify.Client, error) {
ctx := context.Background()
token, err := auth.RefreshToken(ctx, token)
if err != nil {
return nil, err
}
client := spotify.New(auth.Client(ctx, token))
return client, nil
} }