Page updated Nov 29, 2023

Customize your auth rules

Use the .authorization() modifier to configure authorization rules for public, signed-in user, per user, and per user group data access. Authorization rules operate on the deny-by-default principle. Meaning that if an authorization rule is not specifically configured, it is denied.

export const schema = a.schema({ Post: a.model({ content: a.string() }).authorization([ // Allow anyone auth'd with an API key to read everyone's posts. a.allow.public().to(['read']), // Allow signed-in user to create, read, update, // and delete their __OWN__ posts. a.allow.owner(), ]) })
1export const schema = a.schema({
2 Post: a.model({
3 content: a.string()
4 }).authorization([
5 // Allow anyone auth'd with an API key to read everyone's posts.
6 a.allow.public().to(['read']),
7 // Allow signed-in user to create, read, update,
8 // and delete their __OWN__ posts.
9 a.allow.owner(),
10 ])
11})

In the example above, everyone (public) can read every Post but authenticated users (owner) can create, read, update, and delete their own posts. Amplify also allows you to restrict the allowed operations, combine multiple authorization rules, and apply fine-grained field-level authorization.

Available authorization strategies

Use the guide below to select the correct authorization strategy for your use case:

Recommended use caseStrategyProvider
Public data access where users or devices are anonymous. Anyone with the AppSync API key is granted access.publicapiKey
Recommended for production environment's public data access. Public data access where unauthenticated users or devices are granted permissions using AWS IAM controls.publiciam
Per user data access. Access is restricted to the "owner" of a record. Leverages amplify/auth/resource.ts Cognito user pool by default.owneruserPools / oidc
Any signed-in data access. Unlike owner-based access, any signed-in user has access.privateuserPools / oidc / iam
Per user group data access. A specific or dynamically configured group of users has access.groupuserPools / oidc
Define your own custom authorization rule within a serverless function.customfunction

Understand how authorization rules are applied

Authorization rules can be applied globally across all data models in a schema, onto specific data models, and onto specific fields.

Amplify will always use the most specific authorization rule that is available. For example, if there is an authorization rule for a field and an authorization rule for the model that the field belongs to, Amplify will evaluate against the field-level authorization rule. Review Field-level authorization rules to learn more.

If there are multiple authorization rules present, they will be logically OR'ed. Review Configure multiple authorization rules to learn more.

Finally, there are special "Admin IAM Roles" that allow you to overrule any authorization logic applied on the API and determine the API access completely via its IAM policy.

Global authorization rule (only for getting started)

To help you get started, you can define an authorization rule on the data schema that will be applied to all data models that do not have a model-level authorization rule. Instead of having a global authorization rule for all production environments, we recommend creating specific authorization rules for each model or field.

The global authorization rule below uses a.allow.public(). This example allows anyone to create, read, update, and delete and is applied to every data model.

export const schema = a.schema({ // Because no model-level authorization rule is present // this model will use the global authorization rule. Todo: a.model({ content: a.string() }), // Will use model-level authorization rule Notes: a.model({ content: a.string() // [Model-level authorization rule] }).authorization([a.allow.public().to(['read'])]) // [Global authorization rule] }).authorization([ a.allow.public() ])
1export const schema = a.schema({
2 // Because no model-level authorization rule is present
3 // this model will use the global authorization rule.
4 Todo: a.model({
5 content: a.string()
6 }),
7
8 // Will use model-level authorization rule
9 Notes: a.model({
10 content: a.string()
11 // [Model-level authorization rule]
12 }).authorization([a.allow.public().to(['read'])])
13
14// [Global authorization rule]
15}).authorization([
16 a.allow.public()
17])

Model-level authorization rules

Add an authorization rule to a model to apply the authorization rule to all fields of that model.

export const schema = a.schema({ Post: a.model({ content: a.string(), createdBy: a.string() // [Model-level authorization rule] // All fields (content, createdBy) will be protected by // this authorization rule }).authorization([ a.allow.public().to(['read']), a.allow.owner(), ]) })
1export const schema = a.schema({
2 Post: a.model({
3 content: a.string(),
4 createdBy: a.string()
5 // [Model-level authorization rule]
6 // All fields (content, createdBy) will be protected by
7 // this authorization rule
8 }).authorization([
9 a.allow.public().to(['read']),
10 a.allow.owner(),
11 ])
12})

Field-level authorization rules

When an authorization rule is added to a field, it will strictly define the authorization rules applied on the field. Field-level authorization rules do not inherit model-level authorization rules. Meaning, only the specified field-level authorization rule is applied.

In the example below:

  • Owners are allowed to create, read, update, and delete Employee records they own
  • Any signed in user has read access and can read data with the exception of the ssn field
  • Only the ssn field has owner auth applied and this field-level auth rule means that model-level auth rules are not applied
export const schema = a.schema({ Employee: a.model({ name: a.string(), email: a.string(), // [Field-level authorization rule] // This auth rule will be used for the "ssn" field // All other fields will use the model-level auth rule ssn: a.string().authorization([a.allow.owner()]), }) // [Model-level authorization rule] .authorization([ a.allow.private().to(["read"]), a.allow.owner() ]), });
1export const schema = a.schema({
2 Employee: a.model({
3 name: a.string(),
4 email: a.string(),
5 // [Field-level authorization rule]
6 // This auth rule will be used for the "ssn" field
7 // All other fields will use the model-level auth rule
8 ssn: a.string().authorization([a.allow.owner()]),
9 })
10
11 // [Model-level authorization rule]
12 .authorization([
13 a.allow.private().to(["read"]),
14 a.allow.owner()
15 ]),
16});

Configure multiple authorization rules

When combining multiple authorization rules, they are "logically OR"-ed. In the following example:

  • Any user (signed in or not, verified by IAM) is allowed to read all posts
  • Owners are allowed to create, read, update, and delete their own posts
export const schema = a.schema({ Post: a.model({ title: a.string(), content: a.string() }).authorization([ a.allow.public("iam").to(["read"]), a.allow.owner() ]) })
1export const schema = a.schema({
2 Post: a.model({
3 title: a.string(),
4 content: a.string()
5 }).authorization([
6 a.allow.public("iam").to(["read"]),
7 a.allow.owner()
8 ])
9})

On the client side, make sure to always authenticate with the corresponding authorization mode.

import { generateClient } from 'aws-amplify/data' import type { Schema } from '@/backend/data/resource' // Path to your backend resource definition const client = generateClient<Schema>() // Creating a post is restricted to Cognito User Pools const { data: newPostResult , errors } = await client.models.Post.create({ query: queries.createPost, variables: { input: { title: 'Hello World' } }, authMode: 'userPool', }); // Listing posts is available to all users (verified by IAM) const { data: listPostsResult , errors } = await client.models.Post.list({ query: queries.listPosts, authMode: 'iam', });
1import { generateClient } from 'aws-amplify/data'
2import type { Schema } from '@/backend/data/resource' // Path to your backend resource definition
3
4const client = generateClient<Schema>()
5
6// Creating a post is restricted to Cognito User Pools
7const { data: newPostResult , errors } = await client.models.Post.create({
8 query: queries.createPost,
9 variables: { input: { title: 'Hello World' } },
10 authMode: 'userPool',
11});
12
13// Listing posts is available to all users (verified by IAM)
14const { data: listPostsResult , errors } = await client.models.Post.list({
15 query: queries.listPosts,
16 authMode: 'iam',
17});

Learn more about specific authorization strategies