amplify-ui
amplify-ui copied to clipboard
[FR: Authenticator] Support App Router in NextJS 13
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?
- [ ] 👋 I may be able to implement this feature request.
- [ ] ⚠️ This feature might incur a breaking change.
@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!
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.
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 😄
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
@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.
@calebpollman Do you know if there is any update on this topic? Thanks! 😃
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?
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?
Any updates on this?
Wait is there actually no way to use cognito with the new app router ?
@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>
);
}
Hi @zvictor , do you know which file we should add the Authenticator component to? thanks!
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>
)
}
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