diff --git a/routes/web.php b/routes/web.php index 571f082ca7..96df5c790a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,6 +43,31 @@ use App\Models\ReportTemplate; use Illuminate\Support\Facades\Route; use Tabuna\Breadcrumbs\Trail; +/* + * Gate Passport's default personal-access-token routes + * behind the same self.api permission that protects Snipe-IT's own + * /account/api and /api/v1/account/personal-access-tokens surfaces. + * + * These three routes are auto-registered by PassportServiceProvider + * with only `web, auth:web` middleware, which meant any user with a + * valid session cookie could POST here and mint a long-lived bearer + * token even if an admin had revoked their self.api permission. + * + * Snipe-IT's routes/web.php loads before Passport's package service + * provider boots, so these registrations win route resolution over + * the Passport originals (FIFO). Requests are forwarded to the same + * PersonalAccessTokenController Passport would have used, so token + * shape and behavior are unchanged for users who ARE authorized. + */ +Route::middleware(['web', 'auth', 'can:self.api'])->prefix('oauth')->group(function () { + Route::get('personal-access-tokens', [\Laravel\Passport\Http\Controllers\PersonalAccessTokenController::class, 'forUser']) + ->name('passport.personal.tokens.index'); + Route::post('personal-access-tokens', [\Laravel\Passport\Http\Controllers\PersonalAccessTokenController::class, 'store']) + ->name('passport.personal.tokens.store'); + Route::delete('personal-access-tokens/{token_id}', [\Laravel\Passport\Http\Controllers\PersonalAccessTokenController::class, 'destroy']) + ->name('passport.personal.tokens.destroy'); +}); + Route::group(['middleware' => 'auth'], function () { /* * Companies