Verified Permissions with Cognito and API Gateway

Overview

Use Amazon Verified Permissions (AVP) with Amazon Cognito groups to authorize API Gateway requests. Policies in Cedar define which user pool groups can call which routes.

ComponentRole
Cognito User PoolUsers, groups, JWT access tokens
API GatewayREST routes with authorizer
Verified PermissionsPolicy store, Cedar permit rules

Reference: Amazon Verified Permissions


Users and groups

UserGroup
admin@example.comadmins
alice@example.com-
bob@example.comemployee

Groups: admins, employee


API Gateway routes

API: prod

MethodPathWho can access
GET/privateadmins, or users not in admins or employee
GET/private/adminsadmins only
GET/private/employeesadmins and employee
prod
 └── /
      └── private
            ├── GET  /private
            ├── GET  /private/admins
            └── GET  /private/employees

Verified Permissions setup

1. Register API actions

Console: AVP → Policy store → Schema → Actions

Create actions that map to API Gateway operations:

Action namePrincipal typesResource types
get /privateUserApplication
post /privateUserApplication
get /private/adminsUserApplication
get /private/employeesUserApplication

Example action: post /private - applies to principal type User, resource type Application.

Replace us-east-1_du9KuRt50 in policies below with your User Pool ID.

2. Create Cedar policies

Console: AVP → Policy store → Policies → Create policy

Policy 1 - Users outside admins and employee

Allow GET and POST on /private when the principal is in neither group.

permit(
  principal,
  action in [
    cognitoauth::Action::"get /private",
    cognitoauth::Action::"post /private"
  ],
  resource
)
when {
  !(principal in cognitoauth::UserGroup::"us-east-1_du9KuRt50|employee") &&
  !(principal in cognitoauth::UserGroup::"us-east-1_du9KuRt50|admins")
};

Policy 2 - Users in admins

Allow GET on /private/admins and /private/employees.

permit(
  principal in cognitoauth::UserGroup::"us-east-1_du9KuRt50|admins",
  action in [
    cognitoauth::Action::"get /private",
    cognitoauth::Action::"get /private/admins",
    cognitoauth::Action::"get /private/employees"
  ],
  resource
);

Add a separate policy for the employee group on get /private/employees if employees should access that route without being admins.


Testing

Generate a Cognito access token

App client settings

  • Authentication flow: ALLOW_USER_PASSWORD_AUTH

Token request

FieldValue
URLhttps://cognito-idp.us-east-1.amazonaws.com/us-east-1_du9KuRt50
MethodPOST

Headers:

Content-Type: application/x-amz-json-1.1
X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth

Body:

{
  "AuthFlow": "USER_PASSWORD_AUTH",
  "ClientId": "3csb2ppugj180apt0pabrl52v3",
  "AuthParameters": {
    "USERNAME": "admin@example.com",
    "PASSWORD": "Test@123"
  },
  "ClientMetadata": {}
}

Use the AccessToken from the response (not the ID token) when calling API Gateway with a Cognito/AVP authorizer.

Call API Gateway

Attach the authorizer to the API, then send:

Authorization: <AccessToken>

Test each user (admin@example.com, alice@example.com, bob@example.com) against /private, /private/admins, and /private/employees to confirm allow/deny matches the Cedar policies.


Notes

  • Policy 2 label in raw notes said “employee” but the Cedar policy uses the admins group - the policy above matches the Cedar snippet.
  • Group ARN format: cognitoauth::UserGroup::"<region>_<userPoolId>|<groupName>".
  • Action names must match the schema action strings exactly (method + path).
  • Replace ClientId, User Pool ID, and passwords with your environment values before testing.