aws-amplify / amplify-ui

Amplify UI is a collection of accessible, themeable, performant React (and more!) components that can connect directly to the cloud.
https://ui.docs.amplify.aws
Apache License 2.0
884 stars 280 forks source link

[FR: Authenticator] Support App Router in NextJS 13 #3727

Open cwoolum opened 1 year ago

cwoolum commented 1 year ago

On which framework/platform would you like to see this feature implemented?

React, Other

Which UI component is this feature-request for?

Authenticator

Please describe your feature-request in detail.

The new NextJS app router is due to be released in NextJS 13.4 which should be soon . Currently, If I try to use withAuthenticator when using the app router, I get the following error.

error - ./src/app/page.tsx
ReactServerComponentsError:

You're importing a component that needs useEffect. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.

   ,-[/local/home/woolumc/scratch/test/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.esm.js:1:1]
 1 | import { computePosition, arrow as arrow$1 } from '@floating-ui/dom';
 2 | export * from '@floating-ui/dom';
 3 | import * as React from 'react';
 4 | import { useLayoutEffect, useEffect } from 'react';
   :                           ^^^^^^^^^
 5 | import * as ReactDOM from 'react-dom';
 6 | 
 7 | var index = typeof document !== 'undefined' ? useLayoutEffect : useEffect;
   `----

The error was caused by importing '@aws-amplify/ui-react/dist/esm/index.mjs' in './src/app/page.tsx'.

Maybe one of these should be marked as a client entry with "use client":
  ./src/app/page.tsx

Please describe a solution you'd like.

withAuthenticator should be usable in apps using the new App Router.

Adding 'use client' to the top of the file does work but it would be nice to support rendering on the server.

To recreate this, create a new NextJS app using create-next-app and be sure to add the experimental App Router.

Then follow the steps from this blog post

We love contributors! Is this something you'd be interested in working on?

calebpollman commented 1 year ago

@cwoolum Looking at the NextJS docs here, server components are best used for components that do not require user interaction.

As the Authenticator is very much tied to user interaction, not sure if it aligns to the server component use case, but open to discussing!

cwoolum commented 1 year ago

I think my intent here would be to know at the server side that a user is authenticated or not and not leak sensitive information to the client. Even wrapping any of my components in Authenticator.Provider or ThemeProvider produces the same result.

I would be fine redirecting the user to a login page via some sort of server side redirect but I wouldn't want the redirect logic exposed on the client side because then the authenticated UI would also be sent, even if the user isn't authenticated. Let me know if this makes sense or if I'm thinking about it wrong.

calebpollman commented 1 year ago

Can you utilize Auth.currentAuthenticatedUser on the server to check the authentication status of the current user and redirect from there?

Might be misunderstanding the intention here, please let me know if I'm missing something 😄

cwoolum commented 1 year ago

That seems to be broken currently as well although is probably the correct approach.

https://github.com/aws-amplify/amplify-js/issues/10818#issuecomment-1507900794

calebpollman commented 1 year ago

@cwoolum Just wanted to give you a heads up that we are currently looking in to how we will be supporting NextJS server components. Will update the ticket once the investigation is completed.

andremachado94 commented 1 year ago

@calebpollman Do you know if there is any update on this topic? Thanks! 😃

nvm-delete commented 1 year ago

I don't think anything updated here, did it? So basically we are stuck to the pages router till then. @cwoolum Did you find any way around?

ericclemmons commented 1 year ago

Is there a quick solution to add "use client"; at the top of the Authenticator (or whatever's bringing in the useEffect), then further investigate to optimize usage for RSC?

guidocaru commented 10 months ago

Any updates on this?

rkrishnasanka commented 10 months ago

Wait is there actually no way to use cognito with the new app router ?

zvictor commented 10 months ago

@rkrishnasanka There is a workaround! Just use Authenticator instead of withAuthenticator.

https://ui.docs.amplify.aws/react/connected-components/authenticator#step-3-add-the-authenticator

import React from 'react';
import { Amplify } from 'aws-amplify';

import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';

import awsExports from './aws-exports';
Amplify.configure(awsExports);

export default function App() {
  return (
    <Authenticator>
      {({ signOut, user }) => (
        <main>
          <h1>Hello {user.username}</h1>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  );
}
Willis0826 commented 9 months ago

Hi @zvictor , do you know which file we should add the Authenticator component to? thanks!

zvictor commented 8 months ago

Hi @zvictor , do you know which file we should add the Authenticator component to? thanks!

Anywhere you want to "protect". If you want to wrap everything, /app/provider.tsx is probably the place you are looking for. For instance, you can set it up like this:

'use client'

import { Amplify } from 'aws-amplify'
import { Authenticator } from '@aws-amplify/ui-react'
import * as amplifyConfig from '@/modules/auth/config'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
import '@aws-amplify/ui-react/styles.css'

Amplify.configure(amplifyConfig, { ssr: true })

export function Providers({ children }: { children: React.ReactNode }) {
  return (
      <NextThemesProvider attribute="class" defaultTheme="system">
        <Authenticator variation="modal">{children}</Authenticator>
      </NextThemesProvider>
  )
}
zvictor commented 8 months ago

Just beware that even with the workaround I posted you should still find it very faulty!

For reasons unknown, the Authenticator component can sometimes return idle when in authenticated state. As result, your logged in users will be redirected to /sign-in but will be shown a 404 page instead of the signInUp form.

I don't understand why this happens only sometimes, but it would be good to have others confirming the issue.

Related: https://github.com/aws-amplify/amplify-ui/issues/1332

ataylorme commented 6 days ago

Have you all tried what is listed in the Add middleware for server-side redirect doc?