@aldel/superusers
v0.3.8
Published
User administration panel for Firebase Authentication users.
Readme
Superusers
User administration panel for Firebase Authentication users.
Installing this will give you (and/or designated "superadmins") a user administration panel that provides:
- Listing and lookup (by email or user ID) of all of your app's users registered through Firebase Authentication.
- Modification of user accounts including:
- Delete or disable accounts
- Update user info like name and avatar
- Add or remove "superadmin" status and other custom claims
- Reset passwords
There is an unreleased version that also includes more flexible listing and searching of users (it copies all users into a database), plus additional support for customization. It's not really in shape to be used right now, but if you're interested in more functionality and would be willing to support some development work, please get in touch.
The admin panel is a web app that is served directly from a Firebase Function. You will set up a path on your app site to proxy it through, so it appears as a part of your app that only certain users can access.
Installation
These instructions assume your Firebase project uses Firebase Authentication, because there's no point to this kit otherwise. No database is required.
Then you need to do some configuration steps for your app hosting (Firebase Hosting or other) and run a bootstrap process, described in the sections below.
Function Kit installation
Install the kit by running the following command in your project's root directory:
firebase functions:kits:install --package @aldel/superusersThe installation process will ask you several questions. For most of them, you can usually accept the default answers. This is especially true for the kit name and the instance name: there is no reason to rename the kit on installation, and no reason to install multiple instances.
Other questions will be the values of parameters, including:
- FUNCTION_DEFAULT_REGION: The datacenter region to run the functions in; probably us-central1 unless you're doing something fancy.
- BOOTSTRAP_USER_EMAIL: The email address of the person who will be the first superadmin user. This must be the email address of the account they use to log into your app.
- BOOTSTRAP_DATE: Usually today's date. The first superadmin user must run the
bootstrap process within 5 days of this date. If it takes longer than that to
get your app deployed to production, you'll have to update this in
function-kits/superusers/config-superusers/.env.${your-app-name}. - AUTH_DOMAIN: If you're running on Firebase Hosting and follow the other instructions below, you can leave this empty. Otherwise fill in the auth domain your app uses for Firebase Authentication.
- CLIENT_API_KEY: Can be empty if AUTH_DOMAIN can be empty, otherwise it's the client-side API key for your Firebase app.
- LOGIN_METHODS: List of login providers for your app (google, email, facebook, etc). These are used when a superadmin user loads the superadmin page and isn't already logged in. If they first log in elsewhere on the app, or if you use the redirect method instead (not yet supported), this list won't be relevant.
- SUPER_CLAIM_NAME: The name of the custom claim that will indicate a user is a superadmin. Defaults to "super". It's recommended to keep this short, since it is encoded into the user's JWT (auth token). It must not be on the list of registered JWT claims or the list of reserved Firebase claims (this is not enforced).
- SUPER_CLAIM_VALUE: The minimum value of the custom claim named in SUPER_CLAIM_NAME that qualifies a user as a superadmin. Must be a positive integer. Defaults to 10.
- CLAIMS: If not empty, this defines additional custom claims, not including "super". A JSON object with a property for each claim and its type. For example: {"tester":"boolean","title":"string"}. Valid types are "boolean", "string", and "number". It's recommended to keep claim names short, since they are encoded into the user's JWT (auth token). They must not be on the list of registered JWT claims or the list of reserved Firebase claims (this is not enforced).
In most cases you can just deploy the function kit once with firebase deploy
--only functions (with appropriate restrictions if you have other functions),
and not have your normal deploy process touch it. This will only require
modifications to your normal CI process if it deploys other functions, in which
case you'll need to make it not deploy this function kit.
Note that if you do want your CI process to deploy the function kit each time,
you'll not only make sure it deploys functions; you'll also have to have it run
npm ci in firebase-kits/superusers/source first. For some reason it gets
automatically configured to run npm run build, but that will fail if the
dependencies haven't been installed.
Hosting configuration
Map the function to a path within your web application's domain name using
proxying (or URL rewriting, which is basically the same thing). In Firebase
Hosting, this is easy. The following addition to the "hosting" section of your
firebase.json file will allow you to load the admin panel from the URL path
/super on your app:
"rewrites": [
{
"source": "/super",
"function": {
"functionId": "kit-superusers-app"
}
}
]For other hosting platforms, you can usually do something similar. You may need
to manually disable authentication for the kit-superusers-app Cloud Function at
https://console.cloud.google.com/run (click "function", click "Security",
uncheck "Use IAM...").
If you're using a different server (like Vite) for local development work, and want to be able to test the superadmin panel, you'll also need to do some setup for that server:
- Set up your dev environment to also run the Firebase Hosting and Functions emulators
- Set your dev server to proxy through the
/superpath (or whatever path you choose) to the Firebase Hosting emulator - Also set it to proxy through the special
/__/firebase/...endpoints (used by the superuseradmin client code to find the Firebase configuration paramaters)
An example configuration in Vite (in the "server" section of vite.config.ts):
proxy: {
'/super': {
target: 'http://localhost:5000/super',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/super/, ''),
},
'/__/': {
target: 'http://localhost:5000/',
changeOrigin: true,
},
},Alternative hosting setup
This is not recommended, but can work if the above hosting configuration doesn't work for you for some reason. Instead of mapping the Function endpoint into your app's own domain, you can have users load the superadmin panel directly from its Cloud Functions domain. This lets you skip the instructions above for "Hosting configuration", but you will have to:
- Configure Firebase Authentication to allow the Cloud Functions domain for its origin and redirects
- Explicitly set the AUTH_DOMAIN and CLIENT_API_KEY parameters on the Function Kits installation, and also LOGIN_METHODS if users will be logging in with any auth providers other than Google.
Bootstrap process
After deploying the installed function kit for the first time, you'll need to run the bootstrap process. This adds the "super" custom claim to the account named in BOOTSTRAP_USER_EMAIL during the install process above. Visit the superadmin panel at the URL you set up above. Log in with the BOOTSTRAP_USER_EMAIL account and click the button to run the bootstrap process. After this, the BOOTSTRAP_USER_EMAIL and BOOTSTRAP_DATE parameters become unnecessary.
Usage
Users are designated as superadmins by having a special custom claim named "super" (or whatever name you set in the SUPER_CLAIM_NAME parameter) set on their accounts in Firebase Authentication. The "super" claim has a numeric value, which by default must be at least 10 (or the value you set in SUPER_CLAIM_VALUE) to confer "superadmin" status on that user, which gives them access to the superadmin panel. You can use other levels to denote different levels of access, e.g., you might implement your own admin pages that only require a value of 5. Such access should, of course, be enforced both in the frontend and the backend (through database access rules and/or checks in any Cloud Functions or other endpoints you set up).
You can also define and set other custom claims using the CLAIMS parameter.
To access claims in front-end code, you can call User.getIdTokenResult(). If you're using @aldel/react-firebase-login, you can call useAuth() inside a React component.
A NOTE ABOUT CLAIMS AND SECURITY: Claims are part of the user's auth token, which is normally refreshed once per hour in a given browser session. In other words, if you change a user's claims, it can take up to an hour for that change to propagate to all clients. So if claims are used to grant access to data, or to enable app features, you may not be able to rescind access instantly. For backend security, you can fix this by fetching up-to-date user info from Firebase Authentication on any given API call, rather than just checking the token supplied by the client (this is what the Superusers admin panel does). I'm not aware of a way to do this in rules for Firestore, RTDB, or Firebase Storage.
