Admin Privileges
Admins are an important concept in any application; they allow you as the app owner to have fine-grained control over what data you may access and from where, plus the choice of actions you or a member of your team is permitted to make to the data, and how.
This concept also extends to other roles; like managers, developers, paid-members, and so on. This is known as Role-Based Access Control (RBAC) and it's something I've implemented in the FlutterFlow Starter Kit.
It's necessary to run the starter scripts for Supabase and follow the guides in the Supabase setup section to enable this RBAC. Another thing that needs to be done is to create the first admin user, which needs to be done manually. From then on, you may use the admin dashboard described in the following section to make and revoke admin rights for others.
Actions to take
A script is necessary to create the first admin user; this unfortunately cannot be done from the Firebase console. In the ff-starterkit-python-api code repository included with the Starter Kit, navigate to the create_admin.py file inside of the scripts/ directory.
If you don't have a local environment where you can run python code, just follow the guide in the Python API setup section to get one set up. In this case, instead of using the "FastAPI" option in the dropdown of the debug pane, use the "Current File" option, ensuring that the create_admin.py file is open in the editor.
The script will prompt you for the Firebase Auth UID of the user to whom you want to give admin privileges. You can get this UID from the Firebase console. A user account must be created in the app (or Firebase console) before it can be privileged.
The technical stuff
Admin user privileges must be taken seriously; you don't want random users finding their way into this position because your data could potentially be compromised if a malicious actor were to gain this privilege.
For this reason, the Starter Kit embeds these privileges into the Authorization token itself, rather than using flimsy controls like is_admin database flags.
Firebase Auth has the capability of defining custom claims, snippets of information that cannot be tampered with. Whenever a new auth JWT token is issued, it carries these custom claims. By using the create_admin.py script defined above, you can create a new admin user and ensure that all of their subsequent tokens will contain this [object Object] custom claim.
The Starter Kit's python backend API knows how to validate these claims automagically. It also mints the claim into the Supabase tokens. Then, you can set up RLS policies in Supabase that match the role embedded in the token with the "admin" role name. The below details are just an FYI, these SQL commands are all included in the blob of SQL you'll run while following the Supabase setup section.
The initializer from the Supabase setup section will add the admin role:
-- Create an admin role
CREATE ROLE admin;
GRANT USAGE ON SCHEMA public TO admin;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO admin;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO admin;
GRANT admin TO authenticated;
and thereafter when creating an RLS policy you can target the "admin" role
so that admins can also behave as normal users. Then you do the check:
-- Create a policy to allow admins to manage app_compliance
CREATE POLICY "Admins can manage app_compliance"
ON "public"."app_compliance"
FOR ALL
TO admin
USING (
(auth.jwt() ->> 'role'::text) = 'admin'::text
)
WITH CHECK (
(auth.jwt() ->> 'role'::text) = 'admin'::text
);
In the example above, there is a table called app_compliance which houses the privacy policy HTML. This RLS policy ensures that only
those with the role: admin embedded inside their auth token can edit the
privacy policy. In this case, you would also create a different RLS policy
for all users, but restriced to only the SELECT action (meaning anyone can
view the privacy policy).