A developer-friendly package for seamless Strava API integration in Laravel applications
Built by Jordan Partridge - Laravel Integration Specialist & API Package Developer
Stop wrestling with OAuth complexity. Start building features that matter.
Less Code Required
No OAuth routes, controllers, or token management
Setup Time
From installation to working API calls
Maintenance Required
Automatic token refresh handles everything
// 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...
}
// ✅ 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! 🎉
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.
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:
Get up and running with Strava integration in less than 5 minutes!
composer require jordanpartridge/strava-client
Go to Strava API Settings and create a new application:
💡 Important: The callback domain must match your domain exactly (without http/https prefix)
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
php artisan vendor:publish --tag=strava-client-config
php artisan vendor:publish --tag=strava-client-migrations
php artisan migrate
use JordanPartridge\StravaClient\Concerns\HasStravaTokens;
use JordanPartridge\StravaClient\Contracts\HasStravaToken;
class User extends Authenticatable implements HasStravaToken
{
use HasStravaTokens;
// Your existing code...
}
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.
The package automatically handles the entire OAuth 2.0 flow! No routes, controllers, or callback handling needed.
use JordanPartridge\StravaClient\Concerns\HasStravaTokens;
use JordanPartridge\StravaClient\Contracts\HasStravaToken;
class User extends Authenticatable implements HasStravaToken
{
use HasStravaTokens;
// ...
}
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');
The package automatically:
/strava/callback
Configure where to redirect after successful connection:
// In config/strava-client.php
'redirect_after_connect' => '/dashboard', // or wherever you want
The package automatically refreshes expired tokens on every API call. You never need to worry about token expiration again!
💡 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.
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);
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,
]
);
}
}
The package automatically handles token refreshing when tokens expire. Here's how it works:
// 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
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');
}
The "Fat Bike Corps" page on jordanpartridge.us demonstrates a complete implementation of the Strava Client package.
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();
}
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.
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.
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).
Yes, the package works seamlessly with Laravel Sail and Docker environments. There are no specific configuration changes needed for containerized environments.
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.
"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!"
Zero-config OAuth with automatic token refresh
Enterprise-grade email API 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