Files
oauth/app/Http/Controllers/Api/PersonalAccessTokenController.php
Josep Piguillem c2b5291a74 Initial commit: OAuth IAM Laravel application
Laravel-based OAuth/IAM service with Passport, Vue 3 frontend, and
Docker Compose setup for local and production deployment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 01:02:41 +02:00

107 lines
3.6 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Validation\Rule;
use Laravel\Passport\Http\Middleware\CheckToken;
use Laravel\Passport\Passport;
use Laravel\Passport\Token;
use OpenApi\Attributes as OA;
class PersonalAccessTokenController extends Controller implements HasMiddleware
{
public static function middleware(): array
{
return [
new Middleware(CheckToken::using('account:read'), only: ['index']),
new Middleware(CheckToken::using('account:write'), only: ['store', 'destroy']),
];
}
#[OA\Get(
path: '/personal-access-tokens',
summary: 'Listar tus Personal Access Tokens',
security: [['oauth2' => ['account:read']]],
tags: ['Account'],
responses: [new OA\Response(response: 200, description: 'Listado de tokens')]
)]
public function index(Request $request)
{
return response()->json(
$this->requireUser($request)->tokens()
->where('revoked', false)
->whereHas('client', fn ($q) => $q->whereJsonContains('grant_types', 'personal_access'))
->orderByDesc('created_at')
->get(['id', 'name', 'scopes', 'created_at', 'expires_at'])
);
}
#[OA\Post(
path: '/personal-access-tokens',
summary: 'Crear un Personal Access Token (tipo API key)',
security: [['oauth2' => ['account:write']]],
tags: ['Account'],
requestBody: new OA\RequestBody(
required: true,
content: new OA\JsonContent(
required: ['name'],
properties: [
new OA\Property(property: 'name', type: 'string'),
new OA\Property(property: 'scopes', type: 'array', items: new OA\Items(type: 'string')),
]
)
),
responses: [new OA\Response(response: 201, description: 'Token creado (access_token solo se muestra esta vez)')]
)]
public function store(Request $request)
{
$user = $this->requireUser($request);
$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'scopes' => ['array'],
'scopes.*' => [Rule::in(Passport::scopeIds())],
]);
$result = $user->createToken($data['name'], $data['scopes'] ?? []);
return response()->json([
'access_token' => $result->accessToken,
'token' => $result->token,
], 201);
}
#[OA\Delete(
path: '/personal-access-tokens/{tokenId}',
summary: 'Revocar un Personal Access Token',
security: [['oauth2' => ['account:write']]],
tags: ['Account'],
parameters: [new OA\Parameter(name: 'tokenId', in: 'path', required: true, schema: new OA\Schema(type: 'string'))],
responses: [
new OA\Response(response: 204, description: 'Revocado'),
new OA\Response(response: 404, description: 'No existe o no es tuyo'),
]
)]
public function destroy(Request $request, string $tokenId)
{
/** @var Token|null $token */
$token = $this->requireUser($request)->tokens()->where('id', $tokenId)->first();
abort_unless($token, 404);
$token->revoke();
return response()->noContent();
}
private function requireUser(Request $request): User
{
return $request->user('api') ?? abort(422, __('messages.self_service_requires_user'));
}
}