Describe the bug
We have Cognito User Pool with Identity provider configured to Google on the backend.
On the frontend I am using Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google }) in order to trigger HostedUI sign in via google UI.
After returning from authorizing with Google, Auth.currentAuthenticatedUser() returns an error of 'not authenticated' which is fine.
I use Hub to listen to 'auth' events, but nothing is ever arrives. Yesterday (Thursday 24) it was working just fine, I was getting all the events. Today, exact same code just suddenly stopped working. I am not getting the events but I believe authentication succeeds because, if I manually re-run Auth.currentAuthenticatedUser() after some time, it succeeds.
To Reproduce
Steps to reproduce the behavior:
auth channel on Hub.Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google }) and go through the authentication flow as usual.Hub.listen("auth"...) to report "signIn" message.Expected behavior
"Auth" channel on Hub should receive the "signIn" message
Desktop (please complete the following information):
Amplify context
Sample code
Amplify.configure({
Auth: {
region: "xx-xxx-x",
identityPoolId: "XXXXXXXXXXXXX",
userPoolId: "XXXXXXXX",
userPoolWebClientId: "XXXXXXXXXXX",
oauth: {
domain: "auth.xxx.xx",
scope: [
"email",
"openid",
"profile",
"picture",
"aws.cognito.signin.user.admin"
],
redirectSignIn: "http://localhost:3000", // for debugging (it matches settings in cognito)
redirectSignOut: "http://localhost:3000", // for debugging (it matches settings in cognito)
responseType: "code"
}
}
});
const App: React.FC = () => {
const [signInState, setSignInState] = useState("signedOut");
Hub.listen("auth", (message: { payload: HubPayload }) => {
switch (message.payload.event) {
case "signIn":
setAuthState("signedIn");
break;
default:
console.log(`Unhandled event: ${message.payload.event}`);
}
});
useEffect(() => {
Auth.currentAuthenticatedUser()
.then(data => {
setAuthState("signedIn");
})
.catch(e => {
setAuthState("signedOut");
});
}, [signInState]);
function signIn() {
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google });
}
function setAuthState(state: string) {
if (state !== signInState) {
setSignInState(state);
}
}
function signOut() {
Auth.signOut();
}
@benderillo, Hub.listen is a side effect, and so need to add it to useEffect(). Below is a sample of that
export default function useAuth() {
const [isLoading, setIsLoading] = useState(true);
const [user, setUser] = useState();
const handleAuth = ({ payload }) => {
switch (payload.event) {
case 'signIn':
return setUser(payload.data);
case 'signOut':
return setUser();
default:
}
};
useEffect(() => {
Auth.currentAuthenticatedUser()
.then(setUser)
.catch(console.error)
.then(() => setIsLoading(false));
Hub.listen('auth', handleAuth);
return () => Hub.remove('auth', handleAuth);
}, []);
return {
Auth,
isLoading,
owner: user ? user.username : null,
user
};
}
@Amplifiyer
I don't see how this solves the problem. All that Hub.listen() does is simply adds a callback function to Hub module so when a message on the channel arrives, it gets propagated to the callback. It should not matter if I call it from inside useEffect or not.
Moreover, example here https://aws-amplify.github.io/docs/js/authentication#react-components (see Full React example) calls it from the constructor of a class.
Also, I don't see how this explains that it used to work and now it doesn't anymore.
Nevertheless, I did try to put it into useEffect hook but it did not change anything.
The time when my code magically stopped working coincided with the reported DDoS attack on AWS (https://www.crn.com.au/news/aws-hit-by-ddos-attack-dragging-half-of-web-down-532842), could it be a culprit? Also, I did reboot my mac and let it install a heap of system updates, could it be a culprit?
I just need some help to understand how do I debug this thing further to pinpoint the problem. Could you suggest where do I start? I am new to frontend dev, so any hints will be handy.
Code does not simply stop to work for no reason.
So I found the root cause of the issue with Hub.listen().
My import section looked like this: import {Hub} from "@aws-amplify/core/lib/Hub" while it should have been import {Hub} from "@aws-amplify/core".
Once I changed it, everything is back to working state.
@Amplifiyer
I'm facing something similar, but not consistent.
The federated signin always works, but sometimes the signIn message is not fired so my listener is not invoked.
So, it seems like the page is waiting (I have a loader rendered) for something and nothing really happens.
Once I refresh the page all works well, the user is signed in etc.
My code is very similar to what's posted in this issue, so I don't see a point to post my code here.
any ideas?
I'm using [email protected]
What I guess is happening is that the signIn event is dispatched and the listener is not ready yet, so the event is not catched (@Amplifiyer does that make any sense?)
What I eventually ended up doing, is set a timeout in the page where the Hub.listen('auth', callback) is defined, and when the timeout callback fired I check for Auth.currentAuthenticatedUser(), these are the relevant parts of the implementation:
import { Hub, Auth } from 'aws-amplify';
import { HubCallback } from '@aws-amplify/core/lib-esm/Hub';
const TIMER_DELAY = 10000;
const FederatedResponse: FunctionComponent<Props> = ({ location }) => {
const errorHandler = useCallback((...args) => {
console.error('Sign-in Error: ', ...args);
history.push(ROUTES.LOGIN);
}, []);
const onSignInSuccess = useCallback(async () => {
try {
// Do something when signIn was successful
}
} catch (error) {
errorHandler(error);
}
}, [errorHandler, refreshUser]);
useEffect(
function checkIfUserAuthenticated() {
// This is the relevant part
const timeoutId = setTimeout(async () => {
try {
await Auth.currentAuthenticatedUser();
await onSignInSuccess();
} catch (error) {
errorHandler(error);
}
}, TIMER_DELAY);
return () => {
clearTimeout(timeoutId);
};
},
[errorHandler, onSignInSuccess]
);
const authListener = useCallback<HubCallback>(
async ({ payload: { event, data, message } }) => {
if (event === 'signIn') {
await onSignInSuccess();
} else if (event === 'signIn_failure') {
errorHandler(event, data, message);
}
},
[errorHandler, onSignInSuccess]
);
useEffect(() => {
Hub.listen('auth', authListener);
return () => {
Hub.remove('auth', authListener);
};
}, [authListener]);
return <Loader />;
};
export default FederatedResponse;
@daniel500tech, can you check if your issue is similar to #5269. If it's not, please open a new issue with all the information.
Most helpful comment
So I found the root cause of the issue with
Hub.listen().My
importsection looked like this:import {Hub} from "@aws-amplify/core/lib/Hub"while it should have beenimport {Hub} from "@aws-amplify/core".Once I changed it, everything is back to working state.