AuthorizationZone Component
You can use AuthorizationZone component to conditionally render the provided component. You can provide your own custom authorization logic but, by default, the logic is to check whether the user is authenticated (signed-in) or not.
So, to render a component only when a user is signed-in, the simplest usage would be:
<AuthorizationZone
auth={auth}
onSuccess={(user) => (
<p>User with {user?.email} has signed in.</p>
{/** or a sign out button */}
)}
/>
Tip
AuthorizationZone component listens to your authentication state automatically and reflects the changes.
By default, an empty component will be rendered when authorization fails. You can change this behavior via providing a function returning a component on onFailure property of AuthorizationZone. It'd look like this:
<AuthorizationZone
auth={auth}
onSuccess={(user) => (
<p>User with {user?.email} has signed in.</p>
{/** or a sign out button */}
)}
onFailure{() => (
<p>User has not logged in.</p>
{/** or a sign in button */}
)}
/>
As mentioned earlier, AuthorizationZone accepts custom logic. Some of frequent logic is already covered by firereact. For example, instead of rendering when the user is authenticated, you can render when they are anonymous. See this example:
<AuthorizationZone
auth={auth}
validator={Validators.isAnonymous()}
onSuccess={() => (
<p>User has not logged in.</p>
{/** or a sign in button */}
)}
/>
Check out Validators to see available validators by firereact.
You can also provide your own logic in validator property. See the example below:
<AuthorizationZone
auth={auth}
validator={async (user) => {
// you can do anything here
// e.g. check related firestore doc to validate the user has the sufficient role to see this component
// return a boolean
}}
onSuccess={() => (
<p>User can authorized this component.</p>
)}
/>
Info
validator might be async function or not depending on your need.
Input Parameters
Input parameters for FirestoreDocument component is as follows:
| Name | Type | Description | Required | Default Value |
|---|---|---|---|---|
auth |
firebase/auth/Auth |
Auth service instance. | ✅ | - |
onSuccess |
(user: User | null) => ReactNode |
The component to render when validator returns true. |
✅ | - |
onFailure |
(user: User | null) => ReactNode |
The component to render when validator returns false. |
❌ | An empty component. |
validator |
(user: User | null) => Promise<boolean> | boolean |
The function to decide whether to render the component or not. | ❌ | Validators.isAuthenticated() |
Validators
AuthorizationZone component has validator property, which requires a type that is (user: User | null) => Promise<boolean> | boolean. This means it's a function that automatically is provided with an instance of User and might or might not be an async function (can return either Promise<boolean> or boolean).
firereact already provides premade useful validators. Here is an exhaustive list of them:
Validators.isAuthenticatedValidators.isAnonymousValidators.isVerifiedValidators.everyValidators.some
You can also write your own custom validator.
Custom Validator
Let's assume these conditions:
- You'd like to check a user is admin to render a
<button>Delete Product</button> - Each user has their own document under
profilescollection in Firestore, which is possibly created byonCreatevia Firebase Functions. idof each document underprofilesis the same asuser.uid(user's id in Firebase Auth).- Each document under
profilescollection has a field namedroles, which is an array of string (string[]). - For security reasons, of course,
rolesfield is protected as read-only via Firestore security rules.
A minimal document under profiles would look as such:
{
// other fields
"roles": [], // read-only, maybe ["admin"]
}
You can render this delete button with a validator similar to this:
<AuthorizationZone
auth={auth}
validator={async (user) => {
const docRef = doc(firestore, "profiles", user?.uid);
const snapshot = await getDoc(docRef);
const data = snapshot.data();
const roles = data.roles;
return data.roles.includes("admin");
}}
onSuccess={() => (
<button>Delete Product</button>
)}
/>
Warning
Of course, this is a throw-away and quite simple example. Each render will cost one Firestore read. Optimize yourself.
isAuthenticated Validator
This is the default validator used by AuthorizationZone. It will render the component only if the user is authenticated. Since it solely uses Firebase Auth, it does not cost anything.
In Firebase, there are two types of anonymity, check "On Anonymity" section in useSignOut hook to get a grasp of it. This validator returns false when user is really anonymous (meaning null) or when user is Firebase-handled anonymous.
If, for a reason, you'd like to consider Firebase-handled anonymous users as authenticated, then you can pass true to includeFirebaseAnon, the example is:
<AuthorizationZone
auth={auth}
validator={Validators.isAuthenticated(true)}
onSuccess={() => (
<p>Authenticated or Firebase anon maybe</p>
)}
/>
Input Parameters
Only takes positional parameters.
| Name | Type | Description | Required | Default Value |
|---|---|---|---|---|
includeFirebaseAnon |
boolean |
Consider Firebase-handled anonymous as authenticated as well | ❌ | false |
isAnonymous Validator
This validator will render the component only if the user is anonymous. Since it solely uses Firebase Auth, it does not cost anything. A simple example would be:
<AuthorizationZone
auth={auth}
validator={Validators.isAnonymous()}
onSuccess={() => (
<p>only anons can see this</p>
)}
/>
In Firebase, there are two types of anonymity, check "On Anonymity" section in useSignOut hook to get a grasp of it. This validator returns true when user is really anonymous (meaning null) or when user is Firebase-handled anonymous.
If, for a reason, you'd like to consider Firebase-handled anonymous users as authenticated rather than anonymous, then you can pass true to excludeFirebaseAnon, the example is:
<AuthorizationZone
auth={auth}
validator={Validators.isAnonymous(true)}
onSuccess={() => (
<p>definitely an anon, not even Firebase-handled</p>
)}
/>
Input Parameters
Only takes positional parameters.
| Name | Type | Description | Required | Default Value |
|---|---|---|---|---|
excludeFirebaseAnon |
boolean |
Consider Firebase-handled anonymous as authenticated rather than anonymous | ❌ | false |
isVerified Validator
This validator will render the component only if the user email is verified. Since it solely uses Firebase Auth, it does not cost anything. A simple example would be:
<AuthorizationZone
auth={auth}
validator={Validators.isVerified()}
onSuccess={() => (
<p>This user is verified.</p>
)}
/>
Warning
If the user is a real anonymous (null), then isVerified validator will consider it as non-verified (false).
every Validator
This validator is a kind of validator composer and will render the component only if all the subvalidators return true.
This example will render onSuccess:
<AuthorizationZone
auth={auth}
validator={Validators.every([
// your own validators or premade validators
// can be async as well
() => true,
() => true,
])}
onSuccess={() => (
<p>successful</p>
)}
/>
Input Parameters
Only takes positional parameters.
| Name | Type | Description | Required | Default Value |
|---|---|---|---|---|
validators |
An array of (user: User | null) => Promise<boolean> | boolean |
Returns true if all validations pass. |
✅ | - |
some Validator
This validator is a kind of validator composer and will render the component if any of subvalidators return true.
This example will render onSuccess:
<AuthorizationZone
auth={auth}
validator={Validators.some([
// your own validators or premade validators
// can be async as well
() => false,
() => true,
])}
onSuccess={() => (
<p>successful</p>
)}
/>
Input Parameters
Only takes positional parameters.
| Name | Type | Description | Required | Default Value |
|---|---|---|---|---|
validators |
An array of (user: User | null) => Promise<boolean> | boolean |
Returns true if any of validations pass. |
✅ | - |