From 5e0171cf11cc02e3690ae5563f8a8efdaa3a9573 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 16 Sep 2026 00:41:10 -0600 Subject: [PATCH] Add revoke token endpoint --- .../Controllers/Api/ApiV1Dot1Controller.php | 45 +++++++++++++++++++ routes/api.php | 1 + 2 files changed, 46 insertions(+) diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index 178f6f075..fe294f642 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -55,6 +55,7 @@ use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use Illuminate\Validation\Rule; +use Laravel\Passport\RefreshToken; use League\Fractal; use League\Fractal\Serializer\ArraySerializer; @@ -512,6 +513,50 @@ class ApiV1Dot1Controller extends Controller return $this->json($res); } + /** + * POST /api/v1.1/accounts/apps-and-applications/{id}/revoke + * + * @return array + */ + public function accountAppRevoke(Request $request, $id) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $token = $user->tokens()->whereKey($id)->first(); + abort_if(! $token, 404); + abort_if( + $token->id === $request->user()->token()->id, + 422, + 'You cannot revoke the current session. Sign out instead.' + ); + + if (! $token->revoked) { + $token->revoke(); + RefreshToken::whereAccessTokenId($token->id)->update(['revoked' => true]); + + $log = new AccountLog; + $log->user_id = $user->id; + $log->item_id = $user->id; + $log->item_type = User::class; + $log->action = 'account.apps.revoke'; + $log->message = 'Revoked app access: '.$token->client->name; + $log->link = null; + $log->ip_address = $request->ip(); + $log->user_agent = $request->userAgent(); + $log->save(); + } + + return $this->accountApps($request); + } + public function inAppRegistrationPreFlightCheck(Request $request): array { return [ diff --git a/routes/api.php b/routes/api.php index 849fb11c7..a9602b7b5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -247,6 +247,7 @@ Route::prefix('api')->group(function () use ($middleware) { Route::get('two-factor', [ApiV1Dot1Controller::class, 'accountTwoFactor'])->middleware($middleware); Route::get('emails-from-pixelfed', [ApiV1Dot1Controller::class, 'accountEmailsFromPixelfed'])->middleware($middleware); Route::get('apps-and-applications', [ApiV1Dot1Controller::class, 'accountApps'])->middleware($middleware); + Route::post('apps-and-applications/{id}/revoke', [ApiV1Dot1Controller::class, 'accountAppRevoke'])->middleware($middleware); Route::get('mutuals/{id}', [ApiV1Dot1Controller::class, 'getMutualAccounts'])->middleware($middleware); Route::get('username/{username}', [ApiV1Dot1Controller::class, 'accountUsernameToId'])->middleware($middleware); });