zmb3 / spotify

A Go wrapper for the Spotify Web API
Apache License 2.0
1.4k stars 293 forks source link

Spotify refresh token after 1 hour expiry #7

Closed jesseward closed 8 years ago

jesseward commented 8 years ago

Realize this is not so much an issue with this Spotify lib, but curious if anyone has got Spotify's OAUTH token to "refresh" using the Go Ouath2 library?

I have implemented a pair of helper functions to writeToken and readToken that caches a json blob containing the auth token to disk. I am doing this so that the user isn't forced to continually authorize access to Spotify. As it stands Spotify has a very short token expiry (1 hour) but they do provide a refresh token when authenticated. Documented here -> https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow

@zmb3 if you have attempted such an oauth flow using the refresh token, would you mind adding this to the example?

zmb3 commented 8 years ago

I haven't played with this in detail, but it is my understanding that the token should refresh automatically. See https://godoc.org/golang.org/x/oauth2#Config.Client:

Client returns an HTTP client using the provided token. The token will auto-refresh as necessary.

If you're seeing something different or have suggestions for improving the authentication portion I'm all ears :smile:

zmb3 commented 8 years ago

I put together a really simple app that authenticates and makes a call that requires authentication every 10 minutes. I let it run for several hours and there have been no issues, so I believe the token is refreshing as expected.

avinassh commented 7 years ago

Can you tell me what I am doing wrong? I am saving all the details to a file first and then reading from that. Spotify tokens expire after an hour and I guess refresh isn't happening. Here is my code:

    token := &oauth2.Token{
        Expiry:       time.Unix(config.TokenExpiry, 0),
        TokenType:    config.TokenType,
        AccessToken:  config.AccessToken,
        RefreshToken: config.RefreshToken,
    }
    fmt.Println(token.Valid()) // this prints false after an hour and code starts failing
    client := auth.NewClient(token)
    user, err := client.CurrentUser()
    if err != nil {
        log.Fatal("Failed :", err)
    }
    fmt.Println("Hi: ", user.ID)

And I get an error:

2017/03/19 22:11:43 Failed :Get https://api.spotify.com/v1/me: oauth2: cannot fetch token: 400 Bad Request
Response: {"error":"invalid_client"}

To produce this error, fetch tokens from Spotify, save them and run the script again after an hour.

EDIT: Figured out why. I wasn't setting client ID and secret:

auth.SetAuthInfo(config.ClientID, config.ClientSecret)
jordanpotter commented 5 years ago

Just a note, when it comes to the client credentials flow, the OAuth2 spec recommends NOT returning a refresh token. Thus, the auth token will expire after an hour for client credentials

For the authorization code flow, refresh tokens are granted and the Go OAuth2 libraries automatically refresh these tokens for you

metalmatze commented 5 years ago

I run into the problem where my client isn't authenticated after an hour too. I guess I'm using the client credentials flow too. Is my only option to recreate the client I have in memory every hour, so it is still authenticated in the long run? I can do that, but it still feels like a hack and not properly handled by this package, to be honest.

ptrkrlsrd commented 5 years ago

I run into the problem where my client isn't authenticated after an hour too. I guess I'm using the client credentials flow too. Is my only option to recreate the client I have in memory every hour, so it is still authenticated in the long run? I can do that, but it still feels like a hack and not properly handled by this package, to be honest.

@metalmatze I've been solving it the same way as well, but I too think it feels hacky. Have you found any better solution yet?

alfiedouglas0 commented 5 years ago

I implemented the authorization code flow by deploying the code: spotify-token-refresh to heroku (with a free account). And have no issues with this at all!

5 minutes before each token expires I schedule the method below to run to refresh the token.

async function refreshAccessToken(refreshToken) {
    return await request.post({
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-Requested-With': 'XMLHttpRequest',
        },
        url: refreshURL,
        form: {
            refresh_token: refreshToken,
        }
    });`
fabstu commented 4 years ago

Just noting here.. I forgot the line auth.SetAuthInfo(config.ClientID, config.ClientSecret) too. I did only use it on the first authentication workflow but I did not set it before I created the client with the existing token, making the refresh fail.

I copied the auth workflow example and built on it. When I read the spotify auth data from env variables I did not realize they are needed for the refreshing too. The example does not handle this because it always reads from env variables.