Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth invalid grant errors #359

Open
hannah-subtle opened this issue Jan 27, 2025 · 13 comments
Open

OAuth invalid grant errors #359

hannah-subtle opened this issue Jan 27, 2025 · 13 comments

Comments

@hannah-subtle
Copy link

I am currently receiving errors when trying to refresh my token

Jan 26 22:55:00 Access token expired. Attempting to refresh...
Jan 26 22:55:00 Refresh token invalid or expired.
Jan 26 22:55:00 Failed to refresh access token: Reauthentication required.
Jan 26 22:55:00 Error uploading track to SoundCloud:
Jan 26 22:55:00 Error Message: Reauthorization required. Refresh token is invalid or expired.
Jan 26 22:55:00Access token expired. Attempting to refresh...
Jan 26 22:55:00Refresh token invalid or expired.
Jan 26 22:55:00Failed to refresh access token: Reauthentication required.
Jan 26 22:55:00Error uploading track to SoundCloud:
Jan 26 22:55:00Error Message: Reauthorization required. Refresh token is invalid or expired.

Could you help me to understand what is wrong in my authorisation flow.

Access Token Management:

Tokens are stored in a tokens.json file. access_token expiry is calculated using: tokens.expires_at = Date.now() + tokens.expires_in * 1000
The refresh_token is used to renew the access_token when it expires.

async function refreshAccessToken(refreshToken) {
    try {
        const postData = querystring.stringify({
            client_id: clientId,
            client_secret: clientSecret,
            grant_type: 'refresh_token',
            refresh_token: refreshToken,
        });

        const response = await axios.post('https://secure.soundcloud.com/oauth/token', postData, {
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        });

        const data = response.data;
        if (data.access_token) {
            data.expires_at = Date.now() + data.expires_in * 1000; // Calculate new expiry time
            saveTokens(data); // Save updated tokens
            console.log('Access token refreshed successfully.');
            return data.access_token;
        } else {
            throw new Error('Failed to refresh access token. Response data is invalid.');
        }
    } catch (error) {
        if (error.response?.data?.error === 'invalid_grant') {
            console.error('Refresh token invalid or expired.');
            throw new Error('Reauthentication required.');
        }
        throw error;
    }
}
async function getAccessToken() {
    const tokens = readTokens(); // Load tokens from file or database

    // Check if the current access token is still valid
    if (tokens && tokens.access_token && tokens.expires_at > Date.now()) {
        console.log('Access token is valid.');
        return tokens.access_token;
    }

    // Attempt to refresh the token if a refresh token is available
    if (tokens && tokens.refresh_token) {
        try {
            console.log('Access token expired. Attempting to refresh...');
            const newAccessToken = await refreshAccessToken(tokens.refresh_token);
            return newAccessToken;
        } catch (error) {
            if (error.message.includes('Reauthentication required')) {
                console.error('Refresh token invalid or expired. Reauthentication required.');
                // Trigger notification or process to reauthenticate
                throw new Error('Reauthentication required. Please reauthorize the app.');
            } else {
                console.error('Error refreshing access token:', error.message);
                throw error;
            }
        }
    }

    // No valid tokens available, require reauthentication
    console.error('No valid access or refresh token available.');
    throw new Error('Reauthentication required. No valid tokens found.');
}
@dpreussler
Copy link
Contributor

Hi there,
the refresh code looks correct.
Some things to check:

  • You can only use a refresh token once! Invalidate it after use
  • Instead of relying on expiration time, better refresh the token when you get a 401

@dpreussler
Copy link
Contributor

@hannah-subtle where you able to get this solved?

@hannah-subtle
Copy link
Author

@dpreussler working on this today, will keep you posted!

@jasongrishkoff
Copy link

My refresh code has been in place for ages now, but 3-4 days ago it started failing repeatedly. Sometimes it works, sometimes it doesn't. It seems sporadic. Could it be related to #361?

@dpreussler
Copy link
Contributor

@jasongrishkoff what is the error you're getting when trying to refresh.
And yes it might be related!

@jasongrishkoff
Copy link

Here's an example response. Hope it helps?

{"statusCode":400,"content":"{"error":"invalid_grant"}","headers":{"connection":"close","content-encoding":"gzip","content-length":"51","content-type":"application/json; charset=utf-8","date":"Tue, 04 Feb 2025 09:09:13 GMT","referrer-policy":"no-referrer","server":"am/2","strict-transport-security":"max-age=63072000","vary":"Origin","via":"1.1 134f499632d1e15750219cb766bdc50c.cloudfront.net (CloudFront)","x-amz-cf-id":"IDOuI1W5yxZzpKJzDq1kP_RzWa5MVOTQHHdhpBEeOwLkTzCxkAADRQ==","x-amz-cf-pop":"JFK50-P3","x-cache":"Error from cloudfront","x-content-type-options":"nosniff","x-frame-options":"DENY","x-robots-tag":"noindex"},"ok":false,"data":{"error":"invalid_grant"}}

I think most are refreshing just fine -- I'd guess the fail rate is 5%? I haven't actually tracked it. But I'm refreshing user tokens regularly (once per hour), so over the course of a day that means I'm needing to ask quite a few people to reconnect their accounts, as the connection failed.

@jasongrishkoff
Copy link

Following up in this thread as requested. invalid_grant errors have been fairly infrequent for the last few days, but 4-5 hours ago they started to pick up. I've had quite a few failures today. This process was working for many months without error, so I'm not sure what the issue is. More-recent example below:
{"statusCode":400,"content":"{"error":"invalid_grant"}","headers":{"connection":"close","content-encoding":"gzip","content-length":"51","content-type":"application/json; charset=utf-8","date":"Tue, 18 Feb 2025 16:48:35 GMT","referrer-policy":"no-referrer","server":"am/2","strict-transport-security":"max-age=63072000","vary":"Origin","via":"1.1 749177a97cae42477f22c33c927ca0ce.cloudfront.net (CloudFront)","x-amz-cf-id":"RzWLHWu9VuNXpQ0R1eqfnn9cLX4ueDiDo0N7hhdFnpnJmcv2sSNhKA==","x-amz-cf-pop":"JFK50-P3","x-cache":"Error from cloudfront","x-content-type-options":"nosniff","x-frame-options":"DENY","x-robots-tag":"noindex"},"ok":false,"data":{"error":"invalid_grant"}}

@jasongrishkoff
Copy link

Update: I'm seeing a huge uptick in errors today.

All fairly similar:
{"statusCode":400,"content":"{"error":"invalid_grant"}","headers":{"connection":"close","content-encoding":"gzip","content-length":"51","content-type":"application/json; charset=utf-8","date":"Wed, 19 Feb 2025 08:29:41 GMT","referrer-policy":"no-referrer","server":"am/2","strict-transport-security":"max-age=63072000","vary":"Origin","via":"1.1 740fccc7c62d49696904618862f889f8.cloudfront.net (CloudFront)","x-amz-cf-id":"pGuEsm0OmOLddZQLVQyjDLmwEqhAQne0-f1igwi9QNdYM3fTonh-wA==","x-amz-cf-pop":"SIN52-P1","x-cache":"Error from cloudfront","x-content-type-options":"nosniff","x-frame-options":"DENY","x-robots-tag":"noindex"},"ok":false,"data":{"error":"invalid_grant"}}

An example of the code I'm using:

            HTTP.post('https://secure.soundcloud.com/oauth/token', {
                params: {
                    grant_type: 'refresh_token',
                    client_id: SOUNDCLOUD_CLIENT_ID,
                    client_secret: SOUNDCLOUD_SECRET,
                    refresh_token: REFRESH_TOKEN,
                },
                headers: {
                    'Accept': 'application/json; charset=utf-8',
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            },(err,res) => {
                [...]
            })

This has been working smoothly for many months now. The errors started ~2 weeks ago, slowed down last week, and have picked up significantly in the last 24 hours.

Hope that helps provide something to go on. Let me know if I can be of further help!

@mgoodfellow
Copy link

mgoodfellow commented Feb 19, 2025

Interesting - we saw a big increase in these during the instability periods of recent weeks, but the last day or so has stabilised and returned to baseline:

Image

I wonder if you haven't got a bunch of broken tokens from the weeks of stability and are only seeing the delayed effect of it now when users become active after a period of inactivity? We only refresh tokens when required our side (we wait for a 401 and then try to refresh with the stored token) and it is an effect we sometimes see. We also have found that sometimes when refreshing a token and receiving back a 5xx error, the refresh token is burnt even though we didn't get a new token pair back leading to this effect.

Just adding context - this graph shows when we fail to use a refresh token due to the error you are describing and we have to get the user to go through a re-authentication flow

@jasongrishkoff
Copy link

jasongrishkoff commented Feb 20, 2025

Interesting thought! From my side, I'm actually auto-refreshing tokens every ~1 hour. They still seem to be consistently failing, though I did just have an ~18 hour patch with very few disconnects.

@hannah-subtle
Copy link
Author

I am also refreshing every hour and i am still getting the same error:

Failed to refresh access token: { error: 'invalid_grant' }
Refresh token is invalid or expired. Reauthentication required.
Scheduled token refresh failed: Reauthentication required.

@jasongrishkoff
Copy link

This is still a huge problem for me, as well. I've put in all sorts of code to make sure I'm avoiding race conditions and NOT requesting a refresh with the same token. Sometimes it'll go 3-4 days just fine, but today I had all 300 of my users disconnect within 1 hour. I don't know if there was a recent change with SoundCloud around this... the issue only started coming up early February.

@hannah-subtle
Copy link
Author

Massive issue for us still, I can't get it working for longer than an hour now, constant invalid grant errors

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

No branches or pull requests

4 participants