Skip to content

Commit 6b815c6

Browse files
committed
Implement AuthCheck's requiredClaims
1 parent 803159c commit 6b815c6

File tree

1 file changed

+51
-27
lines changed

1 file changed

+51
-27
lines changed

reactfire/auth/index.tsx

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { auth, User } from 'firebase/app';
22
import * as React from 'react';
33
import { user } from 'rxfire/auth';
44
import { useObservable, useFirebaseApp, ReactFireOptions } from '..';
5+
import { from } from 'rxjs';
56

67
function getAuthFromContext(): auth.Auth {
78
const firebaseApp = useFirebaseApp();
@@ -42,13 +43,50 @@ export function useUser<T = unknown>(
4243
);
4344
}
4445

46+
export function useIdTokenResult(user: User, forceRefresh: boolean = false) {
47+
if (!user) {
48+
throw new Error('you must provide a user');
49+
}
50+
51+
const idToken$ = from(user.getIdTokenResult(forceRefresh));
52+
53+
return useObservable(idToken$, `${user.uid}-claims`);
54+
}
55+
4556
export interface AuthCheckProps {
4657
auth?: auth.Auth;
4758
fallback: React.ReactNode;
4859
children: React.ReactNode;
4960
requiredClaims?: Object;
5061
}
5162

63+
export interface ClaimsCheckProps {
64+
user: User;
65+
fallback: React.ReactNode;
66+
children: React.ReactNode;
67+
requiredClaims?: Object;
68+
}
69+
70+
export function ClaimsCheck({ user, fallback, children, requiredClaims }) {
71+
const { claims } = useIdTokenResult(user, false);
72+
const missingClaims = {};
73+
74+
Object.keys(requiredClaims).forEach(claim => {
75+
if (requiredClaims[claim] !== claims[claim]) {
76+
missingClaims[claim] = {
77+
expected: requiredClaims[claim],
78+
actual: claims[claim]
79+
};
80+
}
81+
});
82+
83+
if (Object.keys(missingClaims).length === 0) {
84+
return children;
85+
} else {
86+
return fallback;
87+
}
88+
}
89+
5290
export function AuthCheck({
5391
auth,
5492
fallback,
@@ -57,33 +95,19 @@ export function AuthCheck({
5795
}: AuthCheckProps): React.ReactNode {
5896
const user = useUser<User>(auth);
5997

60-
React.useLayoutEffect(() => {
61-
// TODO(jeff) see if this actually works
62-
if (requiredClaims) {
63-
throw user.getIdTokenResult().then(idTokenResult => {
64-
const { claims } = idTokenResult;
65-
const missingClaims = {};
66-
Object.keys(requiredClaims).forEach(claim => {
67-
if (requiredClaims[claim] !== claims[claim]) {
68-
missingClaims[claim] = {
69-
expected: requiredClaims[claim],
70-
actual: claims[claim]
71-
};
72-
}
73-
});
74-
75-
if (Object.keys(missingClaims).length > 0) {
76-
throw new Error(
77-
`Mismatched Claims: ${JSON.stringify(missingClaims)}`
78-
);
79-
}
80-
});
81-
}
82-
});
83-
84-
if (!user) {
85-
return fallback;
98+
if (user) {
99+
return requiredClaims ? (
100+
<ClaimsCheck
101+
user={user}
102+
fallback={fallback}
103+
requiredClaims={requiredClaims}
104+
>
105+
{children}
106+
</ClaimsCheck>
107+
) : (
108+
children
109+
);
86110
} else {
87-
return children;
111+
return fallback;
88112
}
89113
}

0 commit comments

Comments
 (0)