· strava

Strava: Authorization Error - Missing activity:read_permission

I’m revisiting the Strava API after a two year absence and the approach to authenticating requests has changed in that time. You now need to generate an access token via OAuth 2.0, as described in the 'How to authenticate with OAuth 2.0' section of the Getting Started with the Strava API guide.

I want to generate a token that lets me retrieve all of my activities via the /athlete/activities end point.

I tried to do this by following these steps:

  1. Go to https://www.strava.com/settings/api and copy your Client ID

  2. Paste your Client ID into this URL: REPLACE_WITH_YOUR_CLIENT_ID&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=read

  3. Go to a browser

  4. Paste the URL you edited into the browser window (step 1 and 2 from the graph)

  5. Hit enter

  6. When you see the authorization page, click “Authorize” (step 3a from the graph)

strava 1
Figure 1. Strava Authorisation

Once we click on 'Authorize', the web browser redirects to a localhost URL that contains an authorisation code. For me, this URL looks like this:

http://localhost/exchange_token?state=&code=b55003496d87a9f0b694ca1680cd5690d27d9d28&scope=read

We then take that code and feed it into another request, which will generate a refresh token, access token, and access token expiration date:

curl -X POST https://www.strava.com/oauth/token \
-F client_id=YOURCLIENTID \
-F client_secret=YOURCLIENTSECRET \
-F code=b55003496d87a9f0b694ca1680cd5690d27d9d28 \
-F grant_type=authorization_code

This request will will return a JSON response that looks like this:

{
  "token_type": "Bearer",
  "expires_at": 1608060738,
  "expires_in": 18068,
  "refresh_token": "<refresh-token>",
  "access_token": "<access-token>",
  "athlete": {
    "id": 6958432,
    "username": null,
    "resource_state": 2,
    "firstname": "Mark",
    "lastname": "Needham",
    "city": "London",
    "state": "England",
    "country": "United Kingdom",
    "sex": "M",
    "premium": true,
    "summit": true,
    "created_at": "2014-11-01T10:48:26Z",
    "updated_at": "2020-08-10T06:23:51Z",
    "badge_type_id": 1,
    "profile_medium": "https://dgalywyr863hv.cloudfront.net/pictures/athletes/6958432/17352912/1/medium.jpg",
    "profile": "https://dgalywyr863hv.cloudfront.net/pictures/athletes/6958432/17352912/1/large.jpg",
    "friend": null,
    "follower": null
  }
}

We can then take the access_token and use that on requests against other API endpoints. For example, to retrieve my activities, we can make the following request:

curl -X GET https://www.strava.com/api/v3/athlete/activities -H 'Authorization: Bearer <access-token>'

When I ran that, I got the following response:

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

The mistake I’ve made was right at the beginning of the authentication process, when selecting the 'scope' on the initial request. We used the following URL:

http://www.strava.com/oauth/authorize?client_id=[REPLACE_WITH_YOUR_CLIENT_ID]&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=read

The scope is set to read when this API end point requires activity:read_all permissions, so the URL should instead read like this:

http://www.strava.com/oauth/authorize?client_id=[REPLACE_WITH_YOUR_CLIENT_ID]&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=activity:read_all

And if we do that and use the authorisation code that it returns to generate an access token, it all works as expected.

Now it’s time to analyse those runs!

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket