PHPackages                             little-green-man/earhart - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. little-green-man/earhart

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

little-green-man/earhart
========================

A package to help use PropelAuth with Laravel

2.0.0(4mo ago)3124↓77.8%1[1 PRs](https://github.com/little-green-man/earhart/pulls)MITPHPPHP ^8.3CI passing

Since Nov 9Pushed 2mo agoCompare

[ Source](https://github.com/little-green-man/earhart)[ Packagist](https://packagist.org/packages/little-green-man/earhart)[ Docs](https://github.com/little-green-man/earhart)[ GitHub Sponsors](https://github.com/kurucu)[ Fund](https://thanks.dev/kurucu)[ RSS](/packages/little-green-man-earhart/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)Dependencies (9)Versions (16)Used By (0)

[![](docs/earhart.png)](https://github.com/little-green-man/earhart)

Earhart
=======

[](#earhart)

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](https://docs.propelauth.com/reference/api/getting-started) integration to retrieve and manage user and organisation data.

Thanks to [Laravel News](https://laravel-news.com) for the artwork.

Features
--------

[](#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
------------

[](#installation)

### 1. Install the package via composer:

[](#1-install-the-package-via-composer)

```
composer require little-green-man/earhart
```

### 2. Configure PropelAuth

[](#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 &gt; Svix &gt; tick all events and set test and prod URLs to `https://{your_app_url}/auth/webhooks`

### 3. Set environment variables:

[](#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

[](#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

[](#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 `password` nullable or remove it
- Add any organisation/team models and relations you need

### 6. Add authentication routes

[](#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

[](#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:

[](#8-add-authentication-links-to-your-views)

```
Login
Logout
```

Optionally, add links to PropelAuth's hosted pages:

```
Account
Account Settings
Create Organisation
Organisation Members
Organisation Settings
```

Alternatively, implement these features in your own application using Earhart's API integrations.

Refreshing User Tokens
----------------------

[](#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](docs/REFRESHING_USER_TOKENS.md) for implementation details.

Registered Routes
-----------------

[](#registered-routes)

The following routes are registered automatically:

- `auth.redirect` - Redirect to PropelAuth login
- `auth.account` - PropelAuth account manager
- `auth.settings` - Account settings (requires org\_id query parameter)
- `auth.org.create` - Create new organization
- `auth.org.members` - Organization members (requires org\_id query parameter)
- `auth.org.settings` - Organization settings (requires org\_id query parameter)

Webhook Events
--------------

[](#webhook-events)

Create listeners in your application for these events:

### Organization Events

[](#organization-events)

- `LittleGreenMan\Earhart\Events\PropelAuth\OrgCreated` - Organization created
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgDeleted` - Organization deleted
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgUpdated` - Organization updated
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgApiKeyDeleted` - Organization API key deleted
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgSamlRemoved` - SAML connection removed
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgSamlSetup` - SAML setup initiated
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgSamlWentLive` - SAML connection went live
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupCreated` - SCIM group created
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupDeleted` - SCIM group deleted
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgScimGroupUpdated` - SCIM group updated
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgScimKeyCreated` - SCIM key created
- `LittleGreenMan\Earhart\Events\PropelAuth\OrgScimKeyRevoked` - SCIM key revoked

### User Events

[](#user-events)

- `LittleGreenMan\Earhart\Events\PropelAuth\UserCreated` - User created
- `LittleGreenMan\Earhart\Events\PropelAuth\UserUpdated` - User profile updated
- `LittleGreenMan\Earhart\Events\PropelAuth\UserDeleted` - User deleted
- `LittleGreenMan\Earhart\Events\PropelAuth\UserEnabled` - User account enabled
- `LittleGreenMan\Earhart\Events\PropelAuth\UserDisabled` - User account disabled
- `LittleGreenMan\Earhart\Events\PropelAuth\UserLocked` - User account locked
- `LittleGreenMan\Earhart\Events\PropelAuth\UserAddedToOrg` - User added to organization
- `LittleGreenMan\Earhart\Events\PropelAuth\UserRemovedFromOrg` - User removed from organization
- `LittleGreenMan\Earhart\Events\PropelAuth\UserRoleChangedWithinOrg` - User role changed in organization
- `LittleGreenMan\Earhart\Events\PropelAuth\UserAddedToScimGroup` - User added to SCIM group
- `LittleGreenMan\Earhart\Events\PropelAuth\UserRemovedFromScimGroup` - User removed from SCIM group
- `LittleGreenMan\Earhart\Events\PropelAuth\UserDeletedPersonalApiKey` - User deleted personal API key
- `LittleGreenMan\Earhart\Events\PropelAuth\UserImpersonated` - User impersonated
- `LittleGreenMan\Earhart\Events\PropelAuth\UserInvitedToOrg` - User invited to organization
- `LittleGreenMan\Earhart\Events\PropelAuth\UserLoggedOut` - User logged out
- `LittleGreenMan\Earhart\Events\PropelAuth\UserLogin` - User logged in
- `LittleGreenMan\Earhart\Events\PropelAuth\UserSendMfaPhoneCode` - MFA phone code sent to user

### Example Listener

[](#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
--------------------

[](#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](docs/USING_PROPEL_API.md) for complete API documentation.

Advanced Webhook Verification
-----------------------------

[](#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](docs/ADVANCED_WEBHOOK_VERIFICATION.md).

Package Testing
---------------

[](#package-testing)

Run the test suite:

```
./vendor/bin/pest
```

Run only webhook tests:

```
./vendor/bin/pest tests/Unit/Webhooks/ tests/Feature/Webhooks/
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

Credits
-------

[](#credits)

- [Elliot](https://github.com/kurucu)
- [Yannick](https://github.com/ylynfatt)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 90% of packages

Maintenance80

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 83.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Recently: every ~0 days

Total

13

Last Release

147d ago

Major Versions

1.6.0 → 2.0.02026-01-31

PHP version history (2 changes)1.0.0PHP ^8.4

1.0.5PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/389f4ae921e5c8ca8aaf09f30ccfed468db187252ef46d30e6dc8ee615cdbba3?d=identicon)[lgm](/maintainers/lgm)

---

Top Contributors

[![kurucu](https://avatars.githubusercontent.com/u/1073323?v=4)](https://github.com/kurucu "kurucu (15 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")[![ylynfatt](https://avatars.githubusercontent.com/u/19831?v=4)](https://github.com/ylynfatt "ylynfatt (1 commits)")

---

Tags

laravelpropelauthLittle Green ManEarhart

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/little-green-man-earhart/health.svg)

```
[![Health](https://phpackages.com/badges/little-green-man-earhart/health.svg)](https://phpackages.com/packages/little-green-man-earhart)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[laravel/ai

The official AI SDK for Laravel.

9782.1M162](/packages/laravel-ai)[moonshine/moonshine

Laravel administration panel

1.3k239.9k76](/packages/moonshine-moonshine)[illuminate/auth

The Illuminate Auth package.

9327.9M1.2k](/packages/illuminate-auth)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1542.1k4](/packages/masterix21-laravel-licensing)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
