Skip to content
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

Using Auth method to check if the user is logged in with SSR and then trying to signOut does not work #7223

Closed
MontoyaAndres opened this issue Nov 18, 2020 · 20 comments
Labels
Auth Related to Auth components/category SSR Issues related to Server Side Rendering

Comments

@MontoyaAndres
Copy link

MontoyaAndres commented Nov 18, 2020

Describe the bug
I'm using the Auth method to know if a user is logged in and then execute the signOut method to logout but does not work. Also, the Auth.currentAuthenticatedUser() throws an error that the user is not authenticated even when it is on SSR. I have just implemented this on Dev, I haven't tried on Prod.

To Reproduce

First, I have added the Amplify.configure({ ...config, ssr: true }); in the _app.js file. Then, I created a function to detect if the a user is logged in when the getServerSideProps is executed. This is withAuth:

import { withSSRContext } from 'aws-amplify';

export const withAuth = async context => {
  try {
    const SSR = withSSRContext(context);
    const user = await SSR.Auth.currentAuthenticatedUser();

    return user;
  } catch (error) {
    context.res.writeHead(301, { Location: '/signin' });
    context.res.end();
  }
};

I call this function on every private page the project has, like this:

import React from 'react';

import { withAuth } from '../lib/withAuth';
import { MySecretComponent } from '../components/views';

const MySecretPage = props => {
  const { user } = props;

  return <MySecretComponent user={user} />;
};

export async function getServerSideProps(context) {
  const auth = await withAuth(context);
  const user = JSON.parse(JSON.stringify(auth)); // Next.js throws a validation error with the object response if I dont do this.

  return {
    props: {
      user: user || null,
    },
  };
}

export default MySecretPage;

It works fine, but when the user wants to signOut, like this:

import React from 'react';
import { useRouter } from 'next/router';
import { Auth } from 'aws-amplify';

const MyComponent => () => {
  const router = useRouter();

  const signOut = () => {
    Auth.signOut().then(() => {
      router.reload();
    });
  };

  return <button onClick={signOut}>logout</button>
}

Amplify still detects I'm logged in... Even when the user already executed the signOut function... And here's when the project starts to act weird, the method withAuth throws the user to /signin even when is "logged in" but I can still navigate to any private page with the <Link /> component. I already tried removing the cache from the browser and tried with an incognito page, but nothing...

One thing to mention is that I have a header component, to show the user photo and other info, I get this info using Auth in client-side using an useEffect. I don't know if using Auth in the header component and also in SSR affects something...

Expected behavior
Work fine, when the user wants to signout

  • Device: Windows, Linux, and Android phone
  • Browser Google Chrome latest version
  • Version of aws-amplify: 3.3.7
  • Next.js version: 10.0.1
@MontoyaAndres MontoyaAndres added the to-be-reproduced Used in order for Amplify to reproduce said issue label Nov 18, 2020
@amhinson amhinson added Auth Related to Auth components/category SSR Issues related to Server Side Rendering labels Nov 18, 2020
@ericclemmons
Copy link
Contributor

Thanks for opening this issue @MontoyaAndres from #5435 (comment) 🙏

Can you share more on how you're doing sign in? Are you using <AmplifyAuthenticator>, calling Auth.sign(), Auth.federatedSignIn(), etc.?

@ericclemmons
Copy link
Contributor

@dbhagen You're having this same issue with https://github.com/dbhagen/next.js-authentication-aws, correct? If I were to drop-in aws-exports.js with Auth configured, I should see this bug, correct?

@ericclemmons
Copy link
Contributor

@dbhagen I want to better understand this comment:

I'll admit, the example worked fine until AWS Auth/WebUI/SSO was added

Do you mean the auth from the tutorial (https://dev.to/dabit3/the-complete-guide-to-next-js-authentication-2aco), or something else?

@MontoyaAndres
Copy link
Author

I'm using the method Auth.signIn and yes, I'm using the config to that project, same issue. This the aws-exports.js config:

/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.

const awsmobile = {
  "aws_project_region": "us-east-2",
  "aws_cognito_identity_pool_id": "us-east-2:xxxx-c36bexxxxx",
  "aws_cognito_region": "us-east-2",
  "aws_user_pools_id": "us-east-2_xxxxx",
  "aws_user_pools_web_client_id": "xxxxxx",
  "oauth": {},
  "aws_cloud_logic_custom": [
      {
          "name": "AdminQueries",
          "endpoint": "https://xxxxx.execute-api.us-east-2.amazonaws.com/dev",
          "region": "us-east-2"
      }
  ],
  "aws_appsync_graphqlEndpoint": "https://xxxxxx.appsync-api.us-east-2.amazonaws.com/graphql",
  "aws_appsync_region": "us-east-2",
  "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
  "aws_user_files_s3_bucket": "xxxxxx-dev",
  "aws_user_files_s3_bucket_region": "us-east-2"
};


export default awsmobile;

@MontoyaAndres
Copy link
Author

Maybe I can send you the cloudformation code generated by the amplify-cli? To understand what I'm doing?

@dbhagen
Copy link

dbhagen commented Nov 18, 2020

@dbhagen You're having this same issue with https://github.com/dbhagen/next.js-authentication-aws, correct? If I were to drop-in aws-exports.js with Auth configured, I should see this bug, correct?
Yes. In fact, this is the sanitized aws-exports.js from mine so you can make sure it matches up.

/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.

const awsmobile = {
    "aws_project_region": "us-east-1",
    "aws_cognito_identity_pool_id": "us-east-1:",
    "aws_cognito_region": "us-east-1",
    "aws_user_pools_id": "us-east-1_",
    "aws_user_pools_web_client_id": "",
    "oauth": {
        "domain": "-dev.auth.us-east-1.amazoncognito.com",
        "scope": [
            "phone",
            "email",
            "openid",
            "profile",
            "aws.cognito.signin.user.admin"
        ],
        "redirectSignIn": "http://localhost:3000/signinreturn/",
        "redirectSignOut": "http://localhost:3000/signoutreturn/",
        "responseType": "code"
    },
    "federationTarget": "COGNITO_USER_POOLS"
};


export default awsmobile;

@dbhagen I want to better understand this comment:

I'll admit, the example worked fine until AWS Auth/WebUI/SSO was added

Do you mean the auth from the tutorial (https://dev.to/dabit3/the-complete-guide-to-next-js-authentication-2aco), or something else?

Yes, that tutorial worked perfectly with Auth.signOut() until I added SSO via an amplify update auth from the initial tutorial fork deployment.

@ericclemmons
Copy link
Contributor

Ahhh! The SSO redirect part to /signinreturn is what's interesting:
dbhagen/next.js-authentication-aws@3ec7225

The way SSR Auth works at the moment is the Auth client handles the credentials negotiation, then sets credentials in cookies for the server to read.

If you were to redirect back to / or whichever page uses Auth or AmplifyAuthenticator, the client-side finish the SSO flow & show the signed-in version of the app.

Alternatively, you can convert signinpage to call Auth.currentAuthenticatedUser() and redirect on the client to your protected page (e.g. /profile), or error. Like:

https://github.com/dbhagen/next.js-authentication-aws/blob/main/pages/profile.js

I know it's not the flow you were expecting (client negotiation vs. server), but let me know if that works. Or let me know if I'm misunderstood entirely. I haven't had a chance to run the repository yet, but I do have a SSO version working: the difference is that it redirects back to the client to finish the login flow.

@endigo
Copy link

endigo commented Nov 20, 2020

I just hit the same issue.

Before my modification on UniversalStorgage class, cookies no expiry date or maxAge configured.
When Auth.signOut() function called, universal-cookie.remove function tries to set maxAge: 0 in order to remove from document.cookie but this is not works.

Then made my modification,

protected setUniversalItem(key: keyof Store, value: string) {
    this.cookies.set(key, value, {
      path: "/",
      // `httpOnly` cannot be set via JavaScript: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#JavaScript_access_using_Document.cookie
      sameSite: true,
      // Allow unsecure requests to http://localhost:3000/ when in development.
      secure: window.location.hostname === "localhost" ? false : true,
      maxAge: 24 * 60 * 60, // 24 hours in second,
    });
  }

it works as I expected.

@MontoyaAndres
Copy link
Author

It's weird... I mean, when the SSR support was released completely, I changed the Authentication of the application to use with SSR, as I showed... I don't know if this conversion affected In something?

@ericclemmons
Copy link
Contributor

@endigo To be clear, sign in works for you but sign out isn't clearing cookies as expected?

Can you share which browser you're in?

@endigo
Copy link

endigo commented Nov 21, 2020

@ericclemmons Sign in with username and password works fine. But sometimes federated login failed.

I checked on Brave, Chrome, and Safari.

@endigo
Copy link

endigo commented Nov 25, 2020

@ericclemmons According this comment,

in order to delete a cookie from document, it should have the same path and domain options passed to remove the function.

cookies.remove( "idToken", {path: "/"} );

@dbhagen
Copy link

dbhagen commented Dec 1, 2020

Ahhh! The SSO redirect part to /signinreturn is what's interesting:
dbhagen/next.js-authentication-aws@3ec7225

The way SSR Auth works at the moment is the Auth client handles the credentials negotiation, then sets credentials in cookies for the server to read.

If you were to redirect back to / or whichever page uses Auth or AmplifyAuthenticator, the client-side finish the SSO flow & show the signed-in version of the app.

Alternatively, you can convert signinpage to call Auth.currentAuthenticatedUser() and redirect on the client to your protected page (e.g. /profile), or error. Like:

https://github.com/dbhagen/next.js-authentication-aws/blob/main/pages/profile.js

I know it's not the flow you were expecting (client negotiation vs. server), but let me know if that works. Or let me know if I'm misunderstood entirely. I haven't had a chance to run the repository yet, but I do have a SSO version working: the difference is that it redirects back to the client to finish the login flow.

Hey @ericclemmons, hope you had a good holiday break!
So over the weekend I tested it out, and sure enough, if I routed straight to /, the SSO signout worked as expected. If I routed anywhere else and used useEffect() hooks to run Auth.currentAuthenticatedUser(), the session was still available. After some more poking, it's because I strip/leave off the withAuthenticator() for the page export.

So now I'm looking into that UI to see what I need to implement so that I can implement my own UI, but have the handler functionality.

@dbhagen
Copy link

dbhagen commented Dec 1, 2020

Sorry, quick follow up to say I've committed my tests here: https://github.com/dbhagen/next.js-authentication-aws
Point your redirect in amplify auth (via amplify auth update) to http://localhost:3000/ or http://localhost:3000/profile/ and it will work. Change it to http://localhost:3000/test/ and sign out will stop working.

https://github.com/dbhagen/next.js-authentication-aws/blob/3ec7225c614b580c85b30cdf8be0a0024b1bb020/pages/profile.js#L37 vs. https://github.com/dbhagen/next.js-authentication-aws/blob/28f511cc61ba01d57c9f726c1db4885683ab686f/pages/test.js#L37

@ericclemmons
Copy link
Contributor

Ah, so running your example that withAuthenticator makes a big different. It may be a race-condition, but it looks more like a bug due to #6330:

Screen Shot 2020-12-11 at 12 39 16 PM

Notice how the in progress check is true at the start (which is what we want!), but an error is thrown, preventing the user from resolving correctly.

if (this.isOAuthInProgress()) {
logger.debug('OAuth signIn in progress, waiting for resolution...');
await new Promise(res => {
const timeoutId = setTimeout(() => {
logger.debug('OAuth signIn in progress timeout');
Hub.remove('auth', hostedUISignCallback);
res();
}, OAUTH_FLOW_MS_TIMEOUT);
Hub.listen('auth', hostedUISignCallback);
function hostedUISignCallback({ payload }) {
const { event } = payload;
if (
event === 'cognitoHostedUI' ||
event === 'cognitoHostedUI_failure'
) {
logger.debug(`OAuth signIn resolved: ${event}`);
clearTimeout(timeoutId);
Hub.remove('auth', hostedUISignCallback);
res();
}
}
});
}
const user = this.userPool.getCurrentUser();

Once we resolve #6330, this should "just work".

@ericclemmons
Copy link
Contributor

Oh, another note: it "just worked" with a username/password. The Google sign-in is where I saw the failure, leading me to believe this is an issue with #6330 .

@guiaramos
Copy link

Any solution for this issue?

@sammartinez sammartinez removed the to-be-reproduced Used in order for Amplify to reproduce said issue label Feb 2, 2021
@ericclemmons
Copy link
Contributor

Closing, as #7718 (via v1.0.1) should resolve this duplication issue.

To install the latest version of @aws-amplify/ui-react, for example:

npm install aws-amplify @aws-amplify/ui-react
# or
yarn add aws-amplify @aws-amplify/ui-react

Be sure to install aws-amplify, rather than @aws-amplify/core directly.
(aws-amplify will install @aws-amplify/core and other dependencies itself)

Let us know if you experience any issues! 🙏

@MontoyaAndres
Copy link
Author

Thanks @ericclemmons !

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Auth Related to Auth components/category SSR Issues related to Server Side Rendering
Projects
None yet
Development

No branches or pull requests

7 participants