# Quickstart: Authentication (SP-01)

**Feature**: Admin authentication with Bearer tokens
**Completed**: 2026-06-01

---

## Prerequisites

1. Laravel 11+ installed
2. MySQL 8+ database created
3. `.env` configured with database credentials
4. `APP_TIMEZONE=Asia/Damascus` set in `.env`

---

## Environment Setup

Add these to your `.env` file:

```env
ADMIN_NAME="System Administrator"
ADMIN_EMAIL="admin@tamkeen.local"
ADMIN_PASSWORD="your-secure-password-here"
```

---

## Installation Steps

### 1. Install Sanctum

```bash
php artisan install:api
```

This will:
- Run Sanctum's migration
- Update `config/cors.php` if needed

### 2. Create Admin Model

File: `app/Domains/Auth/Models/Admin.php`

```php
<?php

namespace App\Domains\Auth\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;

class Admin extends Authenticatable
{
    use HasApiTokens;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
    ];
}
```

### 3. Create Migration

```bash
php artisan make:migration create_admins_table
```

### 4. Create Admin Seeder

File: `database/seeders/AdminSeeder.php`

```php
<?php

namespace Database\Seeders;

use App\Domains\Auth\Models\Admin;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class AdminSeeder extends Seeder
{
    public function run(): void
    {
        $email = env('ADMIN_EMAIL');

        if (Admin::where('email', $email)->exists()) {
            return;
        }

        Admin::create([
            'name' => env('ADMIN_NAME'),
            'email' => $email,
            'password' => Hash::make(env('ADMIN_PASSWORD')),
        ]);
    }
}
```

Run seeder:
```bash
php artisan db:seed --class=AdminSeeder
```

### 5. Create Repository Interface

File: `app/Domains/Auth/Repositories/Contracts/AdminRepositoryInterface.php`

```php
<?php

namespace App\Domains\Auth\Repositories\Contracts;

use App\Domains\Auth\Models\Admin;

interface AdminRepositoryInterface
{
    public function findByEmail(string $email): ?Admin;
}
```

### 6. Create Eloquent Repository

File: `app/Domains/Auth/Repositories/Eloquent/EloquentAdminRepository.php`

```php
<?php

namespace App\Domains\Auth\Repositories\Eloquent;

use App\Domains\Auth\Models\Admin;
use App\Domains\Auth\Repositories\Contracts\AdminRepositoryInterface;
use Illuminate\Database\Eloquent\Model;

class EloquentAdminRepository implements AdminRepositoryInterface
{
    public function findByEmail(string $email): ?Model
    {
        return Admin::where('email', $email)->first();
    }
}
```

### 7. Create AuthService

File: `app/Domains/Auth/Services/AuthService.php`

```php
<?php

namespace App\Domains\Auth\Services;

use App\Domains\Auth\Models\Admin;
use App\Domains\Auth\Repositories\Contracts\AdminRepositoryInterface;
use Illuminate\Http\Request;

class AuthService
{
    public function __construct(
        private AdminRepositoryInterface $adminRepository
    ) {}

    public function login(Request $request): array
    {
        $admin = $this->adminRepository->findByEmail($request->email);

        if (!$admin || !Hash::check($request->password, $admin->password)) {
            abort(401, 'Invalid credentials');
        }

        $token = $admin->createToken('auth-token')->plainTextToken;

        return [
            'token' => $token,
            'token_type' => 'Bearer',
            'admin' => $admin,
        ];
    }

    public function logout(Admin $admin): void
    {
        $admin->currentAccessToken()->delete();
    }

    public function me(Admin $admin): Admin
    {
        return $admin;
    }
}
```

### 8. Create LoginRequest

File: `app/Domains/Auth/Http/Requests/LoginRequest.php`

```php
<?php

namespace App\Domains\Auth\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;

class LoginRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' => 'required|email',
            'password' => 'required|string',
        ];
    }

    protected function failedValidation(Validator $validator): void
    {
        throw new HttpResponseException(response()->json([
            'success' => false,
            'message' => 'Validation failed',
            'errors' => $validator->errors(),
        ], 422));
    }
}
```

### 9. Create AdminResource

File: `app/Domains/Auth/Http/Resources/AdminResource.php`

```php
<?php

namespace App\Domains\Auth\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class AdminResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at?->toISOString(),
        ];
    }
}
```

### 10. Create AuthController

File: `app/Domains/Auth/Http/Controllers/AuthController.php`

```php
<?php

namespace App\Domains\Auth\Http\Controllers;

use App\Domains\Auth\Http\Requests\LoginRequest;
use App\Domains\Auth\Http\Resources\AdminResource;
use App\Domains\Auth\Services\AuthService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class AuthController
{
    public function __construct(
        private AuthService $authService
    ) {}

    public function login(LoginRequest $request): JsonResponse
    {
        $result = $this->authService->login($request);

        return response()->json([
            'success' => true,
            'message' => 'Login successful',
            'data' => [
                'token' => $result['token'],
                'token_type' => $result['token_type'],
                'admin' => new AdminResource($result['admin']),
            ],
        ]);
    }

    public function logout(Request $request): JsonResponse
    {
        $this->authService->logout($request->user());

        return response()->json([
            'success' => true,
            'message' => 'Logged out successfully',
            'data' => [],
        ]);
    }

    public function me(Request $request): JsonResponse
    {
        return response()->json([
            'success' => true,
            'message' => 'Success',
            'data' => new AdminResource($request->user()),
        ]);
    }
}
```

### 11. Register Routes

In `routes/api.php`:

```php
use App\Domains\Auth\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;

Route::prefix('v1')->group(function () {
    Route::prefix('auth')->group(function () {
        Route::post('/login', [AuthController::class, 'login'])
            ->middleware('throttle:5,1');

        Route::delete('/logout', [AuthController::class, 'logout'])
            ->middleware('auth:sanctum');

        Route::get('/me', [AuthController::class, 'me'])
            ->middleware('auth:sanctum');
    });
});
```

### 12. Register Service Provider

In `bootstrap/app.php` or create a service provider:

```php
App\Domains\Auth\AuthServiceProvider::class,
```

---

## Verification

After implementation, verify:

```bash
# List routes
php artisan route:list

# Run tests
php artisan test --filter=AuthenticationTest

# Test manually
curl -X POST http://localhost/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@tamkeen.local","password":"your-password"}'
```

---

## Next Steps

After this quickstart:
- Proceed to `/speckit.tasks` to generate implementation tasks
- Write Feature Tests in `tests/Feature/Auth/AuthenticationTest.php`