-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication and Roles
FlightMeet uses CodeIgniter Shield for session-based authentication. There are no API tokens or JWTs: the browser carries a session cookie, and the SPA carries a CSRF token in memory.
Configured in app/Config/AuthGroups.php:
| Group | Permissions | May ... |
|---|---|---|
admin |
admin.*, users.*
|
see the dashboard; create/edit/delete users; edit any meet or group; delete any chat message |
moderator |
users.view |
base permissions only (currently no dashboard access) |
user |
none | log in and use the app as a pilot |
Every registered account lands in group user (every account is a pilot by default). A pilot's public profile also reports the highest group as role (admin > moderator > user).
Authorization is enforced twice, but only the backend is authoritative:
-
Backend (authoritative)
-
ApiAuthFilter(apiauth) rejects sessionless requests to protected routes with401. -
AdminApiFilter(adminapi) additionally requiresadmin.accessfor everything under/api/admin/*; each admin action then checks its concrete permission (users.view/users.create/users.edit/users.delete). - Domain-level ownership rules live in the controllers: only the meet creator (or an admin) can edit a meet, only the group founder (or an admin) can edit a group, only the author (or an admin) can delete a chat message, group chat requires membership.
-
-
Frontend (UX only)
-
RequireAuthandRequireAdmin(infrontend/src/components/) hide routes and redirect to the login page.isAdmincomes fromuser.permissions['admin.access']in the/api/auth/mepayload.
-
CSRF protection is globally enabled in session mode, so every mutating request (POST/PUT/DELETE) must carry the X-CSRF-TOKEN header.
- On app start,
AuthProvidercallsGET /api/auth/me. The response contains{ authenticated, user, csrf: { header, token } }; the SPA stores the token in memory (frontend/src/lib/api.ts). -
POST /api/auth/loginwith{ login, password, remember }logs in. Shield regenerates the session, so the response includes a fresh CSRF token, which the API wrapper picks up automatically (it captures acsrffield from any response). - All subsequent non-GET requests send the token; the session cookie travels via
credentials: 'same-origin'. -
POST /api/auth/logoutends the session; the SPA re-fetches/meto obtain a CSRF token for the new anonymous session.
Login accepts email or username: Shield's validFields includes username, enabled in app/Config/Auth.php.
POST /api/auth/register with { username, email, password, vorname?, nachname? } creates a Shield account in group user, logs the session in immediately, and returns the same { user, csrf } shape as login (201). Validation mirrors the admin create-user rules: unique username and email, Shield password rules.
Profile fields (vorname, nachname, strasse, plz, ort) are columns on Shield's users table (migration AddProfileFieldsToUsers); the legacy personen table stays untouched. A subscription_tier column (pilot / club / school, default pilot) was added by AddSubscriptionTierToUsers; switching tiers via PUT /api/profile/subscription is free (there is no payment flow, matching the landing page pricing section).
| Login (email) | Username | Password | Group |
|---|---|---|---|
admin@team11.local |
admin |
Admin123! |
admin |
moderator@team11.local |
moderator |
Moderator123! |
moderator |
pilot1..pilot6@example.com |
pilot1 .. pilot6
|
password123 |
user |
PersonenSeeder additionally imports the 9999 legacy personen records as regular users: password password123, email <transliterated-username>@example.com (e.g. HerbertBürgers → herbertburgers@example.com).
The admin API refuses to let admins lock themselves out: your own account cannot be deleted, deactivated, or removed from the admin group.
FlightMeet
Code
Reference