Laravel Strava Client

A developer-friendly package for seamless Strava API integration in Laravel applications

Built by Jordan Partridge - Laravel Integration Specialist & API Package Developer

Laravel 8-11 Compatible
MIT Licensed
Actively Maintained
View on GitHub See it in Action: Fat Bike Corps
composer require jordanpartridge/strava-client

Why Developers Choose Laravel Strava Client

Stop wrestling with OAuth complexity. Start building features that matter.

95%

Less Code Required

No OAuth routes, controllers, or token management

5 Min

Setup Time

From installation to working API calls

0

Maintenance Required

Automatic token refresh handles everything

😓 The Traditional Way (Complex & Error-Prone)

// Create OAuth routes and controllers
Route::get('/oauth/redirect', [OAuthController::class, 'redirect']);
Route::get('/oauth/callback', [OAuthController::class, 'callback']);

// Manual state verification and CSRF protection
$state = Str::random(32);
session(['oauth_state' => $state]);

// Build authorization URL manually
$query = http_build_query([
    'client_id' => config('strava.client_id'),
    'redirect_uri' => route('oauth.callback'),
    'response_type' => 'code',
    'scope' => 'read,activity:read_all',
    'state' => $state,
]);

// Manual token exchange and validation
$response = Http::post('https://www.strava.com/oauth/token', [
    'client_id' => config('strava.client_id'),
    'client_secret' => config('strava.client_secret'),
    'code' => $request->code,
    'grant_type' => 'authorization_code',
]);

// Manual token refresh before every API call
if ($token->expires_at < now()) {
    $refreshResponse = Http::post('https://www.strava.com/oauth/token', [
        'client_id' => config('strava.client_id'),
        'client_secret' => config('strava.client_secret'),
        'grant_type' => 'refresh_token',
        'refresh_token' => $token->refresh_token,
    ]);
    // Update stored tokens...
}

// Manual API calls with error handling
$activities = Http::withToken($token->access_token)
    ->get('https://www.strava.com/api/v3/athlete/activities');

if ($activities->status() === 401) {
    // Token expired, need to refresh again...
}
                            

🚀 The Laravel Strava Client Way (Simple & Bulletproof)

// ✅ OAuth routes auto-registered - NO setup needed!
// /strava/redirect - starts OAuth flow
// /strava/callback - handles OAuth callback

// ✅ Just redirect users to start authentication
return redirect('/strava/redirect');

// ✅ Tokens automatically stored after OAuth
// Package handles the entire callback flow

// ✅ Set and forget - just make API calls!
use JordanPartridge\StravaClient\Facades\StravaClient;

// Get activities - tokens auto-refresh if expired
$activities = StravaClient::activityForAthlete(1, 30);

// Get specific activity - still auto-refreshes
$activity = StravaClient::getActivity(12345678);

// Get athlete profile - auto-refreshes too
$athlete = StravaClient::getAthlete();

// Every API call automatically:
// 1. Checks if token is expired
// 2. Refreshes token if needed (up to 3 attempts)
// 3. Updates database with new token
// 4. Makes the API call
// 5. Returns clean data

// Zero token management required! 🎉
                            

Overview

The Laravel Strava Client is a comprehensive package designed to seamlessly integrate Strava API functionality into Laravel applications. Created by Jordan Partridge, a specialist in building Laravel integration packages, this package provides developers with tools to authenticate, retrieve, and manipulate Strava activity data through an elegant and Laravel-friendly interface.

Part of Jordan's Integration Package Suite

This is one of several Laravel integration packages built by Jordan Partridge, including Gmail Client, GitHub integrations, and other API connectors. Each package follows the same philosophy: zero-configuration setup with bulletproof reliability.

Key Features:

  • Enterprise-Grade OAuth Integration: Zero-configuration setup with auto-registered routes and controllers
  • Bulletproof Token Management: Automatic refresh with failover protection (up to 3 retry attempts)
  • Production-Ready Reliability: Built by an integration specialist with real-world experience
  • Laravel-Native Architecture: Follows Laravel conventions with encrypted database storage
  • Saloon HTTP Foundation: Modern HTTP client with comprehensive error handling
  • Seamless Model Integration: HasStravaTokens trait for effortless user relationships
  • API Rate Limit Protection: Built-in safeguards and intelligent retry logic
  • Professional Integration Standards: Same patterns used in Jordan's other integration packages

🚀 Quick Start Guide

Get up and running with Strava integration in less than 5 minutes!

1

Install the Package

composer require jordanpartridge/strava-client
2

Create a Strava App

Go to Strava API Settings and create a new application:

  • Application Name: Your App Name
  • Category: Choose appropriate category
  • Website: https://yourdomain.com
  • Authorization Callback Domain: yourdomain.com

💡 Important: The callback domain must match your domain exactly (without http/https prefix)

3

Configure Environment Variables

Add these to your .env file with your Strava app credentials:

STRAVA_CLIENT_ID=your-client-id-from-strava
STRAVA_CLIENT_SECRET=your-client-secret-from-strava
STRAVA_REDIRECT_URI=https://yourdomain.com/strava/callback

# Optional: Configure where to redirect after successful connection
STRAVA_REDIRECT_AFTER_CONNECT=/dashboard
4

Publish Configuration & Run Migrations

php artisan vendor:publish --tag=strava-client-config
php artisan vendor:publish --tag=strava-client-migrations
php artisan migrate
5

Add Trait to User Model

use JordanPartridge\StravaClient\Concerns\HasStravaTokens;
use JordanPartridge\StravaClient\Contracts\HasStravaToken;

class User extends Authenticatable implements HasStravaToken
{
    use HasStravaTokens;

    // Your existing code...
}

That's It! Start Using the API

Users can now connect their Strava accounts and you can fetch their data:

// In your Blade template - connect Strava button
<a href="/strava/redirect" class="btn btn-primary">
    Connect Strava Account
</a>

// In your controller - fetch activities (auto-refreshes tokens!)
use JordanPartridge\StravaClient\Facades\StravaClient;

$activities = StravaClient::activityForAthlete(1, 30);
$athlete = StravaClient::getAthlete();
$activity = StravaClient::getActivity(12345678);

🎉 Congratulations! You now have a fully functional Strava integration with automatic token refresh, zero-config OAuth, and bulletproof error handling.

Basic Usage

Zero-Configuration Authentication

The package automatically handles the entire OAuth 2.0 flow! No routes, controllers, or callback handling needed.

Step 1: Add the HasStravaTokens trait to your User model

use JordanPartridge\StravaClient\Concerns\HasStravaTokens;
use JordanPartridge\StravaClient\Contracts\HasStravaToken;

class User extends Authenticatable implements HasStravaToken
{
    use HasStravaTokens;
    // ...
}

Step 2: Direct users to start authentication

The package provides ready-to-use routes automatically:

// In your blade template or controller
<a href="/strava/redirect" class="btn btn-primary">
    Connect Strava Account
</a>

// Or programmatically
return redirect('/strava/redirect');

Step 3: That's it! 🎉

The package automatically:

  • Handles OAuth redirect to Strava
  • Processes the callback at /strava/callback
  • Exchanges authorization code for tokens
  • Stores encrypted tokens in the database
  • Redirects users back to your configured success page

Configure where to redirect after successful connection:

// In config/strava-client.php
'redirect_after_connect' => '/dashboard', // or wherever you want

Automatic Token Refresh - Set and Forget!

The package automatically refreshes expired tokens on every API call. You never need to worry about token expiration again!

How Auto-Refresh Works:

  1. You make any API call (activities, athlete data, etc.)
  2. Package checks if token is expired or will expire soon
  3. If expired, automatically refreshes token using refresh_token
  4. Updates database with new access_token and expires_at
  5. Retries the original API call with fresh token
  6. Returns your data as if nothing happened!

💡 Pro Tip: The package will attempt up to 3 refresh attempts before giving up. If all attempts fail, it throws a MaxAttemptsException so you can handle the error gracefully.

Fetching Activities

Once authenticated, simply make API calls. Token refresh happens automatically behind the scenes:

use JordanPartridge\StravaClient\Facades\StravaClient;

// Set tokens from your stored user tokens
$token = auth()->user()->stravaToken;
StravaClient::setToken($token->access_token, $token->refresh_token);

// Get recent activities (page 1, 30 per page)
$activities = StravaClient::activityForAthlete(1, 30);

// Get more activities (page 2, 50 per page)
$moreActivities = StravaClient::activityForAthlete(2, 50);

// Get a specific activity by ID
$activity = StravaClient::getActivity(12345678);

Syncing Activities to Your Database

The package provides a convenient way to sync Strava activities to your application's database:

use JordanPartridge\StravaClient\Facades\Strava;
use App\Models\Ride;

public function syncActivities()
{
    $activities = Strava::activities()->get();

    foreach ($activities as $activity) {
        Ride::updateOrCreate(
            ['external_id' => $activity['id']],
            [
                'name' => $activity['name'],
                'distance' => $activity['distance'],
                'moving_time' => $activity['moving_time'],
                'elapsed_time' => $activity['elapsed_time'],
                'elevation' => $activity['total_elevation_gain'],
                'date' => Carbon::parse($activity['start_date']),
                'average_speed' => $activity['average_speed'],
                'max_speed' => $activity['max_speed'],
                'calories' => $activity['calories'] ?? 0,
                'polyline' => $activity['map']['summary_polyline'] ?? null,
            ]
        );
    }
}

Advanced Usage

Automatic Token Refresh

The package automatically handles token refreshing when tokens expire. Here's how it works:

How Auto-Refresh Works:

  1. You make an API call with potentially expired tokens
  2. If Strava returns HTTP 401 (token expired), the package detects this
  3. Package automatically uses the refresh_token to get new tokens
  4. New tokens are set in the client automatically
  5. Your original API request is retried with fresh tokens
  6. Data is returned as if nothing happened!
// You don't need to check token expiry - the package handles it!
$token = auth()->user()->stravaToken;
StravaClient::setToken($token->access_token, $token->refresh_token);

// This call will auto-refresh tokens if needed
$activities = StravaClient::activityForAthlete(1, 30);

// Built-in retry protection (max 3 attempts)
// Throws MaxAttemptsException if refresh fails repeatedly

Error Handling

The package provides comprehensive error handling for various API scenarios:

use JordanPartridge\StravaClient\Facades\StravaClient;
use JordanPartridge\StravaClient\Exceptions\Request\RateLimitExceededException;
use JordanPartridge\StravaClient\Exceptions\Request\ResourceNotFoundException;
use JordanPartridge\StravaClient\Exceptions\Authentication\MaxAttemptsException;

try {
    $activities = StravaClient::activityForAthlete(1, 30);
} catch (RateLimitExceededException $e) {
    // Handle rate limiting (429 status)
    logger('Rate limited by Strava API');
} catch (ResourceNotFoundException $e) {
    // Handle 404 errors
    logger('Resource not found');
} catch (MaxAttemptsException $e) {
    // Handle when token refresh fails repeatedly
    logger('Token refresh failed after max attempts');
}

Example Implementation

The "Fat Bike Corps" page on jordanpartridge.us demonstrates a complete implementation of the Strava Client package.

From the SyncActivitiesJob

use JordanPartridge\StravaClient\Facades\Strava;

public function handle()
{
    $activities = Strava::activities()
        ->after(now()->subDays(30))
        ->perPage(50)
        ->get();

    foreach ($activities as $activity) {
        Ride::updateOrCreate(
            ['external_id' => $activity['id']],
            [
                'name' => $activity['name'],
                'distance' => $activity['distance'],
                'moving_time' => $activity['moving_time'],
                'elevation' => $activity['total_elevation_gain'],
                'date' => Carbon::parse($activity['start_date']),
                'average_speed' => $activity['average_speed'],
                'max_speed' => $activity['max_speed'],
                'polyline' => $activity['map']['summary_polyline'] ?? null,
            ]
        );
    }

    // Clear cached metrics to ensure fresh data
    app(RideMetricService::class)->clearCache();
}

Frequently Asked Questions

How does Laravel Strava Client handle token refresh?

The package automatically refreshes expired tokens when making API requests. You only need to implement the HasStravaTokens trait in your User model, and the package will handle refreshing the token when it expires.

Which Laravel versions are supported?

Laravel Strava Client is compatible with Laravel 8, 9, 10, and 11. For older Laravel versions, you may need to use a previous version of the package.

How does the automatic token refresh work?

When you make an API call and Strava returns HTTP 401 (token expired), the package automatically uses your stored refresh_token to get new access tokens, then retries your original request. This happens transparently with built-in retry protection (max 3 attempts).

Can I use this package with Laravel Sail or Docker?

Yes, the package works seamlessly with Laravel Sail and Docker environments. There are no specific configuration changes needed for containerized environments.

Does this package support queued jobs for syncing activities?

Yes, you can easily dispatch Laravel jobs to sync activities in the background. This is especially useful when setting up webhooks to receive real-time updates from Strava.

User of Laravel Strava Client
"This package saved me hours of development time. I was able to integrate Strava in my cycling app with just a few lines of code. The automatic token refresh handling is especially impressive - I never have to worry about expired tokens!"
Jordan P.
Developer of Fat Bike Corps

Built by a Laravel Integration Specialist

Strava Integration

Zero-config OAuth with automatic token refresh

Gmail Integration

Enterprise-grade email API integration

GitHub Integration

Repository sync and webhook handling

Jordan Partridge specializes in building production-ready Laravel integration packages that follow enterprise standards and eliminate the complexity of API integrations.

View All Integration Packages