cancel
Showing results for 
Search instead for 
Did you mean: 
Announcements

The Hub is now in read-only mode as we make improvements to the Hub experience. More information is available here.

ERROR - code: 'missing'

vxnuaj
Mt. Kenya

Hey!

I'm trying to build a personal website that displays my weekly mileage through Strava's API!

Unfortunately I keep getting the following error:

message: 'Authorization Error',
  errors: [
    {
      resource: 'AccessToken',
      field: 'activity:read_permission',
      code: 'missing'
    }
  ]

I read a lot of forums online, videos, and the docs, I can't crack this problem and solve it.

I printed out token request & response in my terminal, here it is:

Token Request URL: https://www.strava.com/oauth/token?client_id=108355&client_secret=[KEEPING THIS PRIVATE] &refresh_token=[KEEPING THIS PRIVATE]&grant_type=refresh_token&response_type=code&approval_prompt=auto&scope=activity%3A+read_all
Token Response: {
  token_type: 'Bearer',
  access_token: '[KEEPING THIS PRIVATE]',
  expires_at: 1707040367,
  expires_in: 20581,
  refresh_token: '[KEEPING THIS PRIVATE]'
}

As you can see, the URL is set to the scope = activity: read_all.

I'm a little baffled on why I keep getting this problem.

Here's my JS code, perhaps it'll give some clues into the error:

export default async (req, res) => {
    const headers = {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    };

    const body = new URLSearchParams({
        client_id: process.env.STRAVA_CLIENT_ID,
        client_secret: process.env.STRAVA_SECRET,
        refresh_token: process.env.STRAVA_REFRESH_TOKEN,
        grant_type: 'refresh_token',
        response_type: 'code',
        approval_prompt: 'auto',
        scope: 'activity: read_all',
    });
    
    console.log('Token Request URL:', `https://www.strava.com/oauth/token?${body.toString()}`);
    
    const reauthorizeResponse = await fetch(`https://www.strava.com/oauth/token?${body.toString()}`, {
        method: 'post',
        headers: headers
    });
    
    // ... Rest of your code ...
    
    const reAuthJson = await reauthorizeResponse.json();

    console.log('Token Response:', reAuthJson); // Log token response for debugging

    // Calculate the start and end timestamps for the past week in seconds
    const endDate = Math.floor(Date.now() / 1000); // current date in seconds
    const startDate = endDate - (7 * 24 * 60 * 60); // 7 days ago in seconds

    const apiUrl = `https://www.strava.com/api/v3/athlete/activities?access_token=${reAuthJson.access_token}&after=${startDate}&before=${endDate}`;

    const response = await fetch(apiUrl);
    const activities = await response.json();

    // Ensure activities is an array (if it's an object, convert it to an array)
    const activitiesArray = Array.isArray(activities) ? activities : [activities];

    // Calculate total distance for the week
    const weeklyMileage = activitiesArray.reduce((total, activity) => {
        if (activity.type === 'Run' && activity.distance) {
            total += activity.distance / 1000; // Convert meters to kilometers
        } else {
            // Log activity details for debugging
            console.log('Skipped activity:', activity);
        }
        return total;
    }, 0);

    return res.status(200).json({
        weeklyMileage
    });
};

I'd really value any guidance!

I've been trying to figure out a solution for the past 4 hours.

3 REPLIES 3

ActivityFix
Superuser
Superuser

Your error message says you are missing the activity:read permission (which is a subset of activity:read_all). In your code there's a space between "activity:" and "read_all" and you can also see it in the URL you posted with the extra + character in the scope request.

https://www.strava.com/oauth/token?client_id=108355&client_secret=[KEEPING  THIS PRIVATE]&refresh_token=[KEEPING THIS PRIVATE]&grant_type=refresh_token&response_type=code&approval_prompt=auto&scope=activity%3A+read_all

See https://developers.strava.com/docs/authentication/#detailsaboutrequestingaccess for all of the scopes. While your authentication request is succeeding, the scopes it is requesting are invalid and my guess is that you're only getting plain "read_all" if anything.

orbjeff
Shkhara

I see it defined like this in some other JavaScript on this forum

 

    headers = {
        'Authorization': f'Bearer {token.get("token")}'
    }

 

orbjeff
Shkhara

This line seems like it could be an issue.

const apiUrl = `https://www.strava.com/api/v3/athlete/activities?access_token=${reAuthJson.access_token}&after=${startDate}&before=${endDate}`;

Is it OK to pass the access token as a query parameter versus a new header entry in your request?

"Authorization" : "Bearer kdfjsfjsdffsf......"