Owner vs. Group Access Control in AWS Amplify API

Daniel Dantas (@dantasfiles)
4 min readJan 8, 2020

--

This post compares the behavior of owner access control with group access control in the AWS Amplify API.

To add access control to your API, you add access control annotations to your GraphQL schema in amplify\backend\api\APINAME\schema.graphql
Owner access control has the form @auth(rules: [{allow: owner, ...owner access control settings...}])
Group access control has the form @auth(rules: [{allow: groups, ...group access control settings...}])
AWS Amplify then takes your access control specification and generates resolvers that contain the access control code to enforce your specification.

There are good explanations of how this works in practice in the AWS Amplify docs, but I wanted to think about the owner and group access control more abstractly. By doing that, you can think of owner and group access control as abstract foundations on which you can build a whole spectrum of access control policies, like multi-tenancy. As such, it’s useful to understand the similarities and differences between owner and group access control before starting to build.

Owner access control

Owner access control has the following form @auth(rules: [{allow: owner, ownerField: "fieldName", identityClaim: "claimName"}])

As specified in the AWS Amplify documentation, “each object has an ownerField (by default ‘owner’) that stores ownership information.” To specify that a single user should have access, use an ownerField of type String. To specify that multiple users should have access, use an ownerField of type [String]

IThe identityClaim specifies a field, assumed to contain a scalar value like a string, in the user’s access token. By default this is the username field in the access token.

To think of it abstractly, if the value in the identityClaim field of the user’s access token matches any of the values in the ownerField field of the object to be accessed, the user is authorized.

Group access control

Group access control has the following form @auth(rules: [{allow: groups, groupsField: "fieldName", groupClaim: "claimName"}])

As specified in the documentation, “With dynamic group authorization, each record contains an attribute specifying what groups should be able to access it. Use the groupsField argument to specify which attribute in the underlying data store holds this group information. To specify that a single group should have access, use a field of type String. To specify that multiple groups should have access, use a field of type [String]

The groupClaim specifies a field, assumed to be a list of values, in the user’s access token. By default this is the cognito:groups list in the access token, which contains the list of AWS Cognito groups the user belongs to.

A subtlety is that that AWS Cognito custom attributes can only be a string or a number (not a list of strings). So if you use a custom attribute as your groupClaim, the generated access control code will first parse the string into a list using the $util.parseJson function. So the string in your custom attribute should look like '["value1", "value2",…]'

To think of it abstractly, if any of the values in the groupClaim field of the user’s access token match any of the values in the groupsField field of the object to be accessed, the user is authorized.

Queries, and Update & Delete Mutations

For GraphQL queries (getX and listX), and update & delete mutations, the primary difference between owner and group access control is that the user is assumed to have a scalar value in identityClaim (a user can only have a single unique identifier), but a list of values in groupClaim(a user can be a member of multiple groups).

As such, for these operations, you can think of group access control as a generalization of owner access control, because you can emulate owner access control in group access control by converting the value in identityClaim to a single element list.

Create Mutations

For GraphQL create mutations, a major difference is that, in owner access control, if a create mutation operation does not specify a value for the ownerField in the object it is creating, the value from the identityClaim field in the access token (by default the username), is placed in the ownerField of the created object, and authorization is automatically approved.

There’s no analogous system for group access control because a groupClaim is a list of values. It wouldn’t be clear which of the elements of the list should be automatically placed in the groupsField if the user didn’t explicitly specify a value.

Summary

So when choosing between owner and group access control to build your final access control system on, keep the following two things in mind. Group access control is more generalized, because its claim can contain a list of values, not just a single value as in owner access control. But owner access control allows you to specify a default value during object creation.

--

--

Daniel Dantas (@dantasfiles)

I create guides to help me fully understand the issues that I’m encountering and fixing. Web: dantasfiles.com Email: daniel@dantasfiles.com