Custom React Hook for Authentication with Amazon Cognito
Tags: react, aws, amplify, cognito
Published: 2020-10-27 09:23:57

In one of my last projects I used [Amazon Cognito](https://aws.amazon.com/cognito/) with [Azure AD B2C](https://azure.microsoft.com/en-us/services/active-directory/external-identities/b2c/) as identity provider. I wrote the following post about this integration:

{% post danielbayerlein/how-to-use-azure-ad-b2c-as-idp-for-amazon-cognito-28nj %}

For a plug & play integration into a React application I used the [@aws-amplify/auth](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js#configure-your-application) library for authentication.

The integration is very easy, but with a [React Hook](https://reactjs.org/docs/hooks-intro.html) it is even easier. So I created a simple React Hook that I would like to share with you now, maybe it will help you. It is not bound to Azure, you can use it with any OIDC identity provider.

Let's take a closer look at this one. The hook accepts an object `{ provider, options }` as param. `provider` is the identity provider name you specified in Amazon Cognito. `options` are the AWS Amplify auth options, see the [API documentation](https://aws-amplify.github.io/amplify-js/api/interfaces/authoptions.html) for the complete list.

The hook returns the functions `signIn()` and `signOut()` as well as an identifier (`isSignedIn`) for the login status and last but not least the logged in user (`user`).

```javascript
import { useState, useEffect, useMemo } from 'react'
import Auth from '@aws-amplify/auth'

export default ({ provider, options }) => {
  const [state, setState] = useState({
    user: {},
    isSignedIn: false
  })

  const auth = useMemo(() => {
    Auth.configure(options)
    return Auth
  }, [])

  useEffect(() => {
    auth.currentAuthenticatedUser()
      .then((user) => setState({ user, isSignedIn: true }))
      .catch(() => {})
  }, [])

  const signIn = () => auth.federatedSignIn({ provider })

  const signOut = () => auth.signOut()

  return {
    ...state,
    signIn,
    signOut
  }
}
```

As soon as you call the `signIn()` function, you will be redirected to the login page of the IdP. Afterwards you are returned to the application, see `redirectSignIn` option.

If the `signOut()` function is called, the logout is performed and you are returned to the application, see `redirectSignOut` option.

Here is an example with the React `useAuth()` hook in action.

```jsx
import React from 'react'
import useAuth from '../hooks/useAuth'

const App = () => {
  const { signIn, signOut, user, isSignedIn } = useAuth({
    provider: 'Azure-AD-B2C',
    options: {
      userPoolId: 'eu-central-1_aabbccddeeff',
      userPoolWebClientId: '1a2b3c4d5e6f7g8h9i0',
      oauth: {
        domain: 'cognito-with-azure-example.auth.eu-central-1.amazoncognito.com',
        scope: ['email', 'aws.cognito.signin.user.admin', 'openid'],
        redirectSignIn: 'http://localhost:8080',
        redirectSignOut: 'http://localhost:8080',
        region: 'eu-central-1',
        responseType: 'code'
      }
    }
  })

  return (
    <>
      {isSignedIn ? (
        <div style={{ whiteSpace: 'pre' }}>
          <button onClick={() => signOut()}>Logout</button>
          <h1>Hi {user.username}</h1>
          <code>{JSON.stringify(user, null, 2)}</code>
        </div>
      ) : (
        <button onClick={() => signIn()}>Login</button>
      )}
    </>
  )
}

export default App
```

You can also use this hook centrally together with the [React Context](https://reactjs.org/docs/context.html) in your application.

---

If you have any kind of feedback, suggestions or ideas - feel free to comment this post!