

# Configuring authorization and authentication to secure your GraphQL APIs
<a name="security-authz"></a>

Amazon AppSync offers the following authorization types to secure GraphQL APIs: API keys, Lambda, IAM, OpenID Connect, and Cognito User Pools. Each option provides a different method of security: 

1. **API Key Authorization**: Controls throttling for unauthenticated APIs, providing a simple security option. 

1. **Lambda Authorization**: Enables custom authorization logic, explaining function inputs and outputs in detail. 

1. **IAM Authorization**: Utilizes Amazon's signature version 4 signing process, allowing fine-grained access control through IAM policies. 

1. **OpenID Connect Authorization**: Integrates with OIDC-compliant services for user authentication. 

1. **Cognito User Pools**: Implements group-based access control using Cognito's user management features. 

## Authorization types
<a name="authorization-types"></a>

There are five ways you can authorize applications to interact with your Amazon AppSync GraphQL API. You specify which authorization type you use by specifying one of the following authorization type values in your Amazon AppSync API or CLI call:
+   
** `API_KEY` **  
For using API keys.
+   
** `AWS_LAMBDA` **  
For using an Amazon Lambda function.
+   
** `AWS_IAM` **  
For using Amazon Identity and Access Management ([IAM](http://www.amazonaws.cn/iam/)) permissions.
+   
** `OPENID_CONNECT` **  
For using your OpenID Connect provider.
+   
** `AMAZON_COGNITO_USER_POOLS` **  
For using an Amazon Cognito user pool.

These basic authorization types work for most developers. For more advanced use cases, you can add additional authorization modes through the console, the CLI, and Amazon CloudFormation. For additional authorization modes, Amazon AppSync provides an authorization type that takes the values listed above (that is, `API_KEY`, `AWS_LAMBDA`, `AWS_IAM`, `OPENID_CONNECT`, and `AMAZON_COGNITO_USER_POOLS`).

When you specify `API_KEY`,`AWS_LAMBDA`, or `AWS_IAM` as the main or default authorization type, you can’t specify them again as one of the additional authorization modes. Similarly, you can’t duplicate `API_KEY`, `AWS_LAMBDA` or `AWS_IAM` inside the additional authorization modes. You can use multiple Amazon Cognito User Pools and OpenID Connect providers. However, you can’t use duplicate Amazon Cognito User Pools or OpenID Connect providers between the default authorization mode and any of the additional authorization modes. You can specify different clients for your Amazon Cognito User Pool or OpenID Connect provider using the corresponding configuration regular expression.

When you save changes to your API configuration, Amazon AppSync starts to propagate the changes. Until your configuration change is propagated, Amazon AppSync continues to serve your content from the previous configuration. After your configuration change is propagated, Amazon AppSync immediately starts to serve your content based on the new configuration. While Amazon AppSync is propagating your changes for an API, we can't determine whether the API is serving your content based on the previous configuration or the new configuration.

## API\$1KEY authorization
<a name="api-key-authorization"></a>

Unauthenticated APIs require more strict throttling than authenticated APIs. One way to control throttling for unauthenticated GraphQL endpoints is through the use of API keys. An API key is a hard-coded value in your application that is generated by the Amazon AppSync service when you create an unauthenticated GraphQL endpoint. You can rotate API keys from the console, from the CLI, or from the [Amazon AppSync API reference](https://docs.amazonaws.cn/appsync/latest/APIReference/).

------
#### [ Console ]

1. Sign in to the Amazon Web Services Management Console and open the [AppSync console](https://console.amazonaws.cn/appsync/).

   1. In the **APIs dashboard**, choose your GraphQL API.

   1. In the **Sidebar**, choose **Settings**.

1. Under **Default authorization mode**, choose **API key**.

1. In the **API keys** table, choose **Add API key**.

   A new API key will be generated in the table.

   1. To delete an old API key, select the API key in the table and then choose **Delete**.

1. Choose **Save** at the bottom of the page.

------
#### [ CLI ]

1. If you haven't already done so, configure your access to the Amazon CLI. For more information, see [Configuration basics](https://docs.amazonaws.cn//cli/latest/userguide/cli-configure-quickstart.html).

1. Create a GraphQL API object by running the [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html) command.

   You'll need to type in two parameters for this particular command:

   1. The `api-id` of your GraphQL API.

   1. The new `name` of your API. You can use the same `name`.

   1. The `authentication-type`, which will be `API_KEY`.
**Note**  
There are other parameters such as `Region` that must be configured but will usually default to your CLI configuration values.

   An example command may look like this:

   ```
   aws appsync update-graphql-api --api-id abcdefghijklmnopqrstuvwxyz --name TestAPI --authentication-type API_KEY
   ```

   An output will be returned in the CLI. Here's an example in JSON:

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "TestAPI",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://s8i3kk3ufhe9034ujnv73r513e.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://s8i3kk3ufhe9034ujnv73r513e.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:348581070237:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

------

API keys are configurable for up to 365 days, and you can extend an existing expiration date for up to another 365 days from that day. API Keys are recommended for development purposes or use cases where it’s safe to expose a public API.

On the client, the API key is specified by the header `x-api-key`.

For example, if your `API_KEY` is `'ABC123'`, you can send a GraphQL query via `curl` as follows:

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

## AWS\$1LAMBDA authorization
<a name="aws-lambda-authorization"></a>

You can implement your own API authorization logic using an Amazon Lambda function. You can use a Lambda function for either your primary or secondary authorizer, but there may only be one Lambda authorization function per API. When using Lambda functions for authorization, the following applies:
+ If the API has the `AWS_LAMBDA` and `AWS_IAM` authorization modes enabled, then the SigV4 signature cannot be used as the `AWS_LAMBDA` authorization token.
+ If the API has the `AWS_LAMBDA` and `OPENID_CONNECT` authorization modes or the `AMAZON_COGNITO_USER_POOLS` authorization mode enabled, then the OIDC token cannot be used as the `AWS_LAMBDA` authorization token. Note that the OIDC token can be a Bearer scheme.
+ A Lambda function must not return more than 5MB of contextual data for resolvers.

For example, if your authorization token is `'ABC123'`, you can send a GraphQL query via curl as follows: 

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "Authorization:ABC123" -d '{ "query":
         "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

Lambda functions are called before each query or mutation. The return value can be cached based on the API ID and the authentication token. When a Lambda authorizer response is less than 1,048,576 bytes, Amazon AppSync caches the response for subsequent requests. If the Lambda authorizer response is equal to or greater than 1,048,576 bytes, Amazon AppSync doesn't cache the response and invokes the Lambda authorizer for each incoming request. To optimize performance and minimize Lambda invocation costs, we recommend that you limit your Lambda authorizer responses to 1,048,576 bytes. By default, caching is not turned on, but this can be enabled at the API level or by setting the `ttlOverride` value in a function's return value. 

A regular expression that validates authorization tokens before the function is called can be specified if desired. These regular expressions are used to validate that an authorization token is of the correct format before your function is called. Any request using a token which does not match this regular expression will be denied automatically. 

Lambda functions used for authorization require a principal policy for `appsync.amazonaws.com` to be applied on them to allow Amazon AppSync to call them. This action is done automatically in the Amazon AppSync console; The Amazon AppSync console does *not* remove the policy. For more information on attaching policies to Lambda functions, see [Resource-based policies](https://docs.amazonaws.cn/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) in the Amazon Lambda Developer Guide. 

The Lambda function you specify will receive an event with the following shape:

```
{
    "authorizationToken": "ExampleAUTHtoken123123123",
    "requestContext": {
        "apiId": "aaaaaa123123123example123",
        "accountId": "111122223333",
        "requestId": "f4081827-1111-4444-5555-5cf4695f339f",
        "queryString": "mutation CreateEvent {...}\n\nquery MyQuery {...}\n",
        "operationName": "MyQuery",
        "variables": {}
    }
    "requestHeaders": {
        application request headers
    }
}
```

The `event` object contains the headers that were sent in the request from the application client to Amazon AppSync.

The authorization function must return at least `isAuthorized`, a boolean indicating if the request is authorized. Amazon AppSync recognizes the following keys returned from Lambda authorization functions:

**Note**  
The value for the `operationName` in the `requestContext` for a WebSocket connect operation is set by Amazon AppSync to "`DeepDish:Connect`".

### Functions list
<a name="aws-lambda-authorization-list"></a>

`isAuthorized` (boolean, required)  
A boolean value indicating if the value in `authorizationToken` is authorized to make calls to the GraphQL API.  
If this value is true, execution of the GraphQL API continues. If this value is false, an `UnauthorizedException` is raised

`deniedFields` (list of string, optional)  
A list of which are forcibly changed to `null`, even if a value was returned from a resolver.  
Each item is either a fully qualified field ARN in the form of `arn:aws-cn:appsync:us-east-1:111122223333:apis/GraphQLApiId/types/TypeName/fields/FieldName` or a short form of `TypeName.FieldName`. The full ARN form should be used when two APIs share a Lambda function authorizer and there might be ambiguity between common types and fields between the two APIs.

`resolverContext` (JSON Object, optional)  
A JSON object visible as `$ctx.identity.resolverContext` in resolver templates. For example, if the following structure is returned by a resolver:  

```
{
  "isAuthorized":true
  "resolverContext": {
    "banana":"very yellow",
    "apple":"very green" 
  }
}
```
The value of `ctx.identity.resolverContext.apple` in resolver templates will be "`very green`". The `resolverContext` object only supports key-value pairs. Nested keys are not supported.  
The total size of this JSON object must not exceed 5MB.

`ttlOverride` (integer, optional)  
The number of seconds that the response should be cached for. If no value is returned, the value from the API is used. If this is 0, the response is not cached.

Lambda authorizers have a standard timeout of 10 seconds but may time out earlier under peak traffic conditions. We recommend designing functions to execute in the shortest amount of time as possible (under 1s) to scale the performance of your API.

Multiple Amazon AppSync APIs can share a single authentication Lambda function. Cross account authorizer use is not permitted.

When sharing an authorization function between multiple APIs, be aware that short-form field names (`typename.fieldname`) may inadvertently hide fields. To disambiguate a field in `deniedFields`, you can specify an unambiguous field ARN in the form of `arn:aws-cn:appsync:region:accountId:apis/GraphQLApiId/types/typeName/fields/fieldName`. 

To add a Lambda function as the default authorization mode in Amazon AppSync:

------
#### [ Console ]

1. Log into the Amazon AppSync Console and navigate to the API you wish to update.

1. Navigate to the Settings page for your API.

   Change the API-Level authorization to **Amazon Lambda**.

1. Choose the Amazon Web Services Region and Lambda ARN to authorize API calls against.
**Note**  
The appropriate principal policy will be added automatically, allowing Amazon AppSync to call your Lambda function. 

1. Optionally, set the response TTL and token validation regular expression.

------
#### [ Amazon CLI ]

1. Attach the following policy to the Lambda function being used:

   ```
   aws lambda add-permission --function-name "my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction --output text 
   ```
**Important**  
If you want the policy of the function to be locked to a single GraphQL API, you can run this command:  

   ```
   aws lambda add-permission --function-name “my-function” --statement-id “appsync” --principal appsync.amazonaws.com --action lambda:InvokeFunction --source-arn “<my AppSync API ARN>” --output text
   ```

1. Update your Amazon AppSync API to use the given Lambda function ARN as the authorizer:

   ```
   aws appsync update-graphql-api --api-id example2f0ur2oid7acexample --name exampleAPI --authentication-type AWS_LAMBDA --lambda-authorizer-config authorizerUri="arn:aws:lambda:us-east-2:111122223333:function:my-function"
   ```
**Note**  
You can also include other configuration options such as the token regular expression. 

------

The following example describes a Lambda function that demonstrates the various authentication and failure states a Lambda function can have when used as a Amazon AppSync authorization mechanism:

```
def handler(event, context):
  # This is the authorization token passed by the client
  token = event.get('authorizationToken')
  # If a lambda authorizer throws an exception, it will be treated as unauthorized. 
  if 'Fail' in token:
    raise Exception('Purposefully thrown exception in Lambda Authorizer.')

  if 'Authorized' in token and 'ReturnContext' in token:
    return {
      'isAuthorized': True,
      'resolverContext': {
        'key': 'value'
      }
    }

  # Authorized with no f
  if 'Authorized' in token:
    return {
      'isAuthorized': True
    }
  # Partial authorization
  if 'Partial' in token:
    return {
      'isAuthorized': True,
      'deniedFields':['user.favoriteColor']
    }
  if 'NeverCache' in token:
    return {
      'isAuthorized': True,
      'ttlOverride': 0
    }
  if 'Unauthorized' in token:
    return {
      'isAuthorized': False
    }
  # if nothing is returned, then the authorization fails. 
  return {}
```

### Circumventing SigV4 and OIDC token authorization limitations
<a name="aws-lambda-authorization-create-new-auth-token"></a>

The following methods can be used to circumvent the issue of not being able to use your SigV4 signature or OIDC token as your Lambda authorization token when certain authorization modes are enabled.

If you want to use the SigV4 signature as the Lambda authorization token when the `AWS_IAM` and `AWS_LAMBDA` authorization modes are enabled for Amazon AppSync's API, do the following:
+ To create a new Lambda authorization token, add random suffixes and/or prefixes to the SigV4 signature.
+ To retrieve the original SigV4 signature, update your Lambda function by removing the random prefixes and/or suffixes from the Lambda authorization token. Then, use the original SigV4 signature for authentication.

If you want to use the OIDC token as the Lambda authorization token when the `OPENID_CONNECT` authorization mode or the `AMAZON_COGNITO_USER_POOLS` and `AWS_LAMBDA` authorization modes are enabled for Amazon AppSync's API, do the following:
+ To create a new Lambda authorization token, add random suffixes and/or prefixes to the OIDC token. The Lambda authorization token should not contain a Bearer scheme prefix.
+ To retrieve the original OIDC token, update your Lambda function by removing the random prefixes and/or suffixes from the Lambda authorization token. Then, use the original OIDC token for authentication.

## AWS\$1IAM authorization
<a name="aws-iam-authorization"></a>

This authorization type enforces the [Amazon signature version 4 signing process](https://docs.amazonaws.cn/general/latest/gr/signature-version-4.html) on the GraphQL API. You can associate Identity and Access Management ([IAM](http://www.amazonaws.cn/iam/)) access policies with this authorization type. Your application can leverage this association by using an access key (which consists of an access key ID and secret access key) or by using short-lived, temporary credentials provided by Amazon Cognito Federated Identities.

If you want a role that has access to perform all data operations:

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/*"
         ]
      }
   ]
}
```

------

You can find `YourGraphQLApiId` from the main API listing page in the AppSync console, directly under the name of your API. Alternatively you can retrieve it with the CLI: `aws appsync list-graphql-apis` 

If you want to restrict access to just certain GraphQL operations, you can do this for the root `Query`, `Mutation`, and `Subscription` fields.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-1>",
            "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-2>",
            "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Mutation/fields/<Field-1>",
            "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Subscription/fields/<Field-1>"
         ]
     }
   ]
}
```

------

For example, suppose you have the following schema and you want to restrict access to getting all posts:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
```

The corresponding IAM policy for a role (that you could attach to an Amazon Cognito identity pool, for example) would look like the following:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
            "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws-cn:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/posts"
            ]
        }
    ]
}
```

------

## OPENID\$1CONNECT authorization
<a name="openid-connect-authorization"></a>

This authorization type enforces [OpenID connect](https://openid.net/specs/openid-connect-core-1_0.html) (OIDC) tokens provided by an OIDC-compliant service. Your application can leverage users and privileges defined by your OIDC provider for controlling access.

An Issuer URL is the only required configuration value that you provide to Amazon AppSync (for example, `https://auth.example.com`). This URL must be addressable over HTTPS. Amazon AppSync appends `/.well-known/openid-configuration` to the issuer URL and locates the OpenID configuration at `https://auth.example.com/.well-known/openid-configuration` per the [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) specification. It expects to retrieve an [RFC5785](https://tools.ietf.org/html/rfc5785) compliant JSON document at this URL. This JSON document must contain a `jwks_uri` key, which points to the JSON Web Key Set (JWKS) document with the signing keys. Amazon AppSync requires the JWKS to contain JSON fields of `kty` and `kid`.

Amazon AppSync supports a wide range of signing algorithms.


| Signing algorithms | 
| --- | 
| RS256 | 
| RS384 | 
| RS512 | 
| PS256 | 
| PS384 | 
| PS512 | 
| HS256 | 
| HS384 | 
| HS512 | 
| ES256 | 
| ES384 | 
| ES512 | 

We recommend that you use the RSA algorithms. Tokens issued by the provider must include the time at which the token was issued (`iat`) and may include the time at which it was authenticated (`auth_time`). You can provide TTL values for issued time (`iatTTL`) and authentication time (`authTTL`) in your OpenID Connect configuration for additional validation. If your provider authorizes multiple applications, you can also provide a regular expression (`clientId`) that is used to authorize by client ID. When the `clientId` is present in your OpenID Connect configuration, Amazon AppSync validates the claim by requiring the `clientId` to match with either the `aud` or `azp` claim in the token.

To validate multiple client IDs use the pipeline operator (“\$1”) which is an “or” in regular expression. For example, if your OIDC application has four clients with client IDs such as 0A1S2D, 1F4G9H, 1J6L4B, 6GS5MG, to validate only the first three client IDs, you would place 1F4G9H\$11J6L4B\$16GS5MG in the client ID field.

If an API is configured with multiple authorization types, Amazon AppSync validates the issuer (iss claim) present in the JWT token from request headers by comparing it against the issuer URL specified in the API configuration. However, when an API is configured with only OPENID\$1CONNECT authorization, Amazon AppSync skips this issuer URL validation step.

## AMAZON\$1COGNITO\$1USER\$1POOLS authorization
<a name="amazon-cognito-user-pools-authorization"></a>

This authorization type enforces OIDC tokens provided by Amazon Cognito User Pools. Your application can leverage the users and groups in both your user pools and user pools from another Amazon account and associate these with GraphQL fields for controlling access.

When using Amazon Cognito User Pools, you can create groups that users belong to. This information is encoded in a JWT token that your application sends to Amazon AppSync in an authorization header when sending GraphQL operations. You can use GraphQL directives on the schema to control which groups can invoke which resolvers on a field, thereby giving more controlled access to your customers.

For example, suppose you have the following GraphQL schema:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
...
```

If you have two groups in Amazon Cognito User Pools - bloggers and readers - and you want to restrict the readers so that they cannot add new entries, then your schema should look like this:

```
schema {
   query: Query
   mutation: Mutation
}
```

```
type Query {
   posts:[Post!]!
   @aws_auth(cognito_groups: ["Bloggers", "Readers"])
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
   @aws_auth(cognito_groups: ["Bloggers"])
}
...
```

Note that you can omit the `@aws_auth` directive if you want to default to a specific grant-or-deny strategy on access. You can specify the grant-or-deny strategy in the user pool configuration when you create your GraphQL API via the console or via the following CLI command:

```
$ aws appsync --region us-west-2 create-graphql-api --authentication-type AMAZON_COGNITO_USER_POOLS  --name userpoolstest --user-pool-config '{ "userPoolId":"test", "defaultEffect":"ALLOW", "awsRegion":"us-west-2"}'
```

## Using additional authorization modes
<a name="using-additional-authorization-modes"></a>

When you add additional authorization modes, you can directly configure the authorization setting at the Amazon AppSync GraphQL API level (that is, the `authenticationType` field that you can directly configure on the `GraphqlApi` object) and it acts as the default on the schema. This means that any type that doesn’t have a specific directive has to pass the API level authorization setting.

At the schema level, you can specify additional authorization modes using directives on the schema. You can specify authorization modes on individual fields in the schema. For example, for `API_KEY` authorization you would use `@aws_api_key` on schema object type definitions/fields. The following directives are supported on schema fields and object type definitions:
+  `@aws_api_key` - To specify the field is `API_KEY` authorized.
+  `@aws_iam` - To specify that the field is `AWS_IAM` authorized.
+  `@aws_oidc` - To specify that the field is `OPENID_CONNECT` authorized.
+  `@aws_cognito_user_pools` - To specify that the field is `AMAZON_COGNITO_USER_POOLS` authorized.
+  `@aws_lambda` - To specify that the field is `AWS_LAMBDA` authorized.

You can’t use the `@aws_auth` directive along with additional authorization modes. `@aws_auth` works only in the context of `AMAZON_COGNITO_USER_POOLS` authorization with no additional authorization modes. However, you can use the `@aws_cognito_user_pools` directive in place of the `@aws_auth` directive, using the same arguments. The main difference between the two is that you can specify `@aws_cognito_user_pools` on any field and object type definitions.

To understand how the additional authorization modes work and how they can be specified on a schema, let’s have a look at the following schema:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   getPost(id: ID): Post
   getAllPosts(): [Post]
   @aws_api_key
}

type Mutation {
   addPost(
      id: ID!
      author: String!
      title: String!
      content: String!
      url: String!
   ): Post!
}

type Post @aws_api_key @aws_iam {
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
}
...
```

For this schema, assume that `AWS_IAM` is the default authorization type on the Amazon AppSync GraphQL API. This means that fields that don’t have a directive are protected using `AWS_IAM`. For example, that’s the case for the `getPost` field on the `Query` type. Schema directives enable you to use more than one authorization mode. For example, you can have `API_KEY` configured as an additional authorization mode on the Amazon AppSync GraphQL API, and you can mark a field using the `@aws_api_key` directive (for example, `getAllPosts` in this example). Directives work at the field level so you need to give `API_KEY` access to the `Post` type too. You can do this either by marking each field in the `Post` type with a directive, or by marking the `Post` type with the `@aws_api_key` directive.

To further restrict access to fields in the `Post` type you can use directives against individual fields in the `Post` type as shown following.

For example, you can add a `restrictedContent` field to the `Post` type and restrict access to it by using the `@aws_iam` directive. `AWS_IAM` authenticated requests could access `restrictedContent`, however, `API_KEY` requests wouldn’t be able to access it.

```
type Post @aws_api_key @aws_iam{
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
   restrictedContent: String!
   @aws_iam
}
...
```

## Fine-grained access control
<a name="fine-grained-access-control"></a>

The preceding information demonstrates how to restrict or grant access to certain GraphQL fields. If you want to set access controls on the data based on certain conditions (for example, based on the user that’s making a call and whether the user owns the data) you can use mapping templates in your resolvers. You can also perform more complex business logic, which we describe in [Filtering Information](#aws-appsync-filtering-information).

This section shows how to set access controls on your data using a DynamoDB resolver mapping template.

Before proceeding any further, if you’re not familiar with mapping templates in Amazon AppSync, you may want to review the [Resolver mapping template reference](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference) and the [Resolver mapping template reference for DynamoDB](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb).

In the following example using DynamoDB, suppose you’re using the preceding blog post schema, and only users that created a post are allowed to edit it. The evaluation process would be for the user to gain credentials in their application, using Amazon Cognito User Pools for example, and then pass these credentials as part of a GraphQL operation. The mapping template will then substitute a value from the credentials (like the username)in a conditional statement which will then be compared to a value in your database.

![\[Four-step workflow showing token retrieval, request sending, conditional check, and operation execution.\]](http://docs.amazonaws.cn/en_us/appsync/latest/devguide/images/FGAC.png)


To add this functionality, add a GraphQL field of `editPost` as follows:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   editPost(id:ID!, title:String, content:String):Post
   addPost(id:ID!, title:String!):Post!
}
...
```

The resolver mapping template for `editPost` (shown in an example at the end of this section) needs to perform a logical check against your data store to allow only the user that created a post to edit it. Since this is an edit operation, it corresponds to an `UpdateItem` in DynamoDB. You can perform a conditional check before performing this action, using context passed through for user identity validation. This is stored in an `Identity` object that has the following values:

```
{
   "accountId" : "12321434323",
   "cognitoIdentityPoolId" : "",
   "cognitoIdentityId" : "",
   "sourceIP" : "",
   "caller" : "ThisistheprincipalARN",
   "username" : "username",
   "userArn" : "Sameasabove"
}
```

To use this object in a DynamoDB`UpdateItem` call, you need to store the user identity information in the table for comparison. First, your `addPost` mutation needs to store the creator. Second, your `editPost` mutation needs to perform the conditional check before updating.

Here is an example of the resolver code for `addPost` that stores the user identity as an `Author` column:

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id: postId, ...item } = ctx.args;
	return put({
		key: { postId },
		item: { ...item, Author: ctx.identity.username },
		condition: { postId: { attributeExists: false } },
	});
}

export const response = (ctx) => ctx.result;
```

Note that the `Author` attribute is populated from the `Identity` object, which came from the application.

Finally, here is an example of the resolver code for `editPost`, which only updates the content of the blog post if the request comes from the user that created the post:

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id, ...item } = ctx.args;
	return put({
		key: { id },
		item,
		condition: { author: { contains: ctx.identity.username } },
	});
}

export const response = (ctx) => ctx.result;
```

This example uses a `PutItem` that overwrites all values rather than an `UpdateItem`, but the same concept applies on the `condition` statement block.

## Filtering information
<a name="aws-appsync-filtering-information"></a>

There may be cases where you cannot control the response from your data source, but you don’t want to send unnecessary information to clients on a successful write or read to the data source. In these cases, you can filter information by using a response mapping template.

For example, suppose you don’t have an appropriate index on your blog post DynamoDB table (such as an index on `Author`). You could use the following resolver:

```
import { util, Context } from '@aws-appsync/utils';
import { get } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	return get({ key: { ctx.args.id } });
}

export function response(ctx) {
	if (ctx.result.author === ctx.identity.username) {
		return ctx.result;
	}
	return null;
}
```

The request handler fetches the item even if the caller isn’t the author who created the post. To prevent this from returning all data, the response handler checks to make sure the caller matches the item’s author. If the caller doesn’t match this check, only a null response is returned.

## Data source access
<a name="data-source-access"></a>

Amazon AppSync communicates with data sources using Identity and Access Management ([IAM](http://www.amazonaws.cn/iam/)) roles and access policies. If you are using an existing role, a Trust Policy needs to be added in order for Amazon AppSync to assume the role. The trust relationship will look like below:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

------

It’s important to scope down the access policy on the role to only have permissions to act on the minimal set of resources necessary. When using the AppSync console to create a data source and create a role, this is done automatically for you. However when using a built in sample template from the IAM console to create a role outside of the Amazon AppSync console the permissions will not be automatically scoped down on a resource and you should perform this action before moving your application to production.