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.isAuthenticated
Validators.isAnonymous
Validators.isVerified
Validators.every
Validators.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
profiles
collection in Firestore, which is possibly created byonCreate
via Firebase Functions. id
of each document underprofiles
is the same asuser.uid
(user's id in Firebase Auth).- Each document under
profiles
collection has a field namedroles
, which is an array of string (string[]
). - For security reasons, of course,
roles
field 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. |
✅ | - |