Data Authorization
Authorization rules determine who can access your data and what operations they can perform. Amplify provides powerful, declarative authorization.
Authorization Modes
Amplify supports several authorization modes:
| Mode | Description | Use Case |
|---|---|---|
userPool |
Cognito User Pool authentication | Authenticated users with Cognito |
iam |
AWS IAM authentication | Backend services, Lambda functions |
apiKey |
API Key authentication | Public data, quick prototyping |
oidc |
OpenID Connect provider | Third-party identity providers |
lambda |
Custom Lambda authorizer | Complex authorization logic |
Setting Default Authorization
// amplify/data/resource.ts
export const data = defineData({
schema,
authorizationModes: {
defaultAuthorizationMode: 'userPool',
// Optional: API key for public access
apiKeyAuthorizationMode: {
expiresInDays: 30,
},
},
});
Model-Level Authorization
Add authorization rules directly to your models:
const schema = a.schema({
Todo: a
.model({
content: a.string().required(),
completed: a.boolean().default(false),
})
.authorization((allow) => [
allow.owner(), // Only owner can CRUD
]),
});
Authorization Strategies
Owner-Based Authorization
The most common strategy. Each item has an owner, and only the owner can access it.
Todo: a
.model({
content: a.string().required(),
completed: a.boolean().default(false),
})
.authorization((allow) => [
allow.owner(),
])
This automatically:
- Adds an
ownerfield to store the user's identity - Sets the owner automatically when creating items
- Restricts access to only the owner
Specifying Operations
You can limit which operations are allowed:
Todo: a
.model({...})
.authorization((allow) => [
allow.owner().to(['create', 'read', 'update']),
// Owner can't delete
])
Available operations:
create– Create new itemsread– Read/list itemsupdate– Update existing itemsdelete– Delete items
Group-Based Authorization
Restrict access to users in specific Cognito groups:
// Only admins can manage categories
Category: a
.model({
name: a.string().required(),
description: a.string(),
})
.authorization((allow) => [
allow.group('admin'), // Full CRUD for admins
allow.authenticated().to(['read']), // Read for all authenticated users
])
Public Access
For public data (like a blog or product catalog):
Article: a
.model({
title: a.string().required(),
content: a.string().required(),
published: a.boolean().default(false),
})
.authorization((allow) => [
allow.guest().to(['read']), // Anyone can read
allow.group('editor').to(['create', 'read', 'update', 'delete']),
])
Public/guest access requires an API key authorization mode to be enabled in your data configuration.
Authenticated Users
Allow any authenticated user to access data:
// Shared todos - any signed-in user can see all
SharedTodo: a
.model({
content: a.string().required(),
completed: a.boolean().default(false),
})
.authorization((allow) => [
allow.authenticated().to(['read']), // All users can read
allow.owner().to(['create', 'update', 'delete']), // Only owner can modify
])
Multiple Authorization Rules
Combine rules for complex scenarios:
Post: a
.model({
title: a.string().required(),
content: a.string().required(),
status: a.enum(['DRAFT', 'PUBLISHED']),
})
.authorization((allow) => [
// Author has full access
allow.owner(),
// Editors can read and update any post
allow.group('editor').to(['read', 'update']),
// Admins have full access
allow.group('admin'),
// Public can only read
allow.guest().to(['read']),
])
Custom Owner Field
By default, the owner field is called "owner". Customize it:
Todo: a
.model({
content: a.string().required(),
createdBy: a.string(), // Custom owner field
})
.authorization((allow) => [
allow.ownerDefinedIn('createdBy'),
])
Field-Level Authorization
Restrict access to specific fields:
User: a
.model({
name: a.string().required(),
email: a.string().required(),
// Only owner can see/modify private notes
privateNotes: a.string().authorization((allow) => [
allow.owner(),
]),
// Only admins can modify role
role: a.string().authorization((allow) => [
allow.authenticated().to(['read']),
allow.group('admin').to(['read', 'update']),
]),
})
.authorization((allow) => [
allow.owner(),
allow.authenticated().to(['read']),
])
Complete Example
Here's a complete data resource with various authorization patterns:
// amplify/data/resource.ts
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
const schema = a.schema({
// Private todos - only owner can access
Todo: a
.model({
content: a.string().required(),
completed: a.boolean().default(false),
priority: a.enum(['LOW', 'MEDIUM', 'HIGH']),
dueDate: a.datetime(),
})
.authorization((allow) => [allow.owner()]),
// Categories managed by admins, readable by all
Category: a
.model({
name: a.string().required(),
color: a.string(),
icon: a.string(),
})
.authorization((allow) => [
allow.group('admin'),
allow.authenticated().to(['read']),
]),
// Public announcements
Announcement: a
.model({
title: a.string().required(),
content: a.string().required(),
publishedAt: a.datetime(),
})
.authorization((allow) => [
allow.group('admin'),
allow.guest().to(['read']),
]),
// Team projects with shared access
Project: a
.model({
name: a.string().required(),
description: a.string(),
teamMembers: a.string().array(),
})
.authorization((allow) => [
allow.owner(),
allow.ownersDefinedIn('teamMembers').to(['read', 'update']),
]),
});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({
schema,
authorizationModes: {
defaultAuthorizationMode: 'userPool',
apiKeyAuthorizationMode: {
expiresInDays: 30,
},
},
});
Testing Authorization
Test authorization rules by:
- Creating items as one user
- Signing in as a different user
- Attempting to access/modify the items
- Verifying that unauthorized operations fail
// This should fail if the user is not the owner
try {
await client.models.Todo.update({
id: 'someone-elses-todo',
completed: true,
});
} catch (error) {
console.log('Unauthorized - as expected!');
}
Summary
- Authorization is defined at the model and field level
allow.owner()– Restrict to item ownerallow.group('name')– Restrict to Cognito group membersallow.authenticated()– Allow any signed-in userallow.guest()– Allow public access (requires API key)- Use
.to(['read', 'create'])to limit operations - Combine multiple rules for complex authorization
You now know how to define data models, perform CRUD operations, and secure your data with authorization rules. In the next module, we'll cover deploying your application to production.