Are you looking to implement authentication forms in your NextJS project using
Amazon Cognito? Then this article is for you.
1. Introduction
1.1 Amazon Cognito
Amazon Cognito is an authentication and authorization service that lets you
manage your applications' access control, whether a web or mobile
app. Whether dealing with a small number of users or millions, Cognito
already has the infrastructure set up for you. It also supports integration with popular identity providers such as Facebook, Google, and Apple. See their
documentation.
Amazon Cognito provides a good amount of documentation for any level of
developers to start with. They have complete user authentication forms, UI components that you can easily integrate into your application, and a set of APIs you can call in case you want to implement your own
custom UI. All these are available from their website at https://docs.amplify.aws/lib/auth/getting-started/q/platform/js.
More than that, it can control access to Amazon resources such as Lambda,
databases, and more. But that is a topic for another article.
1.2 NextJS
NextJS is just another open-source front-end web development framework for
React. Its selling point is that it can render server-side and generate static websites, which is very good for SEO. What I love about NextJS
is their easy-to-read documentation at
https://nextjs.org/docs and examples
officially available from their GitHub repository at
https://github.com/vercel/next.js/tree/canary/examples. In a way, NextJS is like Angular Framework for React.
1.3 SSR Support for AWS Amplify
2. Amazon Cognito Pool
2.1 In the Service filter, enter Cognito. Click Manage User Pools.
2.2 Click Create a user pool.
2.3 Enter a Pool name. Click Step through settings.
2.4 Select how you want your users to sign in. For this exercise, we will only
allow the email address.
2.5 At the bottom of this screen, you can select which standard attributes you want to include in your users' profiles. We will use given_name and
family_name. Note that we already have access to the email as a username. Click
Next Step.
2.6 On the next page, Configure the password strength. Click Next Step.
2.7 For the following settings, leave everything to default and click Next
Step.
- MFA and verifications
- Messages customizations
- Tags
- Devices
2.8 Under App clients, click Add an app client. Let's name the client Web
Client.
- Uncheck Generate client secret.
- Check Enable username and password authentication.
Click Create Client.
3. Google Console Identity Provider
3.1 Create a new project. Click the arrow down button in the top left corner
and New Project.
3.2 Enter your project name.
Wait until the project is successfully created.
Before you continue, ensure the newly created project is selected in
the dropdown located at the top left corner of the screen.
*You can default create 25 projects under your Google console account.
3.3 Click the Navigation Menu / API & Services / Credentials.
3.4 Click Create Credentials / OAuth client ID.
3.5 Under Application type, select Web application.
3.6 Enter the name.
3.7 Enter the Authorized Javascript origins and Authorized redirect URIs.
You must get your Cognito domain name and replace the value accordingly:
https://<cognitoDomainUrl>/oauth2/idresponse.
And hit save.
3.8 Once it saves, you must get and keep the Client ID and Secret on the right
side of this page.
3.9 Once again, click the Navigation Menu / API & Services / and click the
OAuth consent screen. This is where you will publish the app when it's ready
for production. You should also add the email addresses of the users you
will use for testing. Remember this as it's essential.
4. The NextJS App
- useSession
- SessionContext
- WithLayout
- WithSession
- Secured
- secured
Part of the hook that authenticates a user:
const useSession = () => {
const [stage, setStage] = useState(0)
const [isLoading, setLoading] = useState(false)
const [user, setUser] = useState(null) // cognito user
const [isAuthenticated, setIsAuthenticated] = useState(!!user)
const [error, setError] = useState(false)
const refreshState = useCallback(() => {
setStage(1)
setLoading(true)
Auth.currentAuthenticatedUser()
.then(user => {
setLoading(false)
setStage(2)
setUser(user)
setIsAuthenticated(_isAuthenticated(user))
setError(null)
})
.catch(err => {
setLoading(false)
setStage(3)
logger.error("Error authenticating user", err)
setIsAuthenticated(false)
if (err === 'not authenticated') {
setError(null)
} else {
setError(err)
}
})
return () => {
setStage(0)
setLoading(false)
}
}, [])
// ...
}
Post a Comment