Skip to content

Commit cd430ae

Browse files
docs: add architecture and security section to README and create admin authentication documentation
1 parent b2c6ec5 commit cd430ae

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ This helps you immediately verify:
132132

133133
---
134134

135+
## Architecture & security
136+
137+
Filament admins authenticate against a dedicated **`admins`** table and **`admin`** guard, separate from student **`users`** / **`web`** sessions. That avoids sharing one model/table for two different roles and keeps admin vs. student sessions isolated.
138+
139+
For motivation and step-by-step setup, see **[docs/admin-authentication.md](docs/admin-authentication.md)**.
140+
141+
---
142+
135143
## 📄 License
136144

137145
This project is open-sourced under the MIT license.

docs/admin-authentication.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Separate admin authentication (Filament)
2+
3+
## Why this exists
4+
5+
The app originally relied on a single `users` table for authentication. When wiring Filament, **installer-style flows and user-creation tooling** typically persist accounts using whatever Eloquent model your panel is configured to use. If that model is the same as your students (`User`), new “admins” land in `users` alongside normal accounts.
6+
7+
That coupling creates real problems:
8+
9+
- **Privilege overlap** — the same identity can satisfy both “logged-in student” and “Filament session” expectations unless you add strict, easy-to-miss guards everywhere.
10+
- **Harder reasoning** — authorization and policies must constantly branch on “is this row an admin or a student?”.
11+
- **Higher blast radius** — bugs in role checks or route middleware can expose admin capabilities to the wrong account class.
12+
13+
This project **splits authentication concerns**: students stay on the `web` guard and `users` table; Filament uses a dedicated **`admins` table** and **`admin` guard**.
14+
15+
---
16+
17+
## 1. Admin model and migration
18+
19+
Create the model and migration:
20+
21+
```bash
22+
php artisan make:model Admin -m
23+
```
24+
25+
Adjust the migration to match the columns you need (at minimum `name`, `email`, `password`).
26+
27+
---
28+
29+
## 2. Admin model
30+
31+
Implement Filament’s `FilamentUser` contract (and any optional MFA interfaces your panel uses). Use the same attribute style as `App\Models\User` for fillable / hidden fields:
32+
33+
```php
34+
<?php
35+
36+
namespace App\Models;
37+
38+
use Filament\Auth\MultiFactor\App\Concerns\InteractsWithAppAuthentication;
39+
use Filament\Auth\MultiFactor\App\Contracts\HasAppAuthentication;
40+
use Filament\Models\Contracts\FilamentUser;
41+
use Filament\Panel;
42+
use Illuminate\Database\Eloquent\Attributes\Fillable;
43+
use Illuminate\Database\Eloquent\Attributes\Hidden;
44+
use Illuminate\Foundation\Auth\User as Authenticatable;
45+
46+
#[Fillable([
47+
'name',
48+
'email',
49+
'password',
50+
])]
51+
#[Hidden([
52+
'password',
53+
])]
54+
class Admin extends Authenticatable implements FilamentUser, HasAppAuthentication
55+
{
56+
use InteractsWithAppAuthentication;
57+
58+
protected function casts(): array
59+
{
60+
return [
61+
'password' => 'hashed',
62+
];
63+
}
64+
65+
public function canAccessPanel(Panel $panel): bool
66+
{
67+
return true;
68+
}
69+
}
70+
```
71+
72+
Tighten `canAccessPanel()` in production (e.g. allow only specific emails, roles, or env-driven allow lists).
73+
74+
---
75+
76+
## 3. Dedicated guard and provider
77+
78+
In `config/auth.php`, register a session guard that points at an `admins` provider, and map that provider to `App\Models\Admin::class`:
79+
80+
```php
81+
'guards' => [
82+
'web' => [
83+
'driver' => 'session',
84+
'provider' => 'users',
85+
],
86+
87+
'admin' => [
88+
'driver' => 'session',
89+
'provider' => 'admins',
90+
],
91+
],
92+
93+
'providers' => [
94+
'users' => [
95+
'driver' => 'eloquent',
96+
'model' => env('AUTH_MODEL', App\Models\User::class),
97+
],
98+
99+
'admins' => [
100+
'driver' => 'eloquent',
101+
'model' => App\Models\Admin::class,
102+
],
103+
],
104+
```
105+
106+
Keep `defaults` aimed at **`web`** for the public site; only the Filament panel should use the **`admin`** guard.
107+
108+
---
109+
110+
## 4. Filament panel configuration
111+
112+
Bind the panel to the admin guard so Filament sessions never authenticate against `User`:
113+
114+
```php
115+
use Filament\Panel;
116+
117+
public function panel(Panel $panel): Panel
118+
{
119+
return $panel
120+
// ...
121+
->authGuard('admin');
122+
}
123+
```
124+
125+
In this repository, see `app/Providers/Filament/AdminPanelProvider.php`.
126+
127+
---
128+
129+
## Result
130+
131+
- Admins live in **`admins`**, students in **`users`**.
132+
- **Session isolation**`auth('web')` and `auth('admin')` are distinct; the student app and Filament no longer share the same credential store.
133+
- **Clearer security boundary** — you still need correct middleware and `canAccessPanel()` logic, but you are not storing two different actor types in one table by default.

0 commit comments

Comments
 (0)