---
title: "Strava OAuth 2.0 Authentication Guide | Apps for Strava"
canonical: https://appsforstrava.com/developers/authentication
source: Markdown mirror of https://appsforstrava.com/developers/authentication — the HTML page is canonical.
---

# Authentication

Strava uses OAuth 2.0 for authentication. This guide covers the complete authorization flow, permission scopes, and token management.

## OAuth 2.0 Flow Overview

The OAuth flow allows users to grant your application access to their Strava data without sharing their password. Here's how it works:

1.  Redirect to Strava
    
    Your app redirects the user to Strava's authorization page
    
2.  User Grants Permission
    
    User logs in and approves the requested permissions (scopes)
    
3.  Receive Authorization Code
    
    Strava redirects back to your app with a temporary authorization code
    
4.  Exchange for Tokens
    
    Your server exchanges the code for access and refresh tokens
    

## Step 1: Redirect to Authorization URL

Construct the authorization URL and redirect users to it:

```
https://www.strava.com/oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  redirect_uri=YOUR_CALLBACK_URL&
  response_type=code&
  scope=read,activity:read_all
```

| Parameter | Description |
| --- | --- |
| client\_id | Your application's Client ID |
| redirect\_uri | URL to redirect to after authorization (must match your app settings) |
| response\_type | Must be `code` |
| scope | Comma- or space-delimited list of requested permissions (required) |
| state | (Optional) Random string to prevent CSRF attacks |

## Permission Scopes

Scopes define what data your app can access. Request only the scopes you need:

| Scope | Access Granted |
| --- | --- |
| read | Public segments, routes, profile data, posts, events, club feeds, leaderboards |
| read\_all | Private routes, segments, and events (in addition to `read`) |
| profile:read\_all | All profile information, even if profile visibility is set to Followers or Only You |
| profile:write | Update athlete weight, FTP, and star/unstar segments |
| activity:read | Activities visible to "Everyone" or "Followers", excluding privacy zone data |
| activity:read\_all | All activities, including "Only You" and privacy zones |
| activity:write | Create manual activities, upload files, and edit activities |

**Best Practice:** Only request the minimum scopes your app needs. Users are more likely to authorize apps that request limited permissions.

## Step 2: Exchange Authorization Code for Tokens

After the user authorizes your app, they're redirected to your callback URL with a `code` parameter. Exchange this code for tokens:

```
curl -X POST https://www.strava.com/oauth/token \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d code=AUTHORIZATION_CODE \
  -d grant_type=authorization_code
```

### Response

```
{
  "token_type": "Bearer",
  "expires_at": 1704931200,
  "expires_in": 21600,
  "refresh_token": "REFRESH_TOKEN_HERE",
  "access_token": "ACCESS_TOKEN_HERE",
  "athlete": {
    "id": 12345678,
    "username": "athlete_username",
    "firstname": "John",
    "lastname": "Doe"
  }
}
```

| Field | Description |
| --- | --- |
| access\_token | Token to use for API requests |
| refresh\_token | Token to get new access tokens (save this securely!) |
| expires\_at | Unix timestamp when the access token expires |
| expires\_in | Seconds until expiration (6 hours = 21600) |

## Refreshing Access Tokens

Access tokens expire after **6 hours**. Use the refresh token to get a new access token:

```
curl -X POST https://www.strava.com/oauth/token \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d refresh_token=CURRENT_REFRESH_TOKEN \
  -d grant_type=refresh_token
```

Important: Refresh Token Rotation

Whenever Strava issues a new access token, it returns a **new refresh token** and invalidates the old one, so always save the refresh token from the response. One caveat: if your current access token still has more than an hour of life, Strava returns the existing tokens instead of minting new ones.

### JavaScript Example

```
async function refreshAccessToken(refreshToken) {
  const response = await fetch('https://www.strava.com/oauth/token', {
    method: 'POST',
    body: new URLSearchParams({
      client_id: process.env.STRAVA_CLIENT_ID,
      client_secret: process.env.STRAVA_CLIENT_SECRET,
      refresh_token: refreshToken,
      grant_type: 'refresh_token'
    })
  });

  const data = await response.json();

  // IMPORTANT: Save the new refresh token!
  await saveTokens(data.access_token, data.refresh_token, data.expires_at);

  return data.access_token;
}
```

## Deauthorization

Users can revoke access from their Strava settings, or your app can programmatically deauthorize. The current endpoint is `POST /oauth/revoke` (added June 1, 2026), authenticated with HTTP Basic using your client ID and secret:

```
curl -X POST https://www.strava.com/oauth/revoke \
  -u "CLIENT_ID:CLIENT_SECRET" \
  -d "token=ACCESS_TOKEN" \
  -d "token_type_hint=access_token"
```

The older `POST /oauth/deauthorize` (which takes an `access_token` parameter) still works but is now legacy. Strava has said `/oauth/revoke` becomes the sole supported method on June 1, 2027.

Either way, this invalidates all tokens and removes your app from the athlete's authorized applications.

## Next Steps

- [API Reference](https://appsforstrava.com/developers/api-reference): Explore all available endpoints
- [Code Examples](https://appsforstrava.com/developers/examples): Complete OAuth implementation examples
