Using Amazon Cognito Tokens for Fine-Grained Access Control


Summary

My team at AWS worked on this integration between Amazon Verified Permissions and Cognito.

Puzzle pieces

Earlier this month Amazon launched Amazon Verified Permissions, a "scalable permissions management and fine-grained authorization service for the applications that you build." Verified Permissions has been in gated preview since November, but now it's available to everyone.

My team worked on an integration between Verified Permissions and Amazon Cognito, Amazon's OpenID Connect service. The idea is pretty simple: if you're using Cognito to manage the people who use your application, then you will likely want to use the information that is stored in Cognito for your access control policies.

Our bit of code allows developers to just submit the tokens they get back from Cognito as a result of the authentication process to Verified Permissions. Verified Permissions uses the attributes they contain to perform a policy evaluation. I wrote a blog post for the AWS Security blog about how this works called Simplify fine-grained authorization with Amazon Verified Permissions and Amazon Cognito. I'll describe the basic idea here, but the blog post has details and links.

Suppose you've got a policy that allows anyone to view any resource so long as their location is USA:

permit(
  principal,
  action == Action::"view",
  resource
)
when {principal.location == "USA"};

If Alice wants to view VacationPhoto94.jpg, then your call to Verified Permissions might look like this if you're not using the Cognito Token:

//JS pseudocode
const authResult = await avp.isAuthorized({
    principal: 'User::"alice"',
    action: 'Action::"view"',
    resource: 'Photo::"VacationPhoto94.jpg"',
    // whenever our policy references attributes of the entity, isAuthorized 
    // needs an entity argument that provides those attributes
    entities: [
        {
            "identifier": {
                "entityType": "User",
                "entityId": "alice"
            },
            "attributes": {
                "location": {
                    "String": "USA"
                }
            }
        ]
});

You have to supply information about the principal and any relevant attributes so the policy has the context it needs to evaluate correctly. Now, suppose your Cognito token contains location information as an attribute:

{
 ...
 “iss”: “User”,
 “sub”: “alice”,
 “custom:location”: “USA”,
 ...
}

Assuming the token is stored in a variable named cognito_id_token you can make a call like this:

const authResult = await avp.isAuthorizedWithToken({
    identity_token: cognito_id_token
    action: 'Action::"view"',
    resource: 'Photo::"VacationPhoto94.jpg"'
});

Using isAuthorizedWithToken, you don’t have to supply the principal or construct the entities argument. Pretty slick.

Take a look at the blog post I mentioned earlier if you're interested in using this in your application. There's more information about the configuration process and how to add resource attributes to the call. This was a fun project.


Photo Credit: Puzzle Pieces from Erdenebayar (Pixabay Content License)


Please leave comments using the Hypothes.is sidebar.

Last modified: Mon Jun 26 21:04:15 2023.