little-green-man / earhart
A package to help use PropelAuth with Laravel
Fund package maintenance!
kurucu
Thanks Dev
Installs: 102
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 0
Forks: 1
Open Issues: 1
pkg:composer/little-green-man/earhart
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0
- illuminate/support: ^11.0|^12.0
- socialiteproviders/propelauth: ^4.0
- spatie/laravel-data: ^4.18
- svix/svix: ^1.81
Requires (Dev)
- larastan/larastan: ^2.0 || ^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^9.15|^10.0
- pestphp/pest: ^1.23|^2.1|^3.1|^4.0
README
A Laravel package that makes working with PropelAuth easier.
Primarily it helps your app use PropelAuth's OAuth flow to log users in via Socialite, and API integration to retrieve and manage user and organisation data.
Features
- Authentication: Socialite integration with easy route controllers for PropelAuth OAuth
- Secure Webhook Handling that drives Events: Verified webhooks fire events you can listen for in your application when e.g. user details change at PropelAuth
- API Integration: Built-in PropelAuth API client for querying data and to build functionality into your app seamlessly.
- Configuration: Flexible webhook configuration with cache invalidation rules (v1.4+)
Installation
1. Install the package via composer:
composer require little-green-man/earhart
2. Configure PropelAuth
In your PropelAuth dashboard:
- Configure general settings (e.g. password requirements)
- Enable these User properties (default settings are fine):
- Name
- Profile Picture
- Terms of Service
- Configure organisation settings as needed
- Set webhook URLs: Integration > Svix > tick all events and set test and prod URLs to
https://{your_app_url}/auth/webhooks
3. Set environment variables:
PROPELAUTH_CLIENT_ID="tbc" PROPELAUTH_CLIENT_SECRET="tbc" PROPELAUTH_CALLBACK_URL=https://localhost/auth/callback PROPELAUTH_AUTH_URL=https://0000000000.propelauthtest.com PROPELAUTH_SVIX_SECRET="whsec_tbd" PROPELAUTH_API_KEY="tbc" PROPELAUTH_CACHE_ENABLED=false PROPELAUTH_CACHE_TTL=60
4. Configure services
Add PropelAuth configuration to config/services.php:
'propelauth' => [ 'client_id' => env('PROPELAUTH_CLIENT_ID'), 'client_secret' => env('PROPELAUTH_CLIENT_SECRET'), 'redirect' => env('PROPELAUTH_CALLBACK_URL'), 'auth_url' => env('PROPELAUTH_AUTH_URL'), 'svix_secret' => env('PROPELAUTH_SVIX_SECRET'), 'api_key' => env('PROPELAUTH_API_KEY'), ],
Optionally, publish Earhart's config file to customise caching and other settings:
php artisan vendor:publish --provider="LittleGreenMan\Earhart\ServiceProvider" --tag="config"
This creates config/earhart.php where you can customise default values.
5. Update your database
Add these fields to your User model/migration:
propel_id(string)propel_access_token(string)propel_refresh_token(string)avatar(string)data(json)- Make
passwordnullable or remove it - Add any organisation/team models and relations you need
6. Add authentication routes
Add the webhook route to routes/web.php:
Route::post('/auth/webhooks', AuthWebhookController::class) ->middleware(LittleGreenMan\Earhart\Middleware\VerifySvixWebhook::class) ->withoutMiddleware('web') ->name('auth.webhook');
Add the OAuth callback and logout routes to routes/web.php:
use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; use Laravel\Socialite\Facades\Socialite; Route::get('/auth/callback', function(Request $request){ $propelUser = Socialite::driver('propelauth')->user(); $rawUser = $propelUser->getRaw(); $user = User::updateOrCreate([ 'propel_id' => $propelUser->id, ], [ 'name' => $rawUser['first_name'] . ' ' . $rawUser['last_name'], 'email' => $propelUser->email, 'propel_access_token' => $propelUser->token, 'propel_refresh_token' => $propelUser->refreshToken, 'avatar' => $rawUser['picture_url'], 'data' => json_encode($rawUser), 'email_verified_at' => $rawUser['email_confirmed'] ? now() : null, ]); Auth::login($user); // you might also want to update and sync `$user`'s organisations with `$rawUser['org_id_to_org_info']`; return redirect('/dashboard'); })->name('auth.callback'); Route::get('/auth/logout', function(Request $request){ // IMPORTANT: Fetch the refresh token BEFORE calling Auth::logout() // Calling Auth::logout() first will clear the authenticated user, resulting in: // "Attempt to read property 'propel_refresh_token' on null" $response = Http::withHeaders([ 'Content-Type' => 'application/json', ])->post(config('services.propelauth.auth_url') . '/api/backend/v1/logout', [ 'refresh_token' => Auth::user()->propel_refresh_token, ]); if ($response->failed()) { Log::debug('Failed to log out from PropelAuth', ['response' => $response->body()]); } Auth::logout(); return redirect('/'); })->name('auth.logout');
7. Register the Socialite provider
Add this to the boot method of your AppServiceProvider:
use Illuminate\Support\Facades\Event; use SocialiteProviders\Manager\SocialiteWasCalled; Event::listen(function (SocialiteWasCalled $event) { $event->extendSocialite('propelauth', \SocialiteProviders\PropelAuth\Provider::class); });
8. Add authentication links to your views:
<a href="{{ route('auth.redirect') }}">Login</a> <a href="{{ route('auth.logout') }}">Logout</a>
Optionally, add links to PropelAuth's hosted pages:
<a href="{{ route('auth.account') }}">Account</a> <a href="{{ route('auth.settings') }}">Account Settings</a> <a href="{{ route('auth.org.create') }}">Create Organisation</a> <a href="{{ route('auth.org.members') }}">Organisation Members</a> <a href="{{ route('auth.org.settings') }}">Organisation Settings</a>
Alternatively, implement these features in your own application using Earhart's API integrations.
Refreshing User Tokens
PropelAuth access tokens expire after 30 minutes. To keep user tokens fresh and prevent authentication failures, you should set up a scheduled job to refresh them automatically.
See docs/REFRESHING_USER_TOKENS.md for implementation details.
Registered Routes
The following routes are registered automatically:
auth.redirect- Redirect to PropelAuth loginauth.account- PropelAuth account managerauth.settings- Account settings (requires org_id query parameter)auth.org.create- Create new organizationauth.org.members- Organization members (requires org_id query parameter)auth.org.settings- Organization settings (requires org_id query parameter)
Webhook Events
Create listeners in your application for these events:
Organization Events
LittleGreenMan\Earhart\Events\PropelAuth\OrgCreated- Organization createdLittleGreenMan\Earhart\Events\PropelAuth\OrgDeleted- Organization deletedLittleGreenMan\Earhart\Events\PropelAuth\OrgUpdated- Organization updatedLittleGreenMan\Earhart\Events\PropelAuth\OrgApiKeyDeleted- Organization API key deletedLittleGreenMan\Earhart\Events\PropelAuth\OrgSamlRemoved- SAML connection removedLittleGreenMan\Earhart\Events\PropelAuth\OrgSamlSetup- SAML setup initiatedLittleGreenMan\Earhart\Events\PropelAuth\OrgSamlWentLive- SAML connection went liveLittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupCreated- SCIM group createdLittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupDeleted- SCIM group deletedLittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupUpdated- SCIM group updatedLittleGreenMan\Earhart\Events\PropelAuth\OrgScimKeyCreated- SCIM key createdLittleGreenMan\Earhart\Events\PropelAuth\OrgScimKeyRevoked- SCIM key revoked
User Events
LittleGreenMan\Earhart\Events\PropelAuth\UserCreated- User createdLittleGreenMan\Earhart\Events\PropelAuth\UserUpdated- User profile updatedLittleGreenMan\Earhart\Events\PropelAuth\UserDeleted- User deletedLittleGreenMan\Earhart\Events\PropelAuth\UserEnabled- User account enabledLittleGreenMan\Earhart\Events\PropelAuth\UserDisabled- User account disabledLittleGreenMan\Earhart\Events\PropelAuth\UserLocked- User account lockedLittleGreenMan\Earhart\Events\PropelAuth\UserAddedToOrg- User added to organizationLittleGreenMan\Earhart\Events\PropelAuth\UserRemovedFromOrg- User removed from organizationLittleGreenMan\Earhart\Events\PropelAuth\UserRoleChangedWithinOrg- User role changed in organizationLittleGreenMan\Earhart\Events\PropelAuth\UserAddedToScimGroup- User added to SCIM groupLittleGreenMan\Earhart\Events\PropelAuth\UserRemovedFromScimGroup- User removed from SCIM groupLittleGreenMan\Earhart\Events\PropelAuth\UserDeletedPersonalApiKey- User deleted personal API keyLittleGreenMan\Earhart\Events\PropelAuth\UserImpersonated- User impersonatedLittleGreenMan\Earhart\Events\PropelAuth\UserInvitedToOrg- User invited to organizationLittleGreenMan\Earhart\Events\PropelAuth\UserLoggedOut- User logged outLittleGreenMan\Earhart\Events\PropelAuth\UserLogin- User logged inLittleGreenMan\Earhart\Events\PropelAuth\UserSendMfaPhoneCode- MFA phone code sent to user
Example Listener
namespace App\Listeners; use App\Models\Organisation; use LittleGreenMan\Earhart\Events\PropelAuth\OrgCreated; class PropelAuthOrgCreatedListener { public function handle(OrgCreated $event): void { Organisation::create([ 'name' => $event->name, 'propel_id' => $event->org_id, ]); } }
PropelAuth API Usage
Use the PropelAuth API within your application:
$orgs = app('earhart')->getOrganisations(); $org = app('earhart')->getOrganisation('org_uuid'); // Returns array of UserData objects $users = app('earhart')->getUsersInOrganisation('org_uuid'); // For pagination control, use the service directly: $result = app('earhart')->organisations()->getOrganisationUsers('org_uuid', pageSize: 50); // $result is PaginatedResult with totalItems, hasMoreResults, etc.
See USING_PROPEL_API.md for complete API documentation.
Advanced Webhook Verification
The middleware shown in step 6 provides secure webhook verification out of the box.
For advanced webhook signature verification options (v1.4+), see ADVANCED_WEBHOOK_VERIFICATION.md.
Package Testing
Run the test suite:
./vendor/bin/pest
Run only webhook tests:
./vendor/bin/pest tests/Unit/Webhooks/ tests/Feature/Webhooks/
Changelog
Please see CHANGELOG.md for more information on what has changed recently.
Contributing
Please see CONTRIBUTING.md for details.
Credits
License
The MIT License (MIT). Please see License File for more information.