This is a simple library with cli tools to provides a way to manage feature flags in React UI applications that use Auth0 for authentication.
The assumption is that feature flags are stored in Auth0 and are available in the user object which can be populated using the user'suser_metadata
field.
A feature flag for a user is set if the property is present.
{
"user_metadata": {
"flags": {
"new_feature": true,
"newest_feature": true
}
}
}
Feature Flags are conceptually boolean values. If present or truthy, the flag is set, otherwise it is not.
Since this user
object is created from the idToken
claims, we must specify a namespace for this flags
custom claim.
In Auth0 this can be configured in a post login rule:
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://platformatic.dev'
// Feature Flags from user_metadata
const { flags } = event.user.user_metadata || {}
api.idToken.setCustomClaim(`${namespace}/flags`, flags)
}
Even if Feature Flags should be temporary (all they should eventually disappear) it can be useful to set a default value for a flag. This can be done in Auth0 using a pre-user-registration
action.
For more details see Auth0 docs
exports.onExecutePreUserRegistration = async (event, api) => {
api.user.setUserMetadata("flag", "default_flag_new_users");
};
In a React app, the user
object is made available through the useAuth0
hook and can be used to get the feature flags.
However, it's not necessary to manage feature flags directly, they can be managed by useFlags
hook or <EnableFeature/>
components from @platformatic/semaforo-ui
Install it with: npm install @platformatic/semaforo-ui
Assuming that the newfeature
flag can be set for some users, we can define different routes for them:
const flags = useFlags();
const getRoutes = flags => {
if (flags.newfeature) {
return <Routes>yy
<Route
path='/'
element={<App />}
/>
<Route
path='/applications/:id'
element={<ProtectedRoute component={Detail} />}
/>
</Routes>
}
return <Routes>
// default routes
</Routes>
}
Or we can change content dynamically:
const flags = useFlags();
return <>
{flags.newfeature && <p>You are a basic user!</p>}
</>
This can be used to return a component conditionally depending on a feature flag. If the flag is not set, it returns the default.
<Route
path='/applications/:id'
element={
<EnableFeature
feature="newfeature"
component={<ProtectedRoute component={BasicDetail} />}
default={<ProtectedRoute component={Detail} />}
/>
}
/>
This library assumes that flags are in user['https://platformatic.dev/flags']
so the namespace
is https://platformatic.dev
. If you want to change this, you must pass the namespace
param to both useFlags
and <EnableFeature />
, e.g.:
const flags = useFlags("https://mynamespace")
return <>
{flags.newfeature && <p>You are a basic user!</p>}
</>
<Route
path='/applications/:id'
element={
<EnableFeature
feature="newfeature"
component={<ProtectedRoute component={BasicDetail} />}
default={<ProtectedRoute component={Detail} />}
namespace="https://mynamespace"
/>
}
/>
The namespace must be the same configured in the Auth0 rule.
To set feature flags for a user, you can use the semaforo
cli tool. It can be installed globally with npm install -g @platformatic/semaforo-cli
or cloning this repo and linking it globally from packages/cli
using pnpm link --global
When installed, you need a env
file set in the current directory with the Auth0 configuration. See cli README for the setup and all the available commands
This project uses pnpm as package manager. To install it, run npm install -g pnpm
and then install dependencies with pnpm install