-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(hooks): update useAuth
to handle more auth hub events
#2795
Changes from all commits
89e0ae3
213202a
ef2655a
f968796
8082476
b0a914f
6ff58e4
9fb0d3f
9adbb19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,15 @@ | ||
import * as React from 'react'; | ||
|
||
import Auth, { CognitoUser } from '@aws-amplify/auth'; | ||
import { Hub, HubCallback } from '@aws-amplify/core'; | ||
|
||
// Exposes relevant CognitoUser properties | ||
interface AuthUser extends CognitoUser { | ||
username: string; | ||
attributes: Record<string, string>; | ||
} | ||
import { AmplifyUser } from '@aws-amplify/ui'; | ||
import { Auth } from 'aws-amplify'; | ||
|
||
export interface UseAuthResult { | ||
user?: AuthUser; | ||
user?: AmplifyUser; | ||
isLoading: boolean; | ||
error?: Error; | ||
fetch?: () => void; | ||
/** @deprecated Fetch is handled automatically, do not use this directly */ | ||
fetch?: () => Promise<void>; | ||
} | ||
|
||
/** | ||
|
@@ -27,32 +23,75 @@ export const useAuth = (): UseAuthResult => { | |
user: undefined, | ||
}); | ||
|
||
const handleAuth: HubCallback = ({ payload }) => { | ||
switch (payload.event) { | ||
case 'signIn': | ||
return setResult({ user: payload.data as AuthUser, isLoading: false }); | ||
case 'signOut': | ||
return setResult({ isLoading: false }); | ||
default: | ||
break; | ||
/** | ||
* Hub events like `tokenRefresh` will not give back the user object. | ||
* This util will be used to get current user after those events. | ||
*/ | ||
const fetchCurrentUser = React.useCallback(async () => { | ||
setResult({ user: undefined, isLoading: true, error: undefined }); | ||
|
||
try { | ||
// casting the result because `Auth.currentAuthenticateduser` returns `any` | ||
const user = (await Auth.currentAuthenticatedUser()) as AmplifyUser; | ||
wlee221 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
setResult({ user, isLoading: false }); | ||
} catch (e) { | ||
const error = e as Error; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's this line for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, so I needed to cast There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was hoping we could do something like } catch (error: Error) {
setResult({ error, isLoading: false })
} but TS does not support strongly typing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Thanks! |
||
setResult({ error, isLoading: false }); | ||
} | ||
}; | ||
}, []); | ||
|
||
const fetch = () => { | ||
setResult({ isLoading: true }); | ||
const handleAuth: HubCallback = React.useCallback( | ||
({ payload }) => { | ||
switch (payload.event) { | ||
calebpollman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// success events | ||
case 'signIn': | ||
case 'signUp': | ||
case 'autoSignIn': { | ||
setResult({ user: payload.data as AmplifyUser, isLoading: false }); | ||
break; | ||
} | ||
case 'signOut': { | ||
setResult({ user: undefined, isLoading: false }); | ||
break; | ||
} | ||
|
||
Auth.currentAuthenticatedUser() | ||
.then((user: AuthUser) => setResult({ user, isLoading: false })) | ||
.catch((error: Error) => setResult({ error, isLoading: false })); | ||
// failure events | ||
case 'tokenRefresh_failure': | ||
case 'signIn_failure': { | ||
setResult({ error: payload.data as Error, isLoading: false }); | ||
break; | ||
} | ||
case 'autoSignIn_failure': { | ||
// autoSignIn just returns error message. Wrap it to an Error object | ||
setResult({ error: new Error(payload.message), isLoading: false }); | ||
break; | ||
} | ||
|
||
// Handle Hub Auth events | ||
Hub.listen('auth', handleAuth); | ||
// events that need another fetch | ||
case 'tokenRefresh': { | ||
fetchCurrentUser(); | ||
break; | ||
} | ||
|
||
// Stop listening events on unmount | ||
return () => Hub.remove('auth', handleAuth); | ||
}; | ||
default: { | ||
// we do not handle other hub events like `configured`. | ||
break; | ||
} | ||
} | ||
}, | ||
[fetchCurrentUser] | ||
); | ||
|
||
React.useEffect(() => { | ||
const unsubscribe = Hub.listen('auth', handleAuth, 'useAuth'); | ||
fetchCurrentUser(); // on init, see if user is already logged in | ||
|
||
React.useEffect(fetch, []); | ||
return unsubscribe; | ||
}, [handleAuth, fetchCurrentUser]); | ||
|
||
return { ...result, fetch }; | ||
return { | ||
...result, | ||
/** @deprecated Fetch is handled automatically, do not use this directly */ | ||
fetch: fetchCurrentUser, | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL
it.each