@@ -65,6 +65,9 @@ export function useConvexAuth(): {
6565 * should be a React hook that returns the provider's authentication state
6666 * and a function to fetch a JWT access token.
6767 *
68+ * If the `useAuth` prop function updates causing a rerender then auth state
69+ * wil transition to loading and the `fetchAccessToken()` function called again.
70+ *
6871 * See [Custom Auth Integration](https://docs.convex.dev/auth/advanced/custom-auth) for more information.
6972 *
7073 * @public
@@ -84,20 +87,25 @@ export function ConvexProviderWithAuth({
8487 } ) => Promise < string | null > ;
8588 } ;
8689} ) {
87- const { isLoading, isAuthenticated, fetchAccessToken } = useAuth ( ) ;
90+ const {
91+ isLoading : tokenLoading ,
92+ isAuthenticated,
93+ fetchAccessToken,
94+ } = useAuth ( ) ;
8895 const [ isConvexAuthenticated , setIsConvexAuthenticated ] = useState <
8996 boolean | null
9097 > ( null ) ;
9198
92- // If the useAuth went back to the loading state (which is unusual but possible)
99+ // If the useAuth went back to the tokenLoading state (which is unusual but possible)
93100 // reset the Convex auth state to null so that we can correctly
94101 // transition the state from "loading" to "authenticated"
95102 // without going through "unauthenticated".
96- if ( isLoading && isConvexAuthenticated !== null ) {
103+ if ( tokenLoading && isConvexAuthenticated !== null ) {
97104 setIsConvexAuthenticated ( null ) ;
98105 }
99106
100- if ( ! isLoading && ! isAuthenticated && isConvexAuthenticated !== false ) {
107+ // If the useAuth goes to not authenticated then isConvexAuthenticated should reflect that.
108+ if ( ! tokenLoading && ! isAuthenticated && isConvexAuthenticated !== false ) {
101109 setIsConvexAuthenticated ( false ) ;
102110 }
103111
@@ -111,16 +119,17 @@ export function ConvexProviderWithAuth({
111119 < ConvexAuthStateFirstEffect
112120 isAuthenticated = { isAuthenticated }
113121 fetchAccessToken = { fetchAccessToken }
114- isLoading = { isLoading }
122+ isLoading = { tokenLoading }
115123 client = { client }
116124 setIsConvexAuthenticated = { setIsConvexAuthenticated }
117125 />
118126 < ConvexProvider client = { client as any } > { children } </ ConvexProvider >
119127 < ConvexAuthStateLastEffect
120128 isAuthenticated = { isAuthenticated }
121129 fetchAccessToken = { fetchAccessToken }
122- isLoading = { isLoading }
130+ isLoading = { tokenLoading }
123131 client = { client }
132+ setIsConvexAuthenticated = { setIsConvexAuthenticated }
124133 />
125134 </ ConvexAuthContext . Provider >
126135 ) ;
@@ -148,16 +157,16 @@ function ConvexAuthStateFirstEffect({
148157 useEffect ( ( ) => {
149158 let isThisEffectRelevant = true ;
150159 if ( isAuthenticated ) {
151- client . setAuth ( fetchAccessToken , ( isAuthenticated ) => {
160+ client . setAuth ( fetchAccessToken , ( backendReportsIsAuthenticated ) => {
152161 if ( isThisEffectRelevant ) {
153- setIsConvexAuthenticated ( isAuthenticated ) ;
162+ setIsConvexAuthenticated ( ( ) => backendReportsIsAuthenticated ) ;
154163 }
155164 } ) ;
156165 return ( ) => {
157166 isThisEffectRelevant = false ;
158167
159- // If we haven't finished fetching the token by now
160- // we shouldn't transition to a loaded state
168+ // If unmounting or something changed before we finished fetching the token
169+ // we shouldn't transition to a loaded state.
161170 setIsConvexAuthenticated ( ( isConvexAuthenticated ) =>
162171 isConvexAuthenticated ? false : null ,
163172 ) ;
@@ -181,20 +190,38 @@ function ConvexAuthStateLastEffect({
181190 fetchAccessToken,
182191 isLoading,
183192 client,
193+ setIsConvexAuthenticated,
184194} : {
185195 isAuthenticated : boolean ;
186196 fetchAccessToken : ( args : {
187197 forceRefreshToken : boolean ;
188198 } ) => Promise < string | null > ;
189199 isLoading : boolean ;
190200 client : IConvexReactClient ;
201+ setIsConvexAuthenticated : React . Dispatch <
202+ React . SetStateAction < boolean | null >
203+ > ;
191204} ) {
192205 useEffect ( ( ) => {
206+ // If rendered with isAuthenticated=true then clear that auth on in cleanup.
193207 if ( isAuthenticated ) {
194208 return ( ) => {
195209 client . clearAuth ( ) ;
210+ // Set state back to loading in case this is a transition from one
211+ // fetchToken function to another which signals a new auth context,
212+ // e.g. a new orgId from Clerk. Auth context changes like this
213+ // return isAuthenticated: true from useAuth() but if
214+ // useQuth reports isAuthenticated: false on the next render
215+ // then this null value will be overridden to false.
216+ setIsConvexAuthenticated ( ( ) => null ) ;
196217 } ;
197218 }
198- } , [ isAuthenticated , fetchAccessToken , isLoading , client ] ) ;
219+ } , [
220+ isAuthenticated ,
221+ fetchAccessToken ,
222+ isLoading ,
223+ client ,
224+ setIsConvexAuthenticated ,
225+ ] ) ;
199226 return null ;
200227}
0 commit comments