Multiple Authentication Types in AWS Amplify
Published: 2020-03-02 17:34:52

---
title: Multiple Authentication Types in AWS Amplify
published: true
description: A simple endpoint for managing public posts
canonical_url: https://blog.robertbroersma.com/multiple-authentication-types-in-aws-amplify
---

The goal is to create a backend that allows us to:

1. Signup and login
2. Create and manage posts through a GraphQL API
3. Enable everyone (also unauthenticated users) to READ all posts
4. Prevent users from editing posts by others

We run the following commands to setup our Amplify project:
```cli
amplify init
? Initialize amplify with your prefered settings
```

```cli
amplify add auth
? Do you want to use the default authentication and security configuration
Default configuration

? How do you want users to be able to sign in?
Username

? Do you want to configure advanced settings?
No, I am done.

# I went with all the defaults. Configure however you'd like!
```

```cli
amplify add api

? Please select from one of the below mentioned services: 
GraphQL

? Provide API name: 
amplifyPosts

? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
# Using cognito user pool for signing up and logging in users

? Do you want to configure advanced settings for the GraphQL API 
Yes, I want to make some additional changes.

? Configure additional auth types? 
Yes

? Choose the additional authorization types you want to configure for the API 
API key
# A public API Key is needed to read ALL the posts

API key configuration
? Enter a description for the API key: 
amplifyPosts

? After how many days from now the API key should expire (1-365): 
7

? Configure conflict detection? 
No

? Do you have an annotated GraphQL schema? 
No

? Do you want a guided schema creation? 
Yes

? What best describes your project: 
Single object with fields (e.g., “Todo” with ID, name, description)

? Do you want to edit the schema now? 
Yes
# This is where you copy and paste the schema below

✔ GraphQL schema compiled successfully.
```

```cli
amplify add codegen

? Choose the code generation language target 
javascript

? Enter the file name pattern of graphql queries, mutations and subscriptions
src/graphql/**/*.js

? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions 
Yes

? Enter maximum statement depth [increase from default if your schema is deeply nested] 
2

✔ Generated GraphQL operations successfully and saved at src/graphql
```

The schema:

```graphql
type Post
  @model
  @auth(
    rules: [
      # The owner is allowed to do everything
      { allow: owner }
      # The public is only allowed to read posts
      { allow: public, operations: [read] }
    ]
  ) {
  id: ID!
  title: String!
  content: String
  owner: String
}
```

At this point we can either run `amplify push` to deploy our backend, or `amplify mock` to mock our backend locally (this still required you to deploy the auth module first, but the `mock` command will guide you through that!)

At this point, add some users and posts to the backend by writing some mutations in the Amplify Console (or in the GraphiQL client at http://localhost:20002 if you used `amplify mock`).

After you `push` or `mock` your backend, Amplify will generate some files for you in your specified src directory:
1. `aws-exports.js` - A configuration file for our frontend to communicate with our backend
2. `src/graphql/{mutations,queries,subscriptions}.js` - A starting point for GraphQL queries so we don't have to write them ourselves (you can write more optimized ones tho if you want!)

Now's the time to consume the backend in our frontend.

Install `aws-amplify` and whatever aws package that fits your framework (We use `react` and `aws-amplify-react`):
```cli
yarn add aws-amplify aws-amplify-react
```

Somewhere high up in our component tree, we configure `Amplify`:
```javascript
import Amplify from 'aws-amplify'
import awsconfig from '../aws-exports'

Amplify.configure(awsconfig)
```

To query for the posts created by the _authenticated user_:
```jsx
import React, { useState, useEffect } from 'react'
import { API, graphqlOperation } from 'aws-amplify'
import { withAuthenticator } from 'aws-amplify-react'
import { listPosts } from '../graphql/queries'

const MyPostsScreen = () => {
  const [myPosts, setMyPosts] = useState([])

  useEffect(() => {
    async function getPosts() {
      const { data } = await API.graphql(graphqlOperation(listPosts))
      setMyPosts(data.listPosts.items)
    }

    getPosts()
  }, [])

  return (
    <div>
      My Posts:
      <ul>
        {myPosts.map(post => (
          <Post key={post.id} post={post} />
        ))}
      </ul>
    </div>
  )
}

// withAuthenticator wraps our components in a signup/login, which makes sure we are logged in when accessing this component!
export const AuthenticatedMyPostsScreen = withAuthenticator(MyPostsScreen)
```

Now, to query for ALL posts, all we need to do is switch the authMode to `API_KEY`:
```jsx
import React, { useState, useEffect } from 'react'
import { API } from 'aws-amplify'
import { listPosts } from '../graphql/queries'

export const AllPostsScreen = () => {
  const [allPosts, setAllPosts] = useState([])

  useEffect(() => {
    async function getPosts() {
      // Switch authMode to API_KEY
      const { data } = await API.graphql({ 
        query: listPosts, 
        authMode: 'API_KEY',
      })
      setPosts(data.listPosts.items)
    }

    getPosts()
  }, [])

  return (
    <div>
      All Posts:
      <ul>
        {allPosts.map(post => (
          <Post key={post.id} post={post} />
        ))}
      </ul>
    </div>
  )
}
```

That's it! Because of the way our GraphQL schema uses the `@auth` directive, it is still impossible to edit posts that you don't own. Trying to run a mutation using `authMode: 'API_KEY'` will result in an `Unauthorized` error.

It took me a while to figure out you need to switch the `authMode`. If there's a better or easier way to do this, I'd love to hear about it! 

Cheers.