Search by

mindtwo / px-user-laravel

mindtwo

Package for handling PX User authentication for Laravel.

Package info

github.com/mindtwo/px-user-laravel

pkg:composer/mindtwo/px-user-laravel

Statistics

Installs: 14

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

4.2.2 2026-10-29 09:38 UTC

This package is auto-updated.

Last update: 2026-10-29 09:39:14 UTC


README

Latest Version on Packagist Software License Total Downloads

Installation

You can install the package via composer:

composer require mindtwo/px-user-laravel

How to use?

Publish config

To publish the modules config file simply run

php artisan vendor:publish px-user

This publishes the px-user.php config file to your projects config folder.

Configure the package

After that you should add the following keys to your .env-file:

  • PX_USER_M2M
  • PX_USER_TENANT
  • PX_USER_DOMAIN

This keys will auto populate the respective config values.

Inside your configuration you will also find the keys:

stage which will use your APP_ENV variable and px_user_cache_time which simply determines for how long the package is allowed to cache the user data in minutes.

Set PX_USER_EXTENDED_PRODUCTS_ON_LOGIN=true (config key extended_products_on_login) to request the user's extended products, e.g. products_validity, when the user is resolved on login and token refresh. By default PX User returns the products without them.

PX_USER_PRODUCT_CODE (config key product_code, default lms) is sent as the X-Context-Product-Code header on user search and user details requests.

Prepare the User model

First you will need to add a column px_user_id to your users table. This value is used to retrieve the cached user data.

This is necessary since PX User only allows us to cache the user data and not to store them inside a database, we rely on caching the data. This is done using Laravel Cache facade. To seemlessly integrate the data for use with your User model the package provides a trait.

use mindtwo\PxUserLaravel\Traits\UseUserDataCache;

class User extends Model
{
    use UseUserDataCache;
}

This trait overrides the models getAttribute($name) method so you can use $user->lastname even though there is no lastname column inside your users table.

Login a user

To login a user the package provides an action called PxUserLoginAction. Utilize this action inside a controller to retrieve the user data from PX Users api.

An example for such a controller is given below:

use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use mindtwo\PxUserLaravel\Actions\PxUserLoginAction;

class LoginController extends Controller
{
    public function __construct(
        protected PxUserLoginAction $pxUserLoginAction,
    ) {
    }

    /**
     * @param  Request  $request
     * @return \Illuminate\Http\JsonResponse
     *
     * @throws Exception
     */
    public function login(Request $request)
    {
        // received token auth data via PX User widgets
        $tokenData = $request->only([
            'access_token',
            'access_token_lifetime_minutes',
            'access_token_expiration_utc',
            'refresh_token',
            'refresh_token_lifetime_minutes',
            'refresh_token_expiration_utc',
        ]);

        $result = $this->pxUserLoginAction->execute($tokenData);

        return response()->json(['success' => $result]);
    }
}

If the value for $result is true you can now access authenticated user via Laravel's Auth facade.

Keep the session alive

PX access tokens are short-lived. On stateful web routes (admin panels, Nova) add the RefreshPxUserSession middleware. It refreshes the authenticated user's PX tokens once they expire within refresh_leeway seconds (PX_USER_REFRESH_LEEWAY, default 60).

When the user is left without a valid token, it logs them out and ends the session, then passes the request on as a guest, so the authentication middleware answers the guest the way it always does (redirect to the login page, 401 for JSON requests). The package adds the middleware to the middleware priority right before AuthenticatesRequests, so it runs before auth wherever it is listed; Laravel would otherwise move auth ahead of it in the web group:

use mindtwo\PxUserLaravel\Http\Middleware\RefreshPxUserSession;

Route::middleware(['web', RefreshPxUserSession::class, 'auth'])->group(function () {
    // ...
});

It uses the default guard; pass another one as a parameter (RefreshPxUserSession::class.':admin'). On a guard without a session to end, it aborts with 401 instead.

To add handling for a failed refresh, extend the middleware and override failedRefresh(). It runs after the session has ended and does nothing by default; throw from it to answer the request yourself instead of passing it on. Add the subclass to the middleware priority before AuthenticatesRequests too, since the package only prioritizes its own class:

use Illuminate\Http\Request;
use mindtwo\PxUserLaravel\Contracts\PxUser;
use mindtwo\PxUserLaravel\Http\Middleware\RefreshPxUserSession;

class RefreshAdminSession extends RefreshPxUserSession
{
    protected function failedRefresh(Request $request, PxUser $user, ?string $guard): void
    {
        logger()->info('PX session ended', ['user' => $user->getKey()]);
    }
}

Concurrent requests refresh only once, and the user is not logged in again, so the session id stays the same. Each refresh dispatches PxUserTokenRefreshEvent.

Keep CheckPxUserSession instead where a client holds its own PX refresh token (e.g. an SPA calling a token-based API): a server-side refresh rotates that token and leaves the client's copy unusable. CheckPxUserSession only checks the token and never refreshes it.

Search users with Scout

The package registers a Scout engine named px-user that searches users by name through the PX User API. Route your searchable model to it:

use Laravel\Scout\EngineManager;
use Laravel\Scout\Engines\Engine;

public function searchableUsing(): Engine
{
    return app(EngineManager::class)->engine('px-user');
}

The tenant and domain wheres set the PX context of the search:

User::search('jane')->where('tenant', $tenant)->where('domain', $domain)->get();
User::search('jane')->take(10)->get();
User::search('jane')->query(fn ($query) => $query->whereNotNull('email_verified_at'))->paginate(20);

The engine requests all matching users from PX once, then loads the matching local users by px_user_id in the order PX returns them. Users PX finds but your database lacks are skipped and not counted. get() honours take(), paginate() and simplePaginate() page over the local users. A PX 404 means no matches; other PX errors are rethrown. Searches need an authenticated PX user.

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email info@mindtwo.de instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.