PHPackages                             clarkewing/handoff - 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. clarkewing/handoff

ActiveLibrary

clarkewing/handoff
==================

Lightweight Laravel package for secure cross-application user handoff via signed URLs and route mapping.

v0.1.3(9mo ago)0158MITPHPPHP ^8.0CI passing

Since Aug 2Pushed 9mo agoCompare

[ Source](https://github.com/clarkewing/handoff)[ Packagist](https://packagist.org/packages/clarkewing/handoff)[ Docs](https://github.com/clarkewing/handoff)[ RSS](/packages/clarkewing-handoff/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (10)Versions (5)Used By (0)

Handoff
=======

[](#handoff)

[![Code Quality](https://github.com/clarkewing/handoff/actions/workflows/code-quality.yml/badge.svg)](https://github.com/clarkewing/handoff/actions/workflows/code-quality.yml)[![Tests](https://github.com/clarkewing/handoff/actions/workflows/tests.yaml/badge.svg)](https://github.com/clarkewing/handoff/actions/workflows/tests.yaml)

**Handoff** is a Laravel package that enables seamless, secure cross-application authentication via temporary signed URLs. It’s ideal for projects maintaining both a legacy and a modern Laravel app, and ensures users can be automatically logged in across both systems without friction.

---

🚀 Features
----------

[](#-features)

- 🔐 Secure authentication handoff via signed URLs
- 🔁 Bi-directional route mapping between apps
- ⏱️ Expirable links with configurable TTL
- ⚙️ Fully customizable user model &amp; identifier
- 🌍 Shared, environment-agnostic logic — install on both apps

---

🧩 Requirements
--------------

[](#-requirements)

To use Handoff, the package must be installed in both Laravel applications you wish to link and their User models must be kept in sync.

Handoff is compatible with applications using Laravel 8 and above, and requires PHP 8.0 or above.

---

📦 Installation
--------------

[](#-installation)

**Handoff** must be installed in both your origin app and the target app.

```
composer require clarkewing/handoff
```

In your origin app’s `.env` file, register the target host:

```
HANDOFF_TARGET_HOST="https://new.example.org"
```

---

⚙️ Configuration
----------------

[](#️-configuration)

Optionally, you can publish the config file using the following command.

```
php artisan vendor:publish --tag=handoff-config
```

**Note:** This is required if you want to use route mapping (see the Usage section).

These are the contents of the published config file:

```
/*
|--------------------------------------------------------------------------
| Authentication
|--------------------------------------------------------------------------
|
| These settings control how authentication is handled when transferring
| a user session from one site to another using a signed URL.
|
*/

'auth' => [
    // The Authenticable model used in your application.
    'model' => App\Models\User::class, /** @phpstan-ignore class.notFound */

    // Lifetime (in seconds) of the signed URL used for authentication.
    // This helps ensure links expire quickly and remain secure.
    'ttl' => env('HANDOFF_TTL', 300),
],

/*
|--------------------------------------------------------------------------
| Target Host
|--------------------------------------------------------------------------
|
| The base URL of the other application (legacy or new) that you want to
| redirect users to. This will be prepended to any path in the route map.
|
*/

'target_host' => env('HANDOFF_TARGET_HOST', ''),

/*
|--------------------------------------------------------------------------
| Route Mapping
|--------------------------------------------------------------------------
|
| This defines which local named routes should redirect to which path on
| the other site. Keys should match local route names, and values should
| be relative paths on the remote app. You may repeat values if multiple
| routes on this side map to a single target path.
|
*/

'routes' => [
    // 'dashboard' => '/home',
    // 'settings.profile' => '/account/info',
],
```

---

🔧 Usage
-------

[](#-usage)

### Target app

[](#target-app)

In the target app, **Handoff** automatically registers a `/handoff` endpoint via its service provider. This endpoint validates the signed URL, logs the user in, and redirects them to the intended destination.

### Origin app

[](#origin-app)

From the origin app, **Handoff** provides three ways of *handing off* a request to the target application:

1. [Manually generating a signed Handoff URL](#manually-generating-a-signed-handoff-url)
2. [Automatically redirecting users via the `handoff` middleware and providing a target path](#automatically-redirecting-users-via-the-handoff-middleware-and-providing-a-target-path)
3. [Automatically redirecting users via the `handoff` middleware while using route mapping](#automatically-redirecting-users-via-the-handoff-middleware-while-using-route-mapping)

---

#### Manually generating a signed Handoff URL

[](#manually-generating-a-signed-handoff-url)

**Handoff** supplies a `GenerateHandoffUrl` action class which can be used to manually create a Handoff URL.

```
use App\Models\User;
use ClarkeWing\Handoff\Actions\GenerateHandoffUrl;

$url = resolve(GenerateHandoffUrl::class)->generate(
    user: $user,                   // required – the user to authenticate
    toPath: '/account/info',       // optional if using fromRoute
    fromRoute: 'settings.profile', // optional if using toPath
    ttl: 300                       // optional – expiration in seconds
);
```

**Note:** Either `toPath` or `fromRoute` must be provided, not both.

#### Automatically redirecting users via the `handoff` middleware and providing a target path

[](#automatically-redirecting-users-via-the-handoff-middleware-and-providing-a-target-path)

To simplify redirecting users, **Handoff** registers its `handoff` middleware. It accepts a target path to which users will be redirected.

```
Route::get('/settings/profile', fn () => view('settings.profile'))
   ->middleware('handoff:/account/info')
```

#### Automatically redirecting users via the `handoff` middleware while using route mapping

[](#automatically-redirecting-users-via-the-handoff-middleware-while-using-route-mapping)

For cases where you’d prefer to centrally manage your handoff origin routes and target paths, **Handoff** provides the possibility to use route to path mapping.

##### 1. Apply the `handoff` middleware to origin routes

[](#1-apply-the-handoff-middleware-to-origin-routes)

You have a few options for this. See the Laravel documentation on [Registering Middleware](https://laravel.com/docs/12.x/middleware#registering-middleware).

##### 2. Setup route mapping in the config

[](#2-setup-route-mapping-in-the-config)

After publishing **Handoff**’s config file, you can set up route mapping:

```
// config/handoff.php

'routes' => [
    'dashboard' => '/home',
    'settings.profile' => '/account/info',
],
```

---

🔐 Security
----------

[](#-security)

This package uses Laravel’s `temporarySignedRoute()` mechanism. URLs are cryptographically signed and valid only for a limited time. You can customize the TTL or add rate limiting via the included service provider.

---

🤝 Contributing
--------------

[](#-contributing)

Issues and PRs welcome! Please see our [Contribution guidelines](CONTRIBUTING.md) if contributing tests or features.

---

📜 License
---------

[](#-license)

Released under the MIT License.

---

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance56

Moderate activity, may be stable

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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 ~0 days

Total

4

Last Release

289d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/98299c7124daab9f3dcf1f15888af172ad4f713765fc45365a872302948b2398?d=identicon)[clarkewing](/maintainers/clarkewing)

---

Top Contributors

[![clarkewing](https://avatars.githubusercontent.com/u/7689302?v=4)](https://github.com/clarkewing "clarkewing (29 commits)")

---

Tags

phplaravelclarkewinghandoff

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/clarkewing-handoff/health.svg)

```
[![Health](https://phpackages.com/badges/clarkewing-handoff/health.svg)](https://phpackages.com/packages/clarkewing-handoff)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[laravel/wayfinder

Generate TypeScript representations of your Laravel actions and routes.

1.7k4.1M69](/packages/laravel-wayfinder)[laravel-doctrine/orm

An integration library for Laravel and Doctrine ORM

8425.3M87](/packages/laravel-doctrine-orm)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.

264778.4k3](/packages/laravel-cashier-paddle)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)

PHPackages © 2026

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