This document describes the authentication and security measures implemented for the admin panel.
- Sessions now expire after 1 hour of inactivity
- Session data is stored as a JSON object with an
expiresAttimestamp - On page load, expired sessions are automatically cleared
- Invalid session data is handled gracefully with error catching
- Username and password are validated together to prevent timing attacks
- Password comparison runs even if username is incorrect
- Single "Invalid credentials" error message for both username and password failures
- Prevents attackers from determining valid usernames through response timing
- Added proper TypeScript interfaces for Branch, Semester, and Subject types
- Replaced
any[]types with strongly typed arrays - Improves code maintainability and catches type errors at compile time
- Credit hours validation improved to handle edge cases:
- Empty strings are properly handled as
undefined - Non-numeric values are rejected
- Negative numbers are rejected
- Empty strings are properly handled as
- Form reload logic fixed to use correct ID variables
- Added null checks for all Supabase insert operations
- Throws descriptive errors if insert operations succeed but return no data
- Prevents undefined access errors
RLS policies have been updated to properly authenticate users using Supabase Auth:
Migration File: supabase/migrations/20251104152900_fix_rls_policies_for_admin_operations.sql
- All tables (branches, semesters, subjects, resources) allow SELECT operations for everyone
- This enables the view-only site to function without authentication
- INSERT, UPDATE, and DELETE operations require authentication
- Policies check
auth.uid() IS NOT NULLto verify the user is authenticated with Supabase - Unauthenticated requests to write operations will be rejected at the database level
- Client authenticates with Supabase Auth (needs to be set up)
- Supabase generates a JWT token containing the user ID
- The JWT is sent with every database request
- RLS policies check
auth.uid()which extracts the user ID from the JWT - If no valid JWT is present,
auth.uid()returns NULL and write operations fail
The following environment variables must be set:
VITE_ADMIN_USERNAME: The admin usernameVITE_ADMIN_PASSWORD_HASH: BCrypt hash of the admin password
To fully enable authentication at the database level:
-
Apply the migration:
supabase db push
-
Set up Supabase Auth (if not already done):
- Enable Email/Password authentication in Supabase dashboard
- Create an admin user account
- Update the client code to use Supabase Auth instead of local authentication
-
Alternative: Service Role Key: If you prefer to keep local authentication:
- Use Supabase service role key for admin operations
- Update
supabaseAcademicApi.tsto use service role client - Note: Service role bypasses RLS, so ensure proper client-side checks
-
Local Authentication Only: The current implementation uses local username/password authentication with bcrypt, which doesn't integrate with Supabase Auth.
-
No Server-Side Session Validation: Sessions are stored in localStorage without server-side validation.
-
Recommended Improvements:
- Integrate with Supabase Auth for full end-to-end authentication
- Implement refresh tokens for longer sessions
- Add CSRF protection for write operations
- Consider implementing role-based access control (RBAC) for different admin levels
You can test RLS policies using the Supabase SQL editor:
-- Test as unauthenticated user (should fail)
INSERT INTO branches (name, description) VALUES ('Test Branch', 'Test Description');
-- Test as authenticated user (should succeed)
SELECT auth.uid(); -- Check if you're authenticated
INSERT INTO branches (name, description) VALUES ('Test Branch', 'Test Description');- Never commit credentials: Use environment variables for all sensitive data
- Use HTTPS: Always serve the application over HTTPS in production
- Regular security audits: Review and update dependencies regularly
- Monitor failed login attempts: Consider implementing rate limiting
- Secure environment variables: Use Vercel/hosting platform's secret management