<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniel Aniszkiewicz</title>
    <description>The latest articles on Forem by Daniel Aniszkiewicz (@pigius).</description>
    <link>https://forem.com/pigius</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F962533%2Fa72f21f3-0848-4362-973d-1a042c909cbc.jpeg</url>
      <title>Forem: Daniel Aniszkiewicz</title>
      <link>https://forem.com/pigius</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pigius"/>
    <language>en</language>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XVI: AVP meets new pricing</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Fri, 13 Jun 2025 16:44:37 +0000</pubDate>
      <link>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xvi-avp-meets-49jf</link>
      <guid>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xvi-avp-meets-49jf</guid>
      <description>&lt;p&gt;Hello there! Long time no see! Let's get back to our series about Amazon Verified Permissions!&lt;/p&gt;

&lt;p&gt;The last few months haven't brought much news in AVP, other than the addition of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/05/amazon-verified-permissions-policy-store-tagging/" rel="noopener noreferrer"&gt;tags&lt;/a&gt; (which should have been added a long time ago), but a few days before &lt;a href="https://reinforce.awsevents.com/" rel="noopener noreferrer"&gt;re:Inforce&lt;/a&gt;, we got a real game changer: a price change.&lt;/p&gt;

&lt;p&gt;As we know, AVP has many advantages, but the biggest drawback has always been the price. For a new service, this made it very difficult for customers to adopt. I've conducted many workshops, talks, and a large implementation around AVP, but this pricing has always been a pain point for many people.&lt;/p&gt;

&lt;p&gt;In this blog post, I want to share my perspective on the price change based on the use case I implemented with my team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap on pricing
&lt;/h2&gt;

&lt;p&gt;Until today, pricing looked like this: we paid for the number of authorization requests, and depending on how many requests we made, we had several tiers. The more requests you made, the less you paid per request (but this only made sense with a large number of requests).&lt;/p&gt;

&lt;p&gt;We also have a cost for Policy management requests, but it's a small cost for managing policy stores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkirv5ltihkbn9m4znlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkirv5ltihkbn9m4znlh.png" alt="Image description" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look at a 70 million requests scenario monthly (our current volume):&lt;/p&gt;

&lt;p&gt;First 40 million requests: 40,000,000 × $0.00015 = $6,000&lt;br&gt;
Next 30 million requests: 30,000,000 × $0.000075 = $2,250&lt;br&gt;
Total: $6,000 + $2,250 = $8,250 monthly =&amp;gt; $99,000 yearly&lt;/p&gt;

&lt;p&gt;Such a price can cause a big headache. Often in smaller companies, this is the entire annual AWS budget, not just for one authorization service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache?
&lt;/h2&gt;

&lt;p&gt;When talking about AVP with different people, the discussion always went to: "Well, okay, but we can always cache authorization decisions so we don't have to pay so much for AVP." And it's true - this is especially efficient if you have M2M flows with lots of repetitive requests in a short period.&lt;/p&gt;

&lt;p&gt;I presented our use case for AVP, handling authorization for 70 million API requests monthly. This consisted of traffic on API Gateway and monolithic apps - API calls only.&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://www.youtube.com/watch?v=QSwp6EJIR04&amp;amp;t=1s" rel="noopener noreferrer"&gt;Re:Invent 2024 presentation&lt;/a&gt;I presented our use case for AVP, handling authorization for 50 million API requests monthly (currently it's 70 million so in this blogpost I will focus on this number). This consisted of traffic on API Gateway and monolithic apps - API calls only.&lt;/p&gt;

&lt;p&gt;I also presented how we built the cache for AVP (API Gateway with its built-in cache mechanism, and how we built our own cache). You'll see that we cache up to 98% of requests when we have 70 million authorization requests per month (currently)!&lt;/p&gt;

&lt;p&gt;To be more precise:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total authz decisions:&lt;/strong&gt; 70.7M&lt;br&gt;
&lt;strong&gt;Direct AVP:&lt;/strong&gt; calls1.4M&lt;br&gt;
&lt;strong&gt;Cache hits:&lt;/strong&gt; 69.3M&lt;/p&gt;

&lt;p&gt;Unfortunately, AVP doesn't have a built-in cache option.&lt;br&gt;
If you use AVP in a Lambda authorizer attached to API Gateway, you can use the authorizer cache mechanism - just remember to set the correct cache keys! If you use it in a monolithic application, you have to build the cache yourself and understand the whole mechanism well. You can use Redis (whether it's ElastiCache Redis or Valkey on AWS). The cache isn't free, but the cost isn't huge either.&lt;/p&gt;

&lt;p&gt;Our current ElastiCache Setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple clusters (cache.t4g.micro, primary + replica = 2 nodes/cluster)&lt;/li&gt;
&lt;li&gt;Engine Redis OSS 7.x (reserved, 1-year)&lt;/li&gt;
&lt;li&gt;Current cost: $7.34/day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which was about 220$ USD monthly for Elasticache clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  New pricing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0i7spbomvihva7go7eq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0i7spbomvihva7go7eq.gif" alt="Image description" width="848" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today a &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/06/amazon-verified-permissions-reduces-price/" rel="noopener noreferrer"&gt;pricing change came out&lt;/a&gt; that changes everything. There are no more tiers for authorization requests, which means we have a flat rate of $5 per million requests (down from $150). That's a 97% price drop!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa68wehsaidnl5krktuc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa68wehsaidnl5krktuc8.png" alt="Image description" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For our case with 70 million authorization requests, the calculation now looks like:&lt;br&gt;
70 million requests: 70,000,000 × $0.000005 = $350 monthly → $4,200 yearly (compared to $99,000 in the old pricing).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep in mind that batch authorization request costs remain unchanged!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Will You Still Cache?
&lt;/h2&gt;

&lt;p&gt;I'm getting lots of questions about whether I plan to get rid of the cache with such a dramatic price change.&lt;br&gt;
"AVP is so cheap now, why bother with cache anymore?"&lt;br&gt;
"Let's simplify and just use direct API calls"&lt;/p&gt;

&lt;p&gt;The short answer is &lt;strong&gt;no&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This only applies to my specific use case - in other cases, the outcome might be totally different. Here's why we're keeping our cache:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First, we built the cache mechanism ourselves (for those who don't use API Gateway's built-in mechanism). It's already implemented, works well, and handles a huge number of requests. This means both a smaller AVP bill every month AND better performance because we get data faster from cache than by sending requests to AWS APIs. (We use 10-minute TTL and spent quite a lot of time developing it.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Second, our cache hit ratio is insanely high (98%). This means without cache, we'd go from 1.4 million API calls to 70 million API calls. That's not just "a few more API calls" - it's 50x more calls. Even at the new cheap rate, 50x more of anything adds up fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Third, there are quota and performance considerations. Loading from cache is faster than direct API calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;However, if we wanted to reduce cache costs, we could look at ElastiCache with Valkey (based on pricing, it would reduce costs by 20% just by changing the engine). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We could go even further and consider Serverless Valkey (my calculations showed about 80% cheaper per cluster per month).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Certainly, if we were starting from scratch today (in our use case), we would not be building a cache with the new pricing structure. We were one of the early adopters of AVP.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My opinion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I think this is a great and needed change that will definitely boost AVP adoption among customers&lt;/li&gt;
&lt;li&gt;It solves one of AVP's major problems, but we still have others (developer experience, lack of aliasing, versioning, cross-region replication, and several others)&lt;/li&gt;
&lt;li&gt;I'm very optimistic that the AVP team is working hard on new features and improvements, so I can't wait for more news!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Go build now!&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XV: AVP with Cognito groups</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Sat, 27 Apr 2024 16:40:16 +0000</pubDate>
      <link>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xv-avp-with-cognito-groups-4gjm</link>
      <guid>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xv-avp-with-cognito-groups-4gjm</guid>
      <description>&lt;p&gt;Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blog post, we learned about the usage of &lt;a href="https://dev.to/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiv-avp-getting-started-478f"&gt;AVP getting started&lt;/a&gt;. Today, we will cover the topic of using Cognito Groups with AVP. &lt;/p&gt;

&lt;p&gt;Related to AVP getting started, Cognito groups are now supported in the AVP, as you well know from the previous blogpost. However, in this blogpost we won't focus on building a getting started gateway with AVP, but we will focus on building authorization with AVP itself using cognito groups (So you can use it for API gateway, resource server, and enhance it for your use case pretty easily. If you want to see the finished result, you can use the scenario from avp-cli &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/ecommerceCognitoGroupsScenario.json" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In addition, we will also use the new &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_BatchIsAuthorizedWithToken.html" rel="noopener noreferrer"&gt;BatchIsAuthorizedWithToken&lt;/a&gt; API operation that was recently released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cognito groups support
&lt;/h2&gt;

&lt;p&gt;Currently, AVP only supports Cognito as an external identity provider(IdP). We create the reference from Cognito through the &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_CreateIdentitySource.html" rel="noopener noreferrer"&gt;CreateIdentitySource&lt;/a&gt; action.&lt;/p&gt;

&lt;p&gt;For configuration, we need to specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;policyStoreID&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;userPoolArn&lt;/code&gt; (ARN of the Cognito user pool), &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;clientIds&lt;/code&gt; (optional, unique application client IDs that are associated with the specified Amazon Cognito user pool.)&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;principalEntityType&lt;/code&gt; (namespace and data type for the entity that will be a principal for our policy store)&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;What was introduced into the &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_CognitoUserPoolConfiguration.html" rel="noopener noreferrer"&gt;CognitoUserPoolConfiguration&lt;/a&gt;, that &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_CognitoGroupConfiguration.html" rel="noopener noreferrer"&gt;groupConfiguration&lt;/a&gt; is the entity type that the policy store maps to groups from the Cognito user pool identity source. In short, which entity from the policy store will be mapped from the Cognito group.&lt;/p&gt;

&lt;p&gt;Below you can see example values for &lt;code&gt;principalEntityType&lt;/code&gt; and &lt;code&gt;groupEntityType&lt;/code&gt; in the case of namespace &lt;code&gt;MyApp&lt;/code&gt; for the AVP policy store to see how it will look in reality. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4vrgl0h2t22aq1o1im5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4vrgl0h2t22aq1o1im5.png" alt="Explanation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is, in short, when building an identity source for a policy store, we need to pass it on, and there you go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice
&lt;/h2&gt;

&lt;p&gt;Today, we would like to build an authorization system for the banking transaction system. Within, we have a user who can perform operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;View&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Approve&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Edit&lt;/code&gt;
for resources of type &lt;code&gt;TransactionRecord&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would like to introduce here RBAC based on groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;transaction_viewers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;transaction_approvers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transaction_editors&lt;/code&gt;
in Cognito, that is, depending on the role, the user can perform different operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1umi71iko659f0bzduhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1umi71iko659f0bzduhd.png" alt="System"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cognito part
&lt;/h2&gt;

&lt;p&gt;Let's start with our IDP from Cognito, we will create a user pool with groups, app client id, and add users there and add them to groups. Then we will obtain a Cognito token and use it for testing.&lt;/p&gt;

&lt;p&gt;In order not to build this from scratch, for the purpose of this blogpost I created a &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/authentication.yaml" rel="noopener noreferrer"&gt;ready-made Cloudformation template&lt;/a&gt; that will create a Cognito user pool, groups, and app client, we just need to later create users and add them to groups.&lt;/p&gt;

&lt;p&gt;Navigate to the AWS console, and open the AWS console, open Cloudformation, and upload the &lt;code&gt;authentication.yaml&lt;/code&gt; from the avp-cli repo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3breb0eofpjo9ao4iq4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3breb0eofpjo9ao4iq4t.png" alt="CF"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the deployment, as outputs you can see both the &lt;code&gt;CognitoUserPoolId&lt;/code&gt; as well as &lt;code&gt;CognitoUserPoolId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Navigate to the Cognito user pool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ea8rys3scvh1x8qqjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ea8rys3scvh1x8qqjz.png" alt="Groups"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see 3 groups generated, now what you need to do, is create users and assign them to the groups:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftel95aj6v2do8jy5xjbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftel95aj6v2do8jy5xjbq.png" alt="Groups assigment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Later we will need to copy the ARN of the Cognito User Pool, App Client Id (it is called &lt;code&gt;avp-client&lt;/code&gt;, and initiate the auth with our users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I am aware I am showing the cognito user pool, however before publishing the blogpost the cognito user pool on my site will be already deleted. Never share credentials, ARNs, JWTs, ClientIds, or secrets over the internet!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Store part
&lt;/h2&gt;

&lt;p&gt;Let's start building a policy store, log in to your AWS console, open the AVP service, and create an empty policy store. &lt;/p&gt;

&lt;p&gt;Go to the schema tab, and paste this &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/schema.json" rel="noopener noreferrer"&gt;schema&lt;/a&gt;. Save the changes, you should see this action diagram and entity types diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwoo3ove7t482k884k4qt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwoo3ove7t482k884k4qt.png" alt="Actions diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg58jrhnhchekc195ctr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg58jrhnhchekc195ctr.png" alt="Entity types diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, we have principal as user (i.e., who), actions like approve, edit, view (i.e., what operation we want to perform), and resource (i.e., on what resource we want to do), i.e., TransactionRecord.&lt;/p&gt;

&lt;p&gt;In addition, we can see that we have an entity of type &lt;code&gt;Group&lt;/code&gt;, to which our user belongs (Hierarchy).&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity Source.
&lt;/h2&gt;

&lt;p&gt;Now, we can reference our IDP (so Cognito) with AVP. Navigate to the &lt;code&gt;Identity sources&lt;/code&gt; in the AVP console and create a new one. Fill the user pool ID (copy it from the user pool details from the Cognito details page, the same for the client application ID (you will find it in the &lt;code&gt;App integration&lt;/code&gt; section of the user pool).&lt;/p&gt;

&lt;p&gt;For the principal details we will use the &lt;code&gt;Principal&lt;/code&gt; type as &lt;code&gt;BankingTransationSystem::User&lt;/code&gt; so this will map our user pool to Cognito as a principal. Moreover the principal ID so the token issued for the connected user pool will be mapped to a principal ID in the format ‘|’&lt;/p&gt;

&lt;p&gt;Unfortunately, we cannot add &lt;code&gt;groupEntityType&lt;/code&gt; from the AWS console position (we cannot both see the value, modify it, or add it from the console). Although we can do it through AWS-CLI, AWS-SDK, Cloudformation, or through AVP-CLI. &lt;/p&gt;

&lt;h3&gt;
  
  
  AVP CLI for CreateIdentitySource
&lt;/h3&gt;

&lt;p&gt;So if we want to do it via AVP-CLI, we can do it with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

➜  avp-cli git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; node index.js
🚀 Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service.
🔧 Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and &lt;span class="nb"&gt;test &lt;/span&gt;with predefined scenarios!
⚠️ Ensure your AWS credentials are correctly &lt;span class="nb"&gt;set &lt;/span&gt;up before proceeding.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Manual approach
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Create Identity Source
? Enter the ID of the policy store TKdiMU5n3DeypqsnEHb9d6
? Enter the entity &lt;span class="nb"&gt;type &lt;/span&gt;of the principal BankingTransactionSystem::User
? Enter the Amazon Cognito User Pool ARN arn:aws:cognito-idp:eu-west-1:ACCOUND_ID_GOES_HERE:userpool/eu-west-1_sXVC4jUDf
? Enter the Amazon Cognito App Client ID 5b33v2gf0cr1c4n6qj04rajjhf
? Enter the entity &lt;span class="nb"&gt;type &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;groups&lt;/span&gt;, or press enter to skip 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Under the hood it will make an SDK call like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
  policyStoreId: &lt;span class="s1"&gt;'TKdiMU5n3DeypqsnEHb9d6'&lt;/span&gt;,
  principalEntityType: &lt;span class="s1"&gt;'BankingTransactionSystem::User'&lt;/span&gt;,
  configuration: &lt;span class="o"&gt;{&lt;/span&gt;
    cognitoUserPoolConfiguration: &lt;span class="o"&gt;{&lt;/span&gt;
      userPoolArn: &lt;span class="s1"&gt;'arn:aws:cognito-idp:eu-west-1:ACCOUNT_ID_GOES_HERE:userpool/eu-west-1_sXVC4jUDf'&lt;/span&gt;,
      clientIds: &lt;span class="o"&gt;[&lt;/span&gt;Array],
      groupConfiguration: &lt;span class="o"&gt;[&lt;/span&gt;Object]
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the console you will see it like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy6xpbs6yyoyouy4yqeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy6xpbs6yyoyouy4yqeb.png" alt="Identity Source details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully, soon we will see the group over there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policies
&lt;/h2&gt;

&lt;p&gt;Now it's time to add &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/allow_policy_1.cedar" rel="noopener noreferrer"&gt;three access policies&lt;/a&gt;, for each action separately, it will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

permit &lt;span class="o"&gt;(&lt;/span&gt;
    principal &lt;span class="k"&gt;in
        &lt;/span&gt;BankingTransactionSystem::Group::&lt;span class="s2"&gt;"&amp;lt;user-pool-id-goes-here&amp;gt;|&amp;lt;cognito-group-name-here&amp;gt;"&lt;/span&gt;,
    action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;BankingTransactionSystem::Action::&lt;span class="s2"&gt;"View"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
    resource
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What we see is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we check if the principal is (with &lt;code&gt;in&lt;/code&gt; operator which checks hierarchies) in a specific group (in the above example &lt;code&gt;transaction_viewers&lt;/code&gt;) from the Cognito user pool.&lt;/li&gt;
&lt;li&gt;we check a specific action&lt;/li&gt;
&lt;li&gt;resource is any.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to add it for all three groups (per action) accordingly, and it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuue4zyhoq592xu94l5cn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuue4zyhoq592xu94l5cn.png" alt="Policy"&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to add those three policies from the AVP-CLI repo, remember to replace &lt;code&gt;&amp;lt;user-pool-id-goes-here&amp;gt;&lt;/code&gt; with your Cognito user pool ID (not the ARN!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember about &lt;code&gt;|&lt;/code&gt; between cognito user pool id and group name from the Cognito!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach with AVP-CLI scenario
&lt;/h2&gt;

&lt;p&gt;As you can see, a little has to be done to get everything ready. What you can do more simply is to use avp-cli to do the deployment of all the things you need.&lt;/p&gt;

&lt;p&gt;Remember to first do the deployment of the &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/authentication.yaml" rel="noopener noreferrer"&gt;authentication.yml&lt;/a&gt; file in the Cloudformation console if you haven't done it before.&lt;/p&gt;

&lt;p&gt;Next, simply use the AVP-CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

➜  avp-cli git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; ✗ &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;personal node index.js
🚀 Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service.
🔧 Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and &lt;span class="nb"&gt;test &lt;/span&gt;with predefined scenarios!
⚠️ Ensure your AWS credentials are correctly &lt;span class="nb"&gt;set &lt;/span&gt;up before proceeding.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario Ecommerce with Cognito Groups Scenario
? Enter the ARN of the Cognito User Pool arn:aws:cognito-idp:eu-west-1:ACCOUNT_NUMBER:userpool/eu-west-1_sXVC4jUDf
? Enter the App Client ID 5b33v2gf0cr1c4n6qj04rajjhf
./scenarios/ecommerceCognitoGroupsScenario/ecommerceCognitoGroupsScenario.json
Starting creating scenario: Ecommerce Cognito Group Scenario
description: This is a basic scenario with a group cognito management platform schema and three policies.
Policy store created with ID: Ny9v75vt5cQGxzEovBgL9R
Schema put successfully &lt;span class="k"&gt;for &lt;/span&gt;policy store ID: Ny9v75vt5cQGxzEovBgL9R
Creating an identity source...
Identity &lt;span class="nb"&gt;source &lt;/span&gt;created with ID: 9M6FTv52wSnLTR2LAJkRYa
Creating a static policy...
Static policy created with ID: W4Z31yfapD5jWJqvXr57XH
Creating a static policy...
Static policy created with ID: 5k1QXfuWxYJqQa9r3Mnygh
Creating a static policy...
Static policy created with ID: WDu7Pac7umBpHrY2o55TYF
┌────────────────────────────────────────┬────────────────────────────────────────┬────────────────────────────────────────┐
│ Policy ID                              │ Policy Store ID                        │ Created Date                           │
├────────────────────────────────────────┼────────────────────────────────────────┼────────────────────────────────────────┤
│ W4Z31yfapD5jWJqvXr57XH                 │ Ny9v75vt5cQGxzEovBgL9R                 │ 2024-04-27 18:00                       │
├────────────────────────────────────────┼────────────────────────────────────────┼────────────────────────────────────────┤
│ 5k1QXfuWxYJqQa9r3Mnygh                 │ Ny9v75vt5cQGxzEovBgL9R                 │ 2024-04-27 18:00                       │
├────────────────────────────────────────┼────────────────────────────────────────┼────────────────────────────────────────┤
│ WDu7Pac7umBpHrY2o55TYF                 │ Ny9v75vt5cQGxzEovBgL9R                 │ 2024-04-27 18:00                       │
└────────────────────────────────────────┴────────────────────────────────────────┴────────────────────────────────────────┘
Generating of the undefined is finished. Open the AWS console to play around with that.

Consider testing it with our prepared &lt;span class="nb"&gt;test &lt;/span&gt;scenarios:
Either use &lt;span class="sb"&gt;`&lt;/span&gt;Test Scenario&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;main CLI to &lt;span class="k"&gt;select &lt;/span&gt;the specific &lt;span class="nb"&gt;test &lt;/span&gt;scenario, or use below path as argument to &lt;span class="sb"&gt;`&lt;/span&gt;IsAuthorized&lt;span class="sb"&gt;`&lt;/span&gt; from the manual approach option of the CLI:
 Remember to update the policy-store-id within files.
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json &lt;span class="o"&gt;(&lt;/span&gt;Access &lt;span class="k"&gt;for &lt;/span&gt;user &lt;span class="nb"&gt;who &lt;/span&gt;has transaction_viewer group can view&lt;span class="o"&gt;)&lt;/span&gt; allow
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_2.json &lt;span class="o"&gt;(&lt;/span&gt;Access &lt;span class="k"&gt;for &lt;/span&gt;user &lt;span class="nb"&gt;who &lt;/span&gt;has transaction_approve group can approve&lt;span class="o"&gt;)&lt;/span&gt; allow
- ./scenarios/ecommerceCognitoGroupsScenario/allow_test_3.json &lt;span class="o"&gt;(&lt;/span&gt;Access &lt;span class="k"&gt;for &lt;/span&gt;user &lt;span class="nb"&gt;who &lt;/span&gt;has transaction_edit group can edit&lt;span class="o"&gt;)&lt;/span&gt; allow

Generating of the ecommerceCognitoGroupsScenario is finished. Open the AWS console to play around with that.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that's it, you can test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepration for tests
&lt;/h2&gt;

&lt;p&gt;First, we need an access token (or ID token) from Cognito for our user.&lt;/p&gt;

&lt;p&gt;Remember, when you create a new user, you must generate a new password for them, which can be done in the AWS CLI with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws cognito-idp admin-respond-to-auth-challenge 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can generate code via AWS-CLI, SDK, or by doing the HTTP request via POSTMAN or curl like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'https://cognito-idp.&amp;lt;REGION&amp;gt;.amazonaws.com/&amp;lt;USER_POOL_HERE!!!!!&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/x-amz-json-1.1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Accept: */*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
  "AuthFlow": "USER_PASSWORD_AUTH",
  "ClientId": "&amp;lt;ID_HERE&amp;gt;",
  "AuthParameters": {
    "USERNAME": "&amp;lt;USERNAME&amp;gt;",
    "PASSWORD": "&amp;lt;PASSWORD&amp;gt;"
  }
}
'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As a response, you will obtain both an access token and an id token, use the access token.&lt;/p&gt;

&lt;p&gt;If you decode the token with jwt.io you will see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cognito:groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"transaction_viewers"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'BLABLA&lt;/span&gt;&lt;span class="s2"&gt;",
  ...
  "&lt;/span&gt;&lt;span class="err"&gt;auth_time&lt;/span&gt;&lt;span class="s2"&gt;": 1713899648,
  "&lt;/span&gt;&lt;span class="err"&gt;exp&lt;/span&gt;&lt;span class="s2"&gt;": 1713903248,
  "&lt;/span&gt;&lt;span class="err"&gt;iat&lt;/span&gt;&lt;span class="s2"&gt;": 1713899648,`
  "&lt;/span&gt;&lt;span class="err"&gt;username&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;daniel&lt;/span&gt;&lt;span class="s2"&gt;"
}
```
so you can double check at this point, whether a proper group is within the JWT of a user.

## Testing
So we can't test it using the test bench because it doesn't support isAuthorizedWithToken operations and for Batch, so we can do it through AWS CLI, SDK, or through AVP-CLI.

### With isAuthorizedWithToken

For authorization with a token, we will use the [isAuthorizedWithToken](https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_IsAuthorizedWithToken.html) operation.

We can provide both an access token and an ID token, we will use the access token. It is worth reminding that our principal is a user from the Cognito user pool. AVP on its side will decode the token and check if it is ok, so we don't need to do it on our side.

**If you delete an Amazon Cognito user pool or user, tokens from that deleted pool or that deleted user continue to be usable until they expire.
**

The structure of the request is [here](https://github.com/Pigius/avp-cli/blob/main/structureAuthorizationWithTokenRequest.json). For use usecase we can use this [allow test](https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json). Generate the access token, and pass it together with policy store ID.

So I've generated an access token for a user which is in the `transaction_viewers` group, and based on the allow test I will try to access the `View` action.

now we will use AVP-CLI:

```shell
? What would you like to do? Manual approach
? What would you like to do? Make an authorization decision with Cognito Identity Token
? Enter the path for json test file scenarios/ecommerceCognitoGroupsScenario/allow_test_1.json

┌──────────┬──────────────────────────────┬────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┐
│ Decision │ Determining Policies         │ Errors             │ Policy Store ID              │ Principal                    │ Action                       │ Resource                     │ Context                      │
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ ALLOW    │ 7UQxoV3bvzpYvGnm939HZH       │                    │ TKdiMU5n3DeypqsnEHb9d6       │ BankingTransactionSystem::Us │ BankingTransactionSystem::Ac │ BankingTransactionSystem::Tr │ {}                           │
│          │                              │                    │                              │ er::eu-west-1_sXVC4jUDf|f245 │ tion::View                   │ ansactionRecord::*           │                              │
│          │                              │                    │                              │ a454-90c1-7084-7709-1dfbfdb1 │                              │                              │                              │
│          │                              │                    │                              │ 0930                         │                              │                              │                              │

```

If I will try the second test scenario I will be rejected, as my user is only allowed to view.

### With BatchIsAuthorizedWithToken

As recently [BatchIsAuthorizedWithToken](https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_BatchIsAuthorizedWithToken.html) has been released, we can use it to test our scenario.

With this operation, we can make up to 30 requests during a single request (and we paid per request, and performance is better). Note that the current request limit is 30, and also our batch can contain up to 100 resources and up to 99 user groups. Example structure is [here](https://github.com/Pigius/avp-cli/blob/main/structureBatchAuthorizationWithTokenRequest.json).

We can pass either an access token or an ID token. The request is either principal or resource oriented.

So, in our scenario, what we can do, is to check, whether my user can access multiple actions on a single resource by making one request to AVP.


![Batch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibjhssbay8ss7vn7x6q1.png)



I've prepared test file for that [here](https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoGroupsScenario/batch_allow_test.json).

Let's try with AVP-CLI now:


```
➜  avp-cli AWS_PROFILE=personal node index.js
🚀 Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the Amazon Verified Permissions (AVP) service.
🔧 Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and test with predefined scenarios!
⚠️ Ensure your AWS credentials are correctly set up before proceeding.
? What would you like to do? Manual approach
? What would you like to do? Make a batch authorization decision with Cognito Identity Token
? Enter the path for batch authorization with token json test file scenarios/ecommerceCognitoGroupsScenario/batch_allow_test.json
Making batch with token authorization decision...

┌──────────┬──────────────────────────────┬────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┐
│ Decision │ Determining Policies         │ Errors             │ Policy Store ID              │ Principal                    │ Action                       │ Resource                     │ Context                      │
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ ALLOW    │ 7UQxoV3bvzpYvGnm939HZH       │                    │ TKdiMU5n3DeypqsnEHb9d6       │ BankingTransactionSystem::Us │ BankingTransactionSystem::Ac │ BankingTransactionSystem::Tr │ {}                           │
│          │                              │                    │                              │ er::eu-west-1_sXVC4jUDf|f245 │ tion::View                   │ ansactionRecord::123         │                              │
│          │                              │                    │                              │ a454-90c1-7084-7709-1dfbfdb1 │                              │                              │                              │
│          │                              │                    │                              │ 0930                         │                              │                              │                              │
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ DENY     │                              │                    │ TKdiMU5n3DeypqsnEHb9d6       │ BankingTransactionSystem::Us │ BankingTransactionSystem::Ac │ BankingTransactionSystem::Tr │ {}                           │
│          │                              │                    │                              │ er::eu-west-1_sXVC4jUDf|f245 │ tion::Edit                   │ ansactionRecord::123         │                              │
│          │                              │                    │                              │ a454-90c1-7084-7709-1dfbfdb1 │                              │                              │                              │
│          │                              │                    │                              │ 0930                         │                              │                              │                              │
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ DENY     │                              │                    │ TKdiMU5n3DeypqsnEHb9d6       │ BankingTransactionSystem::Us │ BankingTransactionSystem::Ac │ BankingTransactionSystem::Tr │ {}                           │
│          │                              │                    │                              │ er::eu-west-1_sXVC4jUDf|f245 │ tion::Approve                │ ansactionRecord::123         │                              │
│          │                              │                    │                              │ a454-90c1-7084-7709-1dfbfdb1 │                              │                              │                              │
│          │                              │                    │                              │ 0930                         │                              │                              │                              │
└──────────┴──────────────────────────────┴──────────
```
We will obtain the array of authorization request decisions. As you can see, my user is only allowed to `View`.


## Sumup

That's it for today. We now know:
- how to build AVP policy stores with Cognito as IDP
- use Cognito groups within the access policy
- how to test it.

Now go build!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>cognito</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XIV: AVP Getting Started</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Tue, 23 Apr 2024 19:52:27 +0000</pubDate>
      <link>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiv-avp-getting-started-478f</link>
      <guid>https://forem.com/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiv-avp-getting-started-478f</guid>
      <description>&lt;p&gt;Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blog post we learned about usage of AVP with IaC &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiii-cloudformation-47d2"&gt;Cloudformation&lt;/a&gt;. Today, we will cover the topic of recently added &lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/04/amazon-cognito-customers-access-apis-verified-permissions/" rel="noopener noreferrer"&gt;AVP getting started&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning curve
&lt;/h2&gt;

&lt;p&gt;As with any adoption of any technology, there's always a learning curve, in the case of AVP, it's a new service, so, naturally, it's not popularized, and there aren't a lot of materials (but there are more and more every day), as well as a learning curve related to the Cedar language. &lt;/p&gt;

&lt;p&gt;The Cedar language is very simple and fun for the developer, but it is a learning curve if you want to implement it in an organization. Let's look at what we need to build authorization with AVP. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft76r5hd8u8g628y50xya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft76r5hd8u8g628y50xya.png" alt="Learning Curve"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use AVP, we need several elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Policy store&lt;/strong&gt;, which is a container for our access policies, where all policies are kept, and every authorization request, is checked against a specific policy store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema&lt;/strong&gt;, which is the definition of all entities for our authorization system, possible actions, hierarchies, required and optional attributes, and their types. With schema we can check that our access policies are correct against schema, and so is the payload we send to AVP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access policies&lt;/strong&gt; in Cedar language, which AVP then evaluates for us. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;payload&lt;/strong&gt; - once we have all of the above, it would be nice to finally test our policy store, but for that we need a payload that we will send to the AVP for authorization decision (i.e. we need to send information about the principal, the action it wants to perform, on what resource, pass the required attributes, hierarchy information, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you look at it from the side, it seems like a lot of things, and it can be overwhelming. &lt;/p&gt;

&lt;p&gt;Rest assured, it was not clear to me at first either, but over time everything has been clarified, and now I fully understand it. That's why the avp-cli was created, to quickly help others understand what it's all about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;The AVP team was aware of a learning curve, so to simplify the use of AVP it added getting started to the service. As we know, most authorization cases are mainly RBAC, on API gateway, so the AVP team wanted to simplify the process (especially if you use Cognito for auth).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10rxnounjym3zvkhkkrk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F10rxnounjym3zvkhkkrk.png" alt="Gateway flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typical flow as shown in the figure, Gateway with various endpoints, Cognito for authentication, in addition, we can have some Cognito authorizer that will check access to the gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AVP Getting Started does for us:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Allows for authorization setup through the AVP wizard in the console under API Gateway.&lt;/li&gt;
&lt;li&gt;Based on the actions in the API Gateway, it maps these actions to Cedar actions, eliminating the initial learning curve of Cedar.&lt;/li&gt;
&lt;li&gt;Creates a lambda authorizer that we can easily attach to the API Gateway and use, so we don't have to worry about how to build the payload for AVP and use it properly (and overall knowledge about lambda authorizer at all).&lt;/li&gt;
&lt;li&gt;On our part, deploying the gateway is required once the authorizer is attached.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsprtc7ifncykfs0tcxyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsprtc7ifncykfs0tcxyg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's assume that we would like to streamline basic flow, and add Role Base Access control (RBAC) authorization, based on groups in Cognito. Before, it was not possible to use Cognito groups in AVP, now it is possible.&lt;/p&gt;

&lt;p&gt;So that it's not just a theory, we'll try using Getting Started on some simple examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we will build today?
&lt;/h2&gt;

&lt;p&gt;Based on the AWS announcement post, consider the example of a loan application with two key actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a &lt;code&gt;Loan Request (POST /loan)&lt;/code&gt;: Users can submit new loan applications.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Approving a Loan (POST /loan/approve/{loan_id}&lt;/code&gt;): Certain users can approve loans that have been submitted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose we have two Amazon Cognito groups that have user permissions as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;loan_creators&lt;/code&gt;: Members of this group are allowed to perform the "Creating a Loan Request" action.&lt;br&gt;
&lt;code&gt;loan_officers&lt;/code&gt;: Members of this group have permissions for both creating and approve loans.&lt;/p&gt;

&lt;p&gt;And based on that we would like to do authorization at the Gateway level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting point Gateway and Cognito
&lt;/h2&gt;

&lt;p&gt;For the purposes of the blog post, I created two Cloudformation so that everyone can play with it themselves, I know how annoying it always is when you do not have an example at hand that you can quickly use in the console, so I prepared:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/blob/main/cloudformation/avp-getting-started/api.yaml" rel="noopener noreferrer"&gt;a simple Cloudformation with Gateway API&lt;/a&gt;, which implements the two endpoints mentioned before.&lt;/li&gt;
&lt;li&gt;both endpoints are mocks (to make it simpler).&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/blob/main/cloudformation/avp-getting-started/authentication.yaml" rel="noopener noreferrer"&gt;simple Cloudformation for Cognito&lt;/a&gt; (with groups inside).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to do deployment of the above cloud formation templates in the AWS console (just grab the template, and go via Cloudformation wizard to deploy it).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fectfxrny0riplxqd8h0y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fectfxrny0riplxqd8h0y.png" alt="CF success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Gateway
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawillnp0jm7wlly6iggk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawillnp0jm7wlly6iggk.png" alt="Gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successful deployment, you can see Gateway with two endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cognito
&lt;/h2&gt;

&lt;p&gt;After successful deployment, you can see the Cognito user pool with two groups, and the &lt;code&gt;avp-client&lt;/code&gt; user pool client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqian46nffsziinqn82hl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqian46nffsziinqn82hl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, we don't have any users, so it would be worthwhile to create a user and add them to a group. This is relatively simple; you need to create a new user and add them to the appropriate group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo34snepabbc6142e3ezs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo34snepabbc6142e3ezs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's finally have some fun with AVP! We have everything we need—authentication, gateway, groups, users in groups—so we can finally add authorization.&lt;/p&gt;

&lt;h2&gt;
  
  
  AVP time!
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gateway actions
&lt;/h3&gt;

&lt;p&gt;Currently, there is no support for CloudFormation, so we need to do this manually. Open the AWS console, and then go to Amazon Verified Permissions.&lt;/p&gt;

&lt;p&gt;Start by creating a new policy store, and then select the option &lt;code&gt;Set up with Cognito and API Gateway - new.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw73w39myae2pp0bklnjs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw73w39myae2pp0bklnjs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we need to select an API; we choose our Loan API, select the stage (v0), and then press 'Import API'. Our resources from the API will automatically be translated into Cedar policies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehp4tf9iz3h7ynpohe14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehp4tf9iz3h7ynpohe14.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity Source
&lt;/h2&gt;

&lt;p&gt;Now, we need to use our Cognito user pool as an identity source. Simply select the newly deployed Cognito user pool, and use all default options untouched. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd4hp5y3mob1qszk3or5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd4hp5y3mob1qszk3or5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Assign actions to groups
&lt;/h2&gt;

&lt;p&gt;Now, we need to assign actions to our Cognito groups, do it the same way as in the picture below (based on our requirements).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filejqlbl0ajuvcb09k7i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filejqlbl0ajuvcb09k7i.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy policy store
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv418zxxl8gburca2j7ux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv418zxxl8gburca2j7ux.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the last step, you need to hit &lt;code&gt;Create policy store&lt;/code&gt; which will trigger the deployment of the Lambda Authorizer. &lt;/p&gt;

&lt;p&gt;You will need to wait for the deployment, and then make sure the lambda authorizer is attached to the gateway, and then you &lt;strong&gt;need to re-deploy&lt;/strong&gt; API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfjbn5ryt12pf2gw80zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfjbn5ryt12pf2gw80zh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me AVP!
&lt;/h2&gt;

&lt;p&gt;We can immediately check in practice how it works, but before we test it, it will be simpler to see exactly what we have generated in AVP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1alqfy4uhbx16krbwkus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1alqfy4uhbx16krbwkus.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start from schema:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsx8gq3t6hdgj1hjnu3fz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsx8gq3t6hdgj1hjnu3fz.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we have two actions (our endpoints), principal as &lt;code&gt;User&lt;/code&gt; and Resource as &lt;code&gt;Application&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As we deal with hierarchy, we also have &lt;code&gt;UserGroup&lt;/code&gt;, which our &lt;code&gt;User&lt;/code&gt; is a member of. So based on that, we have an access policy for group membership.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8bk7qm62ttb8x7s3qmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8bk7qm62ttb8x7s3qmx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's check the generated actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Policy defining permissions for loan_officers cognito group&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;permit(&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;loan_api::UserGroup::&lt;/span&gt;&lt;span class="s2"&gt;"eu-west-1_sXVC4jUDf|loan_officers"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;loan_api::Action::&lt;/span&gt;&lt;span class="s2"&gt;"post /loan/approve/{loan_id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;loan_api::Action::&lt;/span&gt;&lt;span class="s2"&gt;"post /loan"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;resource&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;);&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Policy defining permissions for loan_creators cognito group
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;permit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;loan_api::UserGroup::&lt;/span&gt;&lt;span class="s2"&gt;"eu-west-1_sXVC4jUDf|loan_creators"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;loan_api::Action::&lt;/span&gt;&lt;span class="s2"&gt;"post /loan"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;resource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;);&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By specifying &lt;code&gt;loan_api::UserGroup::"eu-west-1_sXVC4jUDf|loan_officers&lt;/code&gt; and &lt;code&gt;loan_api::UserGroup::"eu-west-1_sXVC4jUDf|loan_creators&lt;/code&gt;, the policies are targeting actions based on the membership of the principal in these particular groups (with usage of &lt;code&gt;in&lt;/code&gt; operator). They also explicitly define what actions these principals can perform. In the case of &lt;code&gt;loan_officers&lt;/code&gt;, the policy permits actions like &lt;code&gt;post /loan/approve/{loan_id}&lt;/code&gt; and &lt;code&gt;post /loan&lt;/code&gt;. For &lt;code&gt;loan_creators&lt;/code&gt;, the policy permits the action &lt;code&gt;post /loan&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With deny as a default rule, we don't need to create &lt;code&gt;forbid&lt;/code&gt; policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lambda
&lt;/h2&gt;

&lt;p&gt;The generated lambda authorizer is a type of &lt;code&gt;request-based&lt;/code&gt; authorizer, which also will have in the event data section, the data from the request, including query params etc.&lt;/p&gt;

&lt;p&gt;The runtime is Node.&lt;/p&gt;

&lt;p&gt;Lambda is quite simple, but for us, the most important part is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;bearerToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bearerToken&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// per https://www.rfc-editor.org/rfc/rfc6750#section-2.1 "Authorization" header should contain:&lt;/span&gt;
    &lt;span class="c1"&gt;//  "Bearer" 1*SP b64token&lt;/span&gt;
    &lt;span class="c1"&gt;// however, match behavior of COGNITO_USER_POOLS authorizer allowing "Bearer" to be optional&lt;/span&gt;
    &lt;span class="nx"&gt;bearerToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bearerToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bearerToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourcePath&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tokenType&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;bearerToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;policyStoreId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;policyStoreId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;actionType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actionType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;actionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;actionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;entityType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resourceType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;entityId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resourceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getContextMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;verifiedpermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAuthorizedWithToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Decision from AVP:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can observe the building of the payload for AVP, which uses the token from Cognito. AVP will decode the token and validate the JWKS for us, so we don't need to do this in Lambda. Then, we use the &lt;code&gt;isAuthorized&lt;/code&gt; action which performs the authorization request. Based on the decision, we either grant or deny access to the endpoint.&lt;/p&gt;

&lt;p&gt;The full lambda code can be found &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/blob/main/cloudformation/avp-getting-started/lambda_handler.js" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Please keep in mind that Lambda code could change, I am not the author of this code!&lt;/p&gt;

&lt;p&gt;You don't need to explicitly create a log group for lambda, they will go to &lt;code&gt;/aws/lambda/yourFunctionName&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's test it in practice
&lt;/h2&gt;

&lt;p&gt;Now that we have everything, we can finally test our solution. First, we need an access token from Cognito for our user. I recommend creating two users who are in two different groups.&lt;/p&gt;

&lt;p&gt;Remember, when you create a new user, you must generate a new password for them, which can be done in the AWS CLI with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws cognito-idp admin-respond-to-auth-challenge 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can generate code via AWS-CLI, SDK, or by doing the HTTP request via POSTMAN or curl like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s1"&gt;'https://cognito-idp.&amp;lt;REGION&amp;gt;.amazonaws.com/&amp;lt;USER_POOL_HERE!!!!!&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/x-amz-json-1.1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Accept: */*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
  "AuthFlow": "USER_PASSWORD_AUTH",
  "ClientId": "&amp;lt;ID_HERE&amp;gt;",
  "AuthParameters": {
    "USERNAME": "&amp;lt;USERNAME&amp;gt;",
    "PASSWORD": "&amp;lt;PASSWORD&amp;gt;"
  }
}
'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As a response, you will obtain both an access token and an id token, use the access token.&lt;/p&gt;

&lt;p&gt;If you decode the token with jwt.io you will see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cognito:groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"loan_creators"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'BLABLA&lt;/span&gt;&lt;span class="s2"&gt;",
  ...
  "&lt;/span&gt;&lt;span class="err"&gt;auth_time&lt;/span&gt;&lt;span class="s2"&gt;": 1713899648,
  "&lt;/span&gt;&lt;span class="err"&gt;exp&lt;/span&gt;&lt;span class="s2"&gt;": 1713903248,
  "&lt;/span&gt;&lt;span class="err"&gt;iat&lt;/span&gt;&lt;span class="s2"&gt;": 1713899648,`
  "&lt;/span&gt;&lt;span class="err"&gt;username&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;daniel&lt;/span&gt;&lt;span class="s2"&gt;"
}
```
so you can double check at this point, whether a proper group is within the JWT of a user.

## Testing Gateway
Now we can test our endpoints, starting from the `loan approval endpoint`:

You can use this curl:

```shell
curl --location 'https://&amp;lt;gateway-id&amp;gt;.execute-api.eu-west-1.amazonaws.com/v0/loan/approve/1234' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--header 'Content-Type: application/json' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--header 'Authorization: Bearer &amp;lt;TOKEN GOES HERE&amp;gt;' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--data '{"&lt;/span&gt;&lt;span class="err"&gt;statusCode&lt;/span&gt;&lt;span class="s2"&gt;": 200}'
```

The `'{"&lt;/span&gt;&lt;span class="err"&gt;statusCode&lt;/span&gt;&lt;span class="s2"&gt;": 200}'` is needed as is the mock integration type.

The same for `loan creation`:

```shell
curl --location 'https://&amp;lt;gateway-id&amp;gt;.execute-api.eu-west-1.amazonaws.com/v0/loan/' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--header 'Content-Type: application/json' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--header 'Authorization: Bearer &amp;lt;JWT here&amp;gt;' &lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
--data '{"&lt;/span&gt;&lt;span class="err"&gt;statusCode&lt;/span&gt;&lt;span class="s2"&gt;": 200}'
```

If your user will be with a not allowed group you will obtain the below response:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2dfnphfr5kudmwzk9x2l.png)

## Summary, next steps

And that wraps up today's blog post. As you can see, you can quite simply "&lt;/span&gt;&lt;span class="err"&gt;click&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;through&lt;/span&gt;&lt;span class="s2"&gt;" the authorization setup for the API Gateway, which as a `getting started` seems sufficient for a PoC and taking the first steps.

When I started, such tools weren’t available, so there was a lot to figure out on your own.

It's also important to note that there is no CloudFormation support for this, so you can't just throw this into your CI/CD and expect it to automatically build. However, you do have something to start with, something you can copy, play with, and then start to build authorization flows in your organization.

You might also try expanding this example to better understand how the service works, for example, try validating an additional parameter from the query params, and learn what needs to be changed.

and now... **Go Build!**

In the next blogpost we will cover [AVP with Cognito Groups](https://dev.to/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xv-avp-with-cognito-groups-4gjm)


## Useful resources
- [Official quick overview and demo video](https://www.youtube.com/watch?v=OBrSrzfuWhQ)
- [Offical Workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/e25284b6-851c-4a89-bee1-ed7571787895/en-US)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>cognito</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XIII: Cloudformation</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Sat, 20 Jan 2024 17:17:30 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiii-cloudformation-47d2</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiii-cloudformation-47d2</guid>
      <description>&lt;p&gt;Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blogpost we've learned about usage &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xii-terraform-598d"&gt;AVP with IaC Terraform&lt;/a&gt;. Today, we will cover the topic of how to use AVP with Cloudformation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudformation/"&gt;Cloudformation (IaC)&lt;/a&gt; does not need to be introduced to anyone, plus if you read the previous blogpost, the terraform provider (CC) we used is based on Cloudformation. Moreover, you will notice a lot of similarities, after all, we are implementing the same scenario, but with a different tool.&lt;/p&gt;

&lt;p&gt;All the Cloudformation references you can check &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_VerifiedPermissions.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's assume that we would like to recreate one of the scenarios from avp-cli in Cloudformation, for example, the &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/documentsScenario.json"&gt;documents scenario&lt;/a&gt;. This is a basic scenario with a document management platform schema and two policies (&lt;code&gt;Allow all users to view all documents&lt;/code&gt; and &lt;code&gt;Forbid user X from viewing any documents&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To recreate this, we need:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7tx6zmpqeh8z5fvjq5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7tx6zmpqeh8z5fvjq5j.png" alt="policy store" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;policy store&lt;/strong&gt;, which is a container for our policies. In such a container, we keep all policies, as well as the schema. It's important to remember that later when using AVP for authorization requests, we send requests against a specific policy store.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;schema&lt;/strong&gt; is the structure of all available entities for a given policy store. In short, it defines what entities are available for our authorization system, including available actions, principals, and resources. The schema not only informs us about the available entities but also validates the correctness of authorization requests.&lt;/p&gt;

&lt;p&gt;Finally, we will also need to add our &lt;strong&gt;policies&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's build!
&lt;/h2&gt;

&lt;p&gt;The code for today's blog post can be found &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/tree/main/cloudformation/scenarios/documentsScenario"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The example we will create is not intended for production use; it has been created for educational purposes. However, in the future, In the next weeks, I will try to recreate all scenarios from avp-cli to Cloudformation. It will be in this &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/tree/main/cloudformation/"&gt;repository&lt;/a&gt;, as well as a couple of more advanced, production-wise examples.&lt;/p&gt;

&lt;p&gt;For our example, we will need two types of resources from the Cloudformation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-verifiedpermissions-policystore.html"&gt;policy store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/userguide/policies.html"&gt;policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we know everything, we can start building the project with Cloudformation.&lt;/p&gt;

&lt;p&gt;Let's start with empty &lt;code&gt;avp.yaml&lt;/code&gt; for our Cloudformation configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2010-09-09"&lt;/span&gt;

&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;IaC for AVP&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've started from adding &lt;code&gt;AWSTemplateFormatVersion&lt;/code&gt; to tell CloudFormation which template version we're adhering to. The &lt;code&gt;Description&lt;/code&gt; part refers to the overall description of the template.&lt;/p&gt;

&lt;p&gt;Now we can focus on the &lt;code&gt;Resources&lt;/code&gt; section where we declare the AWS resources you want CloudFormation to create or manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a policy store
&lt;/h2&gt;

&lt;p&gt;Now our focus will be to add a configuration for a policy store. First, we need to define the &lt;code&gt;validation_settings&lt;/code&gt;. It specifies the validation setting for this policy store. In our use-case, we would like to be &lt;code&gt;strict&lt;/code&gt; as we will add schema and check the validation of our authorization requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;PolicyStore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::PolicyStore&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Policy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;store&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scenario"&lt;/span&gt;
      &lt;span class="na"&gt;ValidationSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're declaring a resource of type &lt;code&gt;AWS::VerifiedPermissions::PolicyStore&lt;/code&gt;, which represents a container in AVP where we will store policies. The &lt;code&gt;Description&lt;/code&gt; nested within Properties gives our policy store a description. Moreover, we've added validation settings setup as strict.&lt;/p&gt;

&lt;p&gt;Now if we deploy it, we will have an empty policy store with a validation mode setup as strict. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Schema
&lt;/h2&gt;

&lt;p&gt;Now we want to add a schema, which you can find &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/schema.json"&gt;here&lt;/a&gt;. As you can see, it is a JSON file that we need to have. Let's update the configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;PolicyStore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::PolicyStore&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Policy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;store&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scenario"&lt;/span&gt;
      &lt;span class="na"&gt;ValidationSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;
      &lt;span class="na"&gt;Schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CedarJson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"DocumentManagementPlatform": {&lt;/span&gt;
              &lt;span class="s"&gt;"entityTypes": {&lt;/span&gt;
                &lt;span class="s"&gt;"User": {&lt;/span&gt;
                  &lt;span class="s"&gt;"shape": {&lt;/span&gt;
                    &lt;span class="s"&gt;"type": "Record",&lt;/span&gt;
                    &lt;span class="s"&gt;"attributes": {}&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;},&lt;/span&gt;
                &lt;span class="s"&gt;"Document": {&lt;/span&gt;
                  &lt;span class="s"&gt;"shape": {&lt;/span&gt;
                    &lt;span class="s"&gt;"type": "Record",&lt;/span&gt;
                    &lt;span class="s"&gt;"attributes": {}&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;},&lt;/span&gt;
              &lt;span class="s"&gt;"actions": {&lt;/span&gt;
                &lt;span class="s"&gt;"View": {&lt;/span&gt;
                  &lt;span class="s"&gt;"appliesTo": {&lt;/span&gt;
                    &lt;span class="s"&gt;"principalTypes": ["User"],&lt;/span&gt;
                    &lt;span class="s"&gt;"resourceTypes": ["Document"]&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;},&lt;/span&gt;
                &lt;span class="s"&gt;"Edit": {&lt;/span&gt;
                  &lt;span class="s"&gt;"appliesTo": {&lt;/span&gt;
                    &lt;span class="s"&gt;"principalTypes": ["User"],&lt;/span&gt;
                    &lt;span class="s"&gt;"resourceTypes": ["Document"]&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;}&lt;/span&gt;
            &lt;span class="s"&gt;}&lt;/span&gt;
          &lt;span class="s"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, we've added a schema to our policy store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Store ID
&lt;/h2&gt;

&lt;p&gt;Before we jump into the policies, we need to tackle one important thing in our template. We would like to know the ID of our policy store, so we can easily find it, and check our Policy Store, or pass it to the resources that will use it (for instance Lambda function which will make requests to AVP later on).&lt;/p&gt;

&lt;p&gt;So to have it, we need to use Cloudformation &lt;code&gt;Outputs&lt;/code&gt; which specifies the values that are returned whenever you view your stack's properties.&lt;/p&gt;

&lt;p&gt;We can easily add it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Identifier&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Amazon&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Verified&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Permissions&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;policy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;store."&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual !Ref directive within Value is an &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html"&gt;intrinsic function&lt;/a&gt; used to retrieve the ID of a resource defined in the same template. In our case, &lt;code&gt;!Ref PolicyStore&lt;/code&gt; gets the ID of the PolicyStore resource created by the stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding policies
&lt;/h2&gt;

&lt;p&gt;Now, it's time for the final step, adding policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/allow_policy.cedar"&gt;this allow policy&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/deny_policy.cedar"&gt;this deny policy&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we can add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;AllowPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::Policy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
      &lt;span class="na"&gt;Definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Static&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;view&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;permit (&lt;/span&gt;
                &lt;span class="s"&gt;principal,&lt;/span&gt;
                &lt;span class="s"&gt;action in [DocumentManagementPlatform::Action::"View"],&lt;/span&gt;
                &lt;span class="s"&gt;resource&lt;/span&gt;
            &lt;span class="s"&gt;);&lt;/span&gt;

  &lt;span class="na"&gt;DenyPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::Policy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
      &lt;span class="na"&gt;Definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Static&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Forbid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;X&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viewing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;forbid(&lt;/span&gt;
              &lt;span class="s"&gt;principal == DocumentManagementPlatform::User::"xyz",&lt;/span&gt;
              &lt;span class="s"&gt;action in [DocumentManagementPlatform::Action::"View"],&lt;/span&gt;
              &lt;span class="s"&gt;resource&lt;/span&gt;
            &lt;span class="s"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Type: AWS::VerifiedPermissions::Policy&lt;/code&gt; is used for creating two policies.&lt;/li&gt;
&lt;li&gt;As any policy is part of that policy store, we needed to reference the Policy Store ID.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Definition&lt;/code&gt;, we've used &lt;code&gt;static&lt;/code&gt;, which indicates that the policy is static – it's not dynamically created from a template but is rather a fixed definition.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Statement&lt;/code&gt; we just need to pass the definition in Cedar language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole file will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2010-09-09"&lt;/span&gt;

&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;IaC for AVP&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PolicyStore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::PolicyStore&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Policy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;store&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scenario"&lt;/span&gt;
      &lt;span class="na"&gt;ValidationSettings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;STRICT&lt;/span&gt;
      &lt;span class="na"&gt;Schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CedarJson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"DocumentManagementPlatform": {&lt;/span&gt;
              &lt;span class="s"&gt;"entityTypes": {&lt;/span&gt;
                &lt;span class="s"&gt;"User": {&lt;/span&gt;
                  &lt;span class="s"&gt;"shape": {&lt;/span&gt;
                    &lt;span class="s"&gt;"type": "Record",&lt;/span&gt;
                    &lt;span class="s"&gt;"attributes": {}&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;},&lt;/span&gt;
                &lt;span class="s"&gt;"Document": {&lt;/span&gt;
                  &lt;span class="s"&gt;"shape": {&lt;/span&gt;
                    &lt;span class="s"&gt;"type": "Record",&lt;/span&gt;
                    &lt;span class="s"&gt;"attributes": {}&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;},&lt;/span&gt;
              &lt;span class="s"&gt;"actions": {&lt;/span&gt;
                &lt;span class="s"&gt;"View": {&lt;/span&gt;
                  &lt;span class="s"&gt;"appliesTo": {&lt;/span&gt;
                    &lt;span class="s"&gt;"principalTypes": ["User"],&lt;/span&gt;
                    &lt;span class="s"&gt;"resourceTypes": ["Document"]&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;},&lt;/span&gt;
                &lt;span class="s"&gt;"Edit": {&lt;/span&gt;
                  &lt;span class="s"&gt;"appliesTo": {&lt;/span&gt;
                    &lt;span class="s"&gt;"principalTypes": ["User"],&lt;/span&gt;
                    &lt;span class="s"&gt;"resourceTypes": ["Document"]&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;
                &lt;span class="s"&gt;}&lt;/span&gt;
              &lt;span class="s"&gt;}&lt;/span&gt;
            &lt;span class="s"&gt;}&lt;/span&gt;
          &lt;span class="s"&gt;}&lt;/span&gt;

  &lt;span class="na"&gt;AllowPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::Policy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
      &lt;span class="na"&gt;Definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Static&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;view&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;permit (&lt;/span&gt;
                &lt;span class="s"&gt;principal,&lt;/span&gt;
                &lt;span class="s"&gt;action in [DocumentManagementPlatform::Action::"View"],&lt;/span&gt;
                &lt;span class="s"&gt;resource&lt;/span&gt;
            &lt;span class="s"&gt;);&lt;/span&gt;

  &lt;span class="na"&gt;DenyPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::VerifiedPermissions::Policy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
      &lt;span class="na"&gt;Definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Static&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Forbid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;X&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;viewing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;documents"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;forbid(&lt;/span&gt;
              &lt;span class="s"&gt;principal == DocumentManagementPlatform::User::"xyz",&lt;/span&gt;
              &lt;span class="s"&gt;action in [DocumentManagementPlatform::Action::"View"],&lt;/span&gt;
              &lt;span class="s"&gt;resource&lt;/span&gt;
            &lt;span class="s"&gt;);&lt;/span&gt;

&lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;PolicyStoreId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Identifier&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Amazon&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Verified&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Permissions&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;policy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;store."&lt;/span&gt;
    &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PolicyStore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Now that we have everything, let's try to deploy our template.&lt;/p&gt;

&lt;p&gt;Navigate to the AWS console, and open Cloudformation service. Inside the Cloudformation service in the AWS console, press &lt;code&gt;Create a new stack&lt;/code&gt; with the option &lt;code&gt;With existing resources (import resources)&lt;/code&gt;. Use the &lt;code&gt;Template is ready&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Overall, we have 3 options for deploying our Cloudformation, either by storing it in S3 (if you use SAM or Serverless Framework you will be aware of that), you can upload it (which we will use), or you can deploy it from your repo. Here is a great article on &lt;a href="https://aws.amazon.com/blogs/devops/automate-safe-aws-cloudformation-deployments-from-github/"&gt;that&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time, use the &lt;code&gt;Upload a template file&lt;/code&gt; option.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach the &lt;code&gt;avp.yaml&lt;/code&gt; file and then for &lt;code&gt;Stack name&lt;/code&gt; create a name, you can leave the rest of the configuration unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhv54htb8f9ic577q2l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhv54htb8f9ic577q2l3.png" alt="upload" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we check the &lt;code&gt;Designer&lt;/code&gt; option it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd34d2kr1n5rnrvwzonom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd34d2kr1n5rnrvwzonom.png" alt="Designer" width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach the &lt;code&gt;avp.yaml&lt;/code&gt; file and then for &lt;code&gt;Stack name&lt;/code&gt; create a name, you can leave the rest of the configuration unchanged.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review a stack, accept capabilities, and deploy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After a couple of minutes everything will be deployed. In the resources tab, you can see 3 resources (AVP policy store, and 2 access policies), and in the output section, you will AVP policy store ID, which you can grab and check the resources in the AVP service.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7lbdgcytyd18yd0373t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7lbdgcytyd18yd0373t.png" alt="Resources" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8jqvyi2ctw8a7kepcep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8jqvyi2ctw8a7kepcep.png" alt="Outputs" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to grab the Policy Store ID and check it in AVP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv95agwgpqcnb9eajmpk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv95agwgpqcnb9eajmpk6.png" alt="AVP" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;As you can see, it's quite simple to create a basic project with AVP using Cloudformation.&lt;/p&gt;

&lt;p&gt;If you're interested in more Cloudformation templates, I've recreated all of the AVP-CLI scenarios in CF, you can find them &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/tree/main/cloudformation/"&gt;here&lt;/a&gt;. In the next blogpost &lt;a href="https://dev.to/aws-heroes/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiv-avp-getting-started-478f"&gt;we will tackle AVP getting started feature&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's all for today. I encourage you to experiment on your own.&lt;/p&gt;

</description>
      <category>avp</category>
      <category>authorization</category>
      <category>cedar</category>
      <category>cloudformation</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XII: Terraform</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Mon, 15 Jan 2024 22:46:29 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xii-terraform-598d</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xii-terraform-598d</guid>
      <description>&lt;p&gt;Welcome back to my blog post series dedicated to building authorization using Cedar and Amazon Verified Permissions. In a previous blogpost we've learned about &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xi-batch-authorization-mj8"&gt;batch authorization&lt;/a&gt;. Today, we will take a look at how to build AVP with one of the most popular Infrastructure as Code (IaC) tool - &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Let's assume that we would like to recreate one of the scenarios from avp-cli in Terraform, for example, the &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/documentsScenario.json" rel="noopener noreferrer"&gt;documents scenario&lt;/a&gt;. This is a basic scenario with a document management platform schema and two policies (&lt;code&gt;Allow all users to view all documents&lt;/code&gt; and &lt;code&gt;Forbid user X from viewing any documents&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To recreate this, we need:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7tx6zmpqeh8z5fvjq5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7tx6zmpqeh8z5fvjq5j.png" alt="policy store"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;policy store&lt;/strong&gt;, which is a container for our policies. In such a container, we keep all policies, as well as the schema. It's important to remember that later when using AVP for authorization requests, we send requests against a specific policy store.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;schema&lt;/strong&gt; is the structure of all available entities for a given policy store. In short, it defines what entities are available for our authorization system, including available actions, principals, and resources. The schema not only informs us about the available entities but also validates the correctness of authorization requests.&lt;/p&gt;

&lt;p&gt;Finally, we will also need to add our &lt;strong&gt;policies&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform provider for AVP
&lt;/h2&gt;

&lt;p&gt;In the context of AWS, a Terraform provider is a plugin that allows Terraform to interact with AWS services and resources. It provides the necessary tools and interfaces for managing the lifecycle of various AWS resources through Terraform's infrastructure as code approach.&lt;/p&gt;

&lt;p&gt;If we check the support for the Terraform AWS Provider &lt;a href="https://github.com/hashicorp/terraform-provider-aws/issues/32158" rel="noopener noreferrer"&gt;here&lt;/a&gt; (state for the date of publishing this article), we will see that the service is not yet fully supported. Last week, after more than half a year, support for creating a policy store was added. Additionally, we have the configuration to add template policies. However, the identity source is in the form of a PR draft, and there is no PR yet for the ability to create policies.&lt;/p&gt;

&lt;p&gt;Does this mean that we currently cannot use AVP with Terraform? Not necessarily, as the &lt;a href="https://github.com/hashicorp/terraform-provider-awscc" rel="noopener noreferrer"&gt;Cloud Control Provider&lt;/a&gt; comes to our rescue.&lt;/p&gt;

&lt;p&gt;What is cool about that provider, is that it's auto-generated straight from AWS CloudFormation schemas, meaning it's always in sync with the latest AWS features - no more waiting for manual updates! &lt;/p&gt;

&lt;p&gt;Weekly deployments (always on Thursday) with the newest AWS enhancements. This provider taps into the AWS Cloud Control API so you can expect new AWS offerings (supported via Cloudformation) in Terraform almost as soon as they're released.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's build!
&lt;/h2&gt;

&lt;p&gt;The example we will create is not intended for production use; it has been created for educational purposes. However, in the future, I will add more advanced projects with Terraform to the &lt;a href="https://github.com/Pigius/avp-terraform" rel="noopener noreferrer"&gt;repository&lt;/a&gt;, also more suited for production use.&lt;/p&gt;

&lt;p&gt;For our example, we will need two types of resources from the Terraform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/verifiedpermissions_policy_store" rel="noopener noreferrer"&gt;policy store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/verifiedpermissions_policy" rel="noopener noreferrer"&gt;policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we know everything, we can start building the project in Terraform. At the end, a link to the repository will be provided, which you can easily clone.&lt;/p&gt;

&lt;p&gt;Let's assume we have a new repository, and we start with an empty &lt;code&gt;main.tf&lt;/code&gt; file. In order to configure the provider, you will need to employ the configuration blocks shown here, while specifying your preferred region:&lt;/p&gt;

&lt;p&gt;main.tf&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;awscc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/awscc"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.68.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"awscc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create a policy store
&lt;/h2&gt;

&lt;p&gt;Now our focus will be to add a configuration for a policy store. First, we need to define the &lt;code&gt;validation_settings&lt;/code&gt;. It specifies the validation setting for this policy store. In our use-case, we would like to be &lt;code&gt;strict&lt;/code&gt; as we will add schema and check the validation of our authorization requests, let's add this code to our &lt;code&gt;main.tf&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"awscc_verifiedpermissions_policy_store"&lt;/span&gt; &lt;span class="s2"&gt;"policy_store"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;validation_settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"STRICT"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This line declares a new resource of type &lt;code&gt;awscc_verifiedpermissions_policy_store&lt;/code&gt;, which is provided by the AWS CC provider. The &lt;code&gt;policy_store&lt;/code&gt; is a local name given to this resource instance, which can be used to refer to it within the Terraform configuration. We've added validation settings setup as strict.&lt;/p&gt;

&lt;p&gt;At this point, we could easily deploy our configuration via:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-profile name terraform init
&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-profile name terraform apply


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which will create an empty policy store with validation settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Schema
&lt;/h2&gt;

&lt;p&gt;Now we want to add a schema, which you can find &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/schema.json" rel="noopener noreferrer"&gt;here&lt;/a&gt;. As you can see, it is a JSON file that we need to have. Let's add a &lt;code&gt;schema.json&lt;/code&gt; file to our main project directory, and then update our configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"awscc_verifiedpermissions_policy_store"&lt;/span&gt; &lt;span class="s2"&gt;"policy_store"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;validation_settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"STRICT"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cedar_json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/schema.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This new line defines the schema for the policy store using the &lt;code&gt;cedar_json&lt;/code&gt; attribute. &lt;br&gt;
The &lt;code&gt;file("${path.module}/schema.json")&lt;/code&gt; function reads the contents of a file named &lt;code&gt;schema.json&lt;/code&gt; located in the same directory as the Terraform module &lt;code&gt;(${path.module}&lt;/code&gt; refers to the current module's directory). &lt;/p&gt;

&lt;p&gt;The content of this file, which should be in JSON format, is used as the schema for the policy store.&lt;/p&gt;

&lt;p&gt;Now when we deploy changes we will schema in our policy store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek6fvysfs3i7tezddgd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek6fvysfs3i7tezddgd.png" alt="Schema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding policies
&lt;/h2&gt;

&lt;p&gt;Now, it's time for the final step, adding policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/allow_policy.cedar" rel="noopener noreferrer"&gt;this allow policy&lt;/a&gt; in the root directory under the name of &lt;code&gt;allow_policy.cedar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/deny_policy.cedar" rel="noopener noreferrer"&gt;this deny policy&lt;/a&gt; in the root directory under the name of &lt;code&gt;deny_policy.cedar&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Later, we can add this config to &lt;code&gt;main.tf&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"awscc_verifiedpermissions_policy"&lt;/span&gt; &lt;span class="s2"&gt;"allow_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_store_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;awscc_verifiedpermissions_policy_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;definition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;static&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;statement&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/allow_policy.cedar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow all users to view all documents"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"awscc_verifiedpermissions_policy"&lt;/span&gt; &lt;span class="s2"&gt;"forbid_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_store_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;awscc_verifiedpermissions_policy_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;definition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;static&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;statement&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${path.module}/deny_policy.cedar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Forbid user X from viewing any documents"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;resource "awscc_verifiedpermissions_policy" "allow_policy":&lt;/code&gt; declares a new resource of type &lt;code&gt;awscc_verifiedpermissions_policy&lt;/code&gt;, named &lt;code&gt;allow_policy&lt;/code&gt;. This resource represents a policy in the AVP Policy Store (similar to the &lt;code&gt;forbid_policy&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;policy_store_id = awscc_verifiedpermissions_policy_store.policy_store.id:&lt;/code&gt; This line specifies the ID of the Policy Store where this policy will be created. It references the id of the previously defined &lt;code&gt;awscc_verifiedpermissions_policy_store&lt;/code&gt; resource named &lt;code&gt;policy_store&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the definition block of the policy we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;static:&lt;/code&gt; Indicates that this is a static policy definition.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;statement = file("${path.module}/allow_policy.cedar"):&lt;/code&gt; The policy statement is defined in an external file named
&lt;code&gt;allow_policy.cedar&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file function reads the contents of this file, which contain the policy written in Cedar policy language. This policy is expected to specify conditions under which access is allowed.&lt;/p&gt;

&lt;p&gt;The repo for this project can be found &lt;a href="https://github.com/Pigius/avp-terraform/tree/main/basic-example" rel="noopener noreferrer"&gt;here&lt;/a&gt; with proper readme. I've made small improvements to the project (adding outputs to see policy store id and region), and when you deploy it you can see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

wscc_verifiedpermissions_policy_store.policy_store: Creating...
awscc_verifiedpermissions_policy_store.policy_store: Creation complete after 1s [id=VUdm7eCYdN3xW8CeJrrVx8]
awscc_verifiedpermissions_policy.allow_policy: Creating...
awscc_verifiedpermissions_policy.forbid_policy: Creating...
awscc_verifiedpermissions_policy.allow_policy: Creation complete after 9s [id=VKo7ca1kCNHSpVhLfHgrYs|VUdm7eCYdN3xW8CeJrrVx8]
awscc_verifiedpermissions_policy.forbid_policy: Creation complete after 9s [id=VN4qXzoMRhLqxa51KY3WPr|VUdm7eCYdN3xW8CeJrrVx8]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

aws_region = "eu-west-1"
policy_store_id = "VUdm7eCYdN3xW8CeJrrVx8"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0pekc2j2v88enk240m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0pekc2j2v88enk240m9.png" alt="Policies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;As you can see, it's quite simple to create a basic project with AVP using Terraform. That's all for today. I encourage you to experiment on your own.&lt;/p&gt;

&lt;p&gt;If you're interested in more TF templates, I've recreated all of the AVP-CLI scenarios in TF, you can find them &lt;a href="https://github.com/Pigius/awesome-amazon-verified-permissions-and-cedar/tree/main/terraform" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the next blogpost, you can read about usage &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xiii-cloudformation-47d2"&gt;AVP with Cloudformation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part XI: Batch Authorization</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Wed, 06 Dec 2023 17:12:10 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xi-batch-authorization-mj8</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xi-batch-authorization-mj8</guid>
      <description>&lt;p&gt;Hello again in the series about building authorization with Amazon Verified Permissions (AVP) and Cedar. In the previous post, we focused on the &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-x-avp-cli-aih"&gt;AVP-CLI tool&lt;/a&gt; (which we will also use today). This time, we will focus on a new feature called batch authorization, which, in my opinion, is a game changer in terms of using AVP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch Authorization
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2023/11/amazon-verified-permissions-supports-batch-authorization/"&gt;Batch authorization&lt;/a&gt; in AVP allows you to process up to 30 authorization decisions for a single principal or resource in a single API call. The entities of an API request can contain up to 100 principals and up to 100 resources.&lt;/p&gt;

&lt;p&gt;One of the many objections to AVP was the theory that it is too expensive as a service. Now, where we can make many requests in one, it allows for a significant reduction in &lt;a href="https://aws.amazon.com/verified-permissions/pricing/"&gt;costs&lt;/a&gt; and an increase in performance, as everything goes in one request (&lt;strong&gt;and we will pay just for one request&lt;/strong&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;isAuthorized&lt;/code&gt; vs &lt;code&gt;batchIsAuthorized&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Traditionally, the &lt;code&gt;isAuthorized&lt;/code&gt; action in AVP is used to process a single authorization request (If you use Test Bench in the AVP console, the AVP is using this API operation to make the authorization decision). This involves sending an individual request for each authorization decision, which can be resource-intensive, especially when multiple decisions are needed.&lt;/p&gt;

&lt;p&gt;An example of an &lt;code&gt;isAuthorized&lt;/code&gt; request structure can be found below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"policyStoreId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-policy-store-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Principal::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"entity_id"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Action::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"action_id"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Resource::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resource_id"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityList"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This JSON file outlines the format for a typical single authorization request, including details about the principal, action, resource, entities, and context. More examples of authorization requests you can found in the avp-cli &lt;a href="https://github.com/Pigius/avp-cli/tree/main/scenarios"&gt;scenarios&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;decision:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ALLOW'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;determiningPolicies:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;policyId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ID_OF_THE_POLICY'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;errors:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;decision&lt;/strong&gt; - authz decision that indicated if the authorization request should be allowed or denied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;determiningPolicies&lt;/strong&gt; - The list of determining policies used to make the authorization decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;errors&lt;/strong&gt; - Errors that occurred while making an authorization decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;batchIsAuthorized&lt;/code&gt; &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/apireference/API_BatchIsAuthorized.html"&gt;action&lt;/a&gt;, however, allows for processing multiple authorization requests in a single API call. This is particularly useful when you need to make several authorization decisions simultaneously, either for one principal across multiple resources or for one resource across multiple principals. The structure of a &lt;code&gt;batchIsAuthorized&lt;/code&gt; request is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"policyStoreId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-policy-store-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entityList"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Principal::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"entity_id"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Resource::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"entity_id"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;entities&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;included&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"requests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Principal::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"entity_id"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Action::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"action_id"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Resource::Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resource_id"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Additional&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;requests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;included&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this format, the entities section defines a common list of entities (principals and resources) involved in the batch request. The requests array then specifies individual authorization requests, each comprising a principal, action, resource, and context.&lt;/p&gt;

&lt;p&gt;The response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"determiningPolicies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"policyId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"policyId"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"View"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"determiningPolicies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"policyId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"policyId"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GetDiscount"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, we have &lt;code&gt;results&lt;/code&gt; which is a series of Allow or Deny decisions for each request and the policies that produced them. We have an array of authorization decision objects, and with that, we have a &lt;code&gt;request&lt;/code&gt; key, which is the authorization request that initiated the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  E-commerce example
&lt;/h2&gt;

&lt;p&gt;To demonstrate the power of batch authorization, I've added a new scenario in the AVP CLI tool - the &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceBatchScenario/ecommerceBatchScenario.json"&gt;Batch Scenario&lt;/a&gt; Scenario. This scenario simulates an e-commerce platform with various user roles, actions, and policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxjzraam9o6b4h71ibg9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxjzraam9o6b4h71ibg9.png" alt="Schema" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceBatchScenario/schema.json"&gt;schema&lt;/a&gt; includes entities like &lt;code&gt;Product&lt;/code&gt;, &lt;code&gt;Role&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt;, and &lt;code&gt;Order&lt;/code&gt;, each with specific attributes. Actions such as &lt;code&gt;View&lt;/code&gt;, &lt;code&gt;Edit&lt;/code&gt;, &lt;code&gt;Buy&lt;/code&gt;, &lt;code&gt;GetDiscount&lt;/code&gt;, and &lt;code&gt;Preorder&lt;/code&gt; are defined to mimic typical e-commerce operations.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fel7lawgpnuzwgeaynrd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fel7lawgpnuzwgeaynrd4.png" alt="Entity types" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Policies
&lt;/h2&gt;

&lt;p&gt;We've crafted policies that cater to different user roles and scenarios:&lt;/p&gt;
&lt;h3&gt;
  
  
  Admin Role - Order Editing Policy
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;permit(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Role::&lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Action::&lt;/span&gt;&lt;span class="s2"&gt;"Edit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;resource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;resource.status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This policy allows users with the admin role to edit orders. However, it restricts editing based on the order's status. Admins can only edit orders that are in the "paid" status, ensuring that orders in other stages of processing are not altered.&lt;/p&gt;
&lt;h3&gt;
  
  
  Customer Role - Basic Access Policy
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;permit(&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Role::&lt;/span&gt;&lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Action::&lt;/span&gt;&lt;span class="s2"&gt;"Buy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Action::&lt;/span&gt;&lt;span class="s2"&gt;"View"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;resource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Customers are granted the ability to perform basic actions like &lt;code&gt;Buy&lt;/code&gt; and &lt;code&gt;View&lt;/code&gt; on products. This policy is straightforward and applies to all customers, allowing them to browse and purchase products from the e-commerce platform.&lt;/p&gt;
&lt;h3&gt;
  
  
  Premium Membership - Special Privileges Policy
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;permit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;principal,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Action::&lt;/span&gt;&lt;span class="s2"&gt;"GetDiscount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="err"&gt;EcommerceStore::Action::&lt;/span&gt;&lt;span class="s2"&gt;"Preorder"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;resource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;principal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;premiumMembership&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;principal.premiumMembership&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This policy is designed for users with a premium membership. It allows them to access special actions like &lt;code&gt;GetDiscount&lt;/code&gt; and &lt;code&gt;Preorder&lt;/code&gt; on products. The policy checks if the user has a &lt;code&gt;premiumMembership&lt;/code&gt; attribute set to &lt;code&gt;true&lt;/code&gt;, indicating their premium status.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing Policies
&lt;/h2&gt;

&lt;p&gt;I've designed two types of tests for this scenario: single authorization requests and batch authorization requests, each serving a unique purpose in our testing strategy.&lt;/p&gt;
&lt;h3&gt;
  
  
  Single Authorization Request Tests
&lt;/h3&gt;

&lt;p&gt;These tests focus on individual authorization requests, assessing one action at a time. They help us verify the specific behavior of our policies in granular scenarios. Examples include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin Editing Paid Orders:&lt;/strong&gt; Checks if an admin user (Daniel) can edit orders with the status "paid."&lt;br&gt;
&lt;strong&gt;Customer Viewing Products:&lt;/strong&gt; Verifies that a customer (Tom) can view any product.&lt;br&gt;
&lt;strong&gt;Premium Member Discounts:&lt;/strong&gt; Ensures a premium member (Ken) can access discounts on products.&lt;/p&gt;
&lt;h3&gt;
  
  
  Batch Authorization Tests
&lt;/h3&gt;

&lt;p&gt;Batch tests are more comprehensive, allowing us to evaluate multiple authorization requests in a single API call. We've prepared two types of batch tests:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource-Oriented Batch Test:&lt;/strong&gt; This test checks multiple resources against a single principal to determine what actions they can perform. For instance, it can assess which orders an admin user is authorized to edit. This approach is particularly useful for scenarios where a user's role or status might grant them varying levels of access across different resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principal-Oriented Batch Test:&lt;/strong&gt; Conversely, this test evaluates multiple actions for a single principal on a specific resource. It helps us understand the range of actions a user (like Ken) can perform on a particular product. This type of test is essential for applications where user permissions vary based on the resource they are interacting with.&lt;/p&gt;

&lt;p&gt;To test the &lt;code&gt;BatchIsAuthorized&lt;/code&gt;, we cannot do this through the Test Bench, where we can test our &lt;code&gt;isAuthorized&lt;/code&gt; requests to AVP. To solve this problem, I added the option to test &lt;code&gt;batchIsAuthorized&lt;/code&gt; to avp-cli. You need to select it from the manual approach option, select make a batch authorization decision, and provide a path to the json test file (use &lt;code&gt;structureBatchAuthorizationRequest.json&lt;/code&gt; as a reference) It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Manual approach
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Make a batch authorization decision
? Enter the path &lt;span class="k"&gt;for &lt;/span&gt;batch authorization json &lt;span class="nb"&gt;test &lt;/span&gt;file structureBatchAuthorizationRequest.json
Making batch authorization decision...
┌──────────┬──────────────────────────────┬────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────
│ Decision │ Determining Policies         │ Errors             │ Policy Store ID              │ Principal                    │ Action                       │ Resource                     
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────
│ ALLOW    │ Vz4ZUYv36HwY6v65XTix4i       │                    │ JahHZkVn82ryyn5qMfBXG9       │ EcommerceStore::User::Ken    │ EcommerceStore::Action::View │ EcommerceStore::Product::Hat 
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────
│ ALLOW    │ 4ZbngosNQ8ZCbaBcEQ4SE9       │                    │ JahHZkVn82ryyn5qMfBXG9       │ EcommerceStore::User::Ken    │ EcommerceStore::Action::GetD │ EcommerceStore::Product::Hat 
│          │                              │                    │                              │                              │ iscount                      │                              
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────
│ ALLOW    │ Vz4ZUYv36HwY6v65XTix4i       │                    │ JahHZkVn82ryyn5qMfBXG9       │ EcommerceStore::User::Ken    │ EcommerceStore::Action::Buy  │ EcommerceStore::Product::Hat 
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────
│ ALLOW    │ 4ZbngosNQ8ZCbaBcEQ4SE9       │                    │ JahHZkVn82ryyn5qMfBXG9       │ EcommerceStore::User::Ken    │ EcommerceStore::Action::Preo │ EcommerceStore::Product::Hat 
│          │                              │                    │                              │                              │ rder                         │                              
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────
│ DENY     │                              │                    │ JahHZkVn82ryyn5qMfBXG9       │ EcommerceStore::User::Ken    │ EcommerceStore::Action::Edit │ EcommerceStore::Product::Hat 
└──────────┴──────────────────────────────┴────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our Batch Scenario, we have also the option to test prepared batch authorization test requests like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Test Batch Authorization Scenario
? Choose a scenario ecommerceBatchScenario
? Choose a &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;Use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
❯ Checking multiple actions &lt;span class="k"&gt;for &lt;/span&gt;a single principal &lt;span class="o"&gt;(&lt;/span&gt;For specific product, What action can be taken by Ken 
  Checking multiple resources, to check which orders can admin edit.
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to update &lt;code&gt;policy_store_id&lt;/code&gt; in &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceBatchScenario/multiple_actions_batch_test.json#L2"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceBatchScenario/multiple_resource_batch_test.json#L2"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example test structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"policyStoreId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-policy-store-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entityList"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"premiumMembership"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"boolean"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"requests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"View"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GetDiscount"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Buy"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Preorder"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ken"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"actionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Edit"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommerceStore::Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hat"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"contextMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Batch authorization in AVP offers a powerful and efficient way to handle multiple authorization requests simultaneously (up to 30 requests principal or request oriented, with up to 100 entities (principals and resources)). &lt;/li&gt;
&lt;li&gt;It will decrease costs for requests to AVP as well as improve performance.&lt;/li&gt;
&lt;li&gt;Keep in mind that you cannot use the &lt;code&gt;BatchIsAuthorized&lt;/code&gt; with the &lt;code&gt;token&lt;/code&gt; option, it's not supported currently.&lt;/li&gt;
&lt;li&gt;Keep in mind that you cannot use the &lt;code&gt;BatchIsAuthorized&lt;/code&gt; within the Test Bench currently.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>cedar</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part X: AVP-CLI</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Tue, 15 Aug 2023 13:09:15 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-x-avp-cli-aih</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-x-avp-cli-aih</guid>
      <description>&lt;p&gt;In previous &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-ix-hierarchies-and-abac-8gm"&gt;article&lt;/a&gt;, we delved deep into the world of hierarchies and ABAC (Attribute-Based Access Control) within the AWS Verified Permissions (AVP). We've learned how to deal with hierarchy and ABAC with practical example.&lt;/p&gt;

&lt;p&gt;Today, we shift our focus to a tool that aims to make your interactions with AVP smoother and more intuitive: the open-source &lt;a href="https://www.npmjs.com/package/avp-cli"&gt;avp-cli&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture behind avp-cli
&lt;/h2&gt;

&lt;p&gt;AWS Verified Permissions (AVP) is a relatively new service. While AWS provides comprehensive documentation, workshops, and examples, there was a noticeable gap in community-driven resources. For developers like me, eager to dive deep and experiment with AVP, the initial journey was filled with manual setups via the AWS console. This process was not only repetitive but also prone to errors, especially when dealing with intricate components like schemas and policy definitions.&lt;/p&gt;

&lt;p&gt;Imagine the hassle of setting up multiple policy stores, schemas, and policies, only to realize you made a small mistake and had to start over. Or the challenge of managing and deleting resources, especially when you find yourself with 85 policy stores cluttering your AWS account!&lt;/p&gt;

&lt;p&gt;This is where the idea of avp-cli was born. I envisioned a tool that would simplify these interactions, making the process of learning and experimenting with AVP more efficient and enjoyable. The initial versions of the CLI focused on basic API operations, such as creating and deleting policy stores, schemas, and policies.&lt;/p&gt;

&lt;p&gt;However, as I delved deeper into AVP, I had an "aha" moment. Why not create predefined scenarios? These scenarios would encapsulate a policy store, schema, and set of policies, providing a ready-to-use example for developers to play with, experiment, and modify. This not only reduced the setup time but also provided a tangible context for understanding how different AVP components interacted, as well as differences between Cedar and AVP format.&lt;/p&gt;

&lt;p&gt;The most recent addition to avp-cli has been the test scenarios. These are designed to validate that the policies and configurations set up through the scenarios work as expected. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is avp-cli?
&lt;/h2&gt;

&lt;p&gt;The avp-cli is a command-line interface tool designed to streamline your interactions with the AWS Verified Permissions (AVP) service. Its primary goal is to enhance the learning and prototyping experience for developers diving into AVP. Whether you're a beginner trying to grasp the basics or an advanced user looking to experiment with complex policies, avp-cli offers a set of functionalities tailored to your needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;🚀 Welcome to the AVP CLI Tool!
Designed to streamline your interactions with the AWS Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service.
🔧 Create, manage, and delete policy stores, schemas, and policies. Plus, deploy and &lt;span class="nb"&gt;test &lt;/span&gt;with predefined scenarios!
⚠️ Ensure your AWS credentials are correctly &lt;span class="nb"&gt;set &lt;/span&gt;up before proceeding.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? &lt;span class="o"&gt;(&lt;/span&gt;Use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
❯ Test Scenario 
  Manual approach 
  Use prepared scenarios 
  Exit 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it's essential to note that while avp-cli is a powerful tool for learning and experimentation, it is not intended for production workloads. Always ensure that tools and configurations used in production environments are thoroughly vetted and adhere to best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features of avp-cli
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;API operations:&lt;/strong&gt; avp-cli supports all API operations provided by the AWS Verified Permissions service. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating, listing, updating, and deleting policy stores.&lt;/li&gt;
&lt;li&gt;Adding and retrieving schemas.&lt;/li&gt;
&lt;li&gt;Creating, updating, retrieving, and deleting policies (both static and template-linked).&lt;/li&gt;
&lt;li&gt;Making authorization decisions (with or without Cognito Identity Token).&lt;/li&gt;
&lt;li&gt;Identity source and more...
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Manual approach
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? &lt;span class="o"&gt;(&lt;/span&gt;Use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
❯ Make an authorization decision 
  Make an authorization decision with Cognito Identity Token 
  Add Policy Template 
  Add Schema to a Policy Store 
  Add Static Policy 
  Add Template Policy 
  Create a Policy Store 
&lt;span class="o"&gt;(&lt;/span&gt;Move up and down to reveal more choices&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Scenarios:&lt;/strong&gt; One of the standout features of avp-cli is the predefined scenarios. These scenarios encapsulate a policy store, schema, and a set of policies, providing developers with ready-to-use examples. Each scenario is designed to showcase a specific feature or use-case of AVP, making it easier to understand its practical applications.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/documentsScenario/documentsScenario.json"&gt;Documents Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This is a basic scenario with a document management platform schema and two policies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceContextScenario/ecommerceContextScenario.json"&gt;Ecommerce with Context usage Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This scenario demonstrates the use of context in AVP. It allows customers to view products only when they are in the US region.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceGroupScenario/ecommerceGroupScenario.json"&gt;Ecommerce with Group usage Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This scenario demonstrates the use of Groups in AWS Verified Permissions. It allows customers who belong to the VIP group to preorder products.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommercePolicyTemplateScenario/ecommercePolicyTemplateScenario.json"&gt;Ecommerce with Policy Template usage Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This scenario demonstrates the use of policy templates and template-linked policies in AWS Verified Permissions. It allows sellers to list their own products.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceCognitoIntegrationScenario/ecommerceCognitoIntegrationScenario.json"&gt;Ecommerce with Cognito Integration usage Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This scenario demonstrates the use of Cognito integration in AWS Verified Permissions. It allows sellers to discount if they have agreed discount privilege. Refer to this &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb"&gt;blogpost&lt;/a&gt; for setup.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceHierarchyAndAbacScenario/ecommerceCognitoIntegrationScenario.json"&gt;Ecommerce with Hierarchy and ABAC Scenario&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This scenario demonstrates the use of Hierarchy and ABAC (with Entities) in AWS Verified Permissions. It allows sellers to sell car if department matches the car's department.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;⚠️ Ensure your AWS credentials are correctly &lt;span class="nb"&gt;set &lt;/span&gt;up before proceeding.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario Documents Scenario
Starting creating scenario: Documents Scenario
description: This is a basic scenario with a document management platform schema and two policies.
Policy store created with ID: 3rJVM5629fGKxxcuPg87es
Schema put successfully &lt;span class="k"&gt;for &lt;/span&gt;policy store ID: 3rJVM5629fGKxxcuPg87es
Static policy created with ID: 5FcwTty3sAvgJPQGp7rcji
Static policy created with ID: XqJb31ZJ9E2VBLzFxTY7Y2
┌────────────────────────────────────────┬────────────────────────────────────────┬────────────────────────────────────────┐
│ Policy ID                              │ Policy Store ID                        │ Created Date                           │
├────────────────────────────────────────┼────────────────────────────────────────┼────────────────────────────────────────┤
│ 5FcwTty3sAvgJPQGp7rcji                 │ 3rJVM5629fGKxxcuPg87es                 │ 2023-08-15 14:52                       │
├────────────────────────────────────────┼────────────────────────────────────────┼────────────────────────────────────────┤
│ XqJb31ZJ9E2VBLzFxTY7Y2                 │ 3rJVM5629fGKxxcuPg87es                 │ 2023-08-15 14:52                       │
└────────────────────────────────────────┴────────────────────────────────────────┴────────────────────────────────────────┘
Generating of the documentsScenario is finished. Open the AWS console to play around with that.

Consider testing it with our prepared &lt;span class="nb"&gt;test &lt;/span&gt;scenarios:
Either use &lt;span class="sb"&gt;`&lt;/span&gt;Test Scenario&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;main CLI to &lt;span class="k"&gt;select &lt;/span&gt;the specific &lt;span class="nb"&gt;test &lt;/span&gt;scenario, or use below path as argument to &lt;span class="sb"&gt;`&lt;/span&gt;IsAuthorized&lt;span class="sb"&gt;`&lt;/span&gt; from the manual approach option of the CLI:
 Remember to update the policy-store-id within files.
- ./scenarios/documentsScenario/allow_test_1.json &lt;span class="o"&gt;(&lt;/span&gt;User Daniel is allowed the ability to view &lt;span class="o"&gt;(&lt;/span&gt;action&lt;span class="o"&gt;)&lt;/span&gt; the Payslip &lt;span class="o"&gt;(&lt;/span&gt;resource&lt;span class="o"&gt;))&lt;/span&gt; allow
- ./scenarios/documentsScenario/deny_test_1.json &lt;span class="o"&gt;(&lt;/span&gt;User xyz is denied the ability to view &lt;span class="o"&gt;(&lt;/span&gt;action&lt;span class="o"&gt;)&lt;/span&gt; the Payslip &lt;span class="o"&gt;(&lt;/span&gt;resource&lt;span class="o"&gt;))&lt;/span&gt; forbid
- ./scenarios/documentsScenario/deny_test_2.json &lt;span class="o"&gt;(&lt;/span&gt;User Daniel is denied the ability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test Scenarios:&lt;/strong&gt; To complement the predefined scenarios, avp-cli also offers test scenarios. These are predefined sets of inputs and expected outcomes that allow users to test the policies and configurations set up by the scenarios. It's a seamless way to validate and troubleshoot configurations, ensuring they function as intended.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Test Scenario
? Choose a scenario documentsScenario
? Choose a &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;Use arrow keys&lt;span class="o"&gt;)&lt;/span&gt;
❯ User Daniel is allowed the ability to view &lt;span class="o"&gt;(&lt;/span&gt;action&lt;span class="o"&gt;)&lt;/span&gt; the Payslip &lt;span class="o"&gt;(&lt;/span&gt;resource&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;allow&lt;span class="o"&gt;)&lt;/span&gt; 
  User xyz is denied the ability to view &lt;span class="o"&gt;(&lt;/span&gt;action&lt;span class="o"&gt;)&lt;/span&gt; the Payslip &lt;span class="o"&gt;(&lt;/span&gt;resource&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;forbid&lt;span class="o"&gt;)&lt;/span&gt; 
  User Daniel is denied the ability to edit &lt;span class="o"&gt;(&lt;/span&gt;action&lt;span class="o"&gt;)&lt;/span&gt; the Payslip &lt;span class="o"&gt;(&lt;/span&gt;resource&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;forbid&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Choose a test User Daniel is allowed the ability to view (action) the Payslip (resource) (allow)
Making authorization decision...
┌──────────┬──────────────────────────────┬────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┬──────────────────────────────┐
│ Decision │ Determining Policies         │ Errors             │ Policy Store ID              │ Principal                    │ Action                       │ Resource                     │ Context                      │
├──────────┼──────────────────────────────┼────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┼──────────────────────────────┤
│ ALLOW    │ 5FcwTty3sAvgJPQGp7rcji       │                    │ 3rJVM5629fGKxxcuPg87es       │ DocumentManagementPlatform:: │ DocumentManagementPlatform:: │ DocumentManagementPlatform:: │ {}                           │
│          │                              │                    │                              │ User::Daniel                 │ Action::View                 │ Document::Payslip            │                              │
└──────────┴──────────────────────────────┴────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┴──────────────────────────────┘
? What would you like to do? (Use arrow keys)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dive in and experiment
&lt;/h2&gt;

&lt;p&gt;I encourage you to play around with avp-cli. Whether you're setting up a new policy store, experimenting with a scenario, or running a test, the tool is designed to make your AVP journey smoother and more insightful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cedar Policy Language Slack
&lt;/h2&gt;

&lt;p&gt;A significant portion of the success and functionality of avp-cli can be attributed to the invaluable support and guidance I received from the teams behind the Cedar Policy Language and AWS Verified Permissions (AVP) on the &lt;a href="https://communityinviter.com/apps/cedar-policy/cedar-policy-language"&gt;Cedar Policy Language Slack&lt;/a&gt;. I'd like to thank you all individuals at AWS who took the time to address my queries, clarify my doubts, and provide insights that were instrumental in shaping the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;As the AWS Verified Permissions service and Cedar continue to evolve, so will avp-cli. I'm particularly excited about the upcoming &lt;code&gt;is&lt;/code&gt; operator in Cedar and the potential to name policy-stores in AVP (which now is autogenrated string). Once these features are available, you can expect &lt;code&gt;avp-cli&lt;/code&gt; to incorporate them, ensuring the tool remains up-to-date and continues to serve the AVP community effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Feel free to read next &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-xi-batch-authorization-mj8"&gt;article&lt;/a&gt; from the series, about batch authorization.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>awscommunitybuilders</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part IX: Hierarchies and ABAC</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Fri, 11 Aug 2023 14:36:03 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-ix-hierarchies-and-abac-8gm</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-ix-hierarchies-and-abac-8gm</guid>
      <description>&lt;p&gt;Welcome back to our series on Amazon Verified Permissions (AVP)! In the previous article we've discussed how to &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb"&gt;integrate AVP with Cognito&lt;/a&gt;. Today, we're going to delve into a more advanced topic: hierarchies and entities in AVP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hierarchies vs Groups
&lt;/h2&gt;

&lt;p&gt;In one of a previous article, we've seen how to use groups in AVP to manage permissions for a set of users. Groups are a powerful tool for simplifying permission management, especially when you have a large number of users with similar roles. For example, in our e-commerce platform, we might have a group for VIP customers who have access to preorder some products.&lt;/p&gt;

&lt;p&gt;However, groups are not always sufficient to capture the full complexity of real-world authorization scenarios. For example, consider an e-commerce platform with a hierarchical customer structure, where permissions need to be inherited or overridden based on the customer's level in the hierarchy. In these cases, we need a more sophisticated way to model the relationships between users and resources. This is where hierarchies and entities come into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entities and Attributes in AVP
&lt;/h2&gt;

&lt;p&gt;In AVP, an entity is a representation of a principal, action, or resource in your application. Each entity has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An identifier&lt;/strong&gt;: This includes an entity type and an entity ID. For example, for a customer entity, the entity type might be "EcommercePlatform::Customer" and the entity ID might be "Daniel".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A set of attributes&lt;/strong&gt;: These are properties or characteristics of the entity. For example, a customer entity might have attributes like 'purchase history' and 'loyalty level'.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A list of parent entities&lt;/strong&gt;: This is used to define the parent entities. In our use case we will add departments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cedar vs AVP Format: A Comparative Look
&lt;/h2&gt;

&lt;p&gt;To better understand the differences between the Cedar and AVP formats, let's take a look at how a Seller entity from our e-commerce example would be represented in each format:&lt;/p&gt;

&lt;h3&gt;
  
  
  Cedar Format:
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Seller"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attrs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"__entity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"luxury"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  AVP Format:
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Seller"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"luxury"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Key Differences:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entity Representation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cedar&lt;/strong&gt;: Uses &lt;code&gt;uid&lt;/code&gt; with type and &lt;code&gt;id&lt;/code&gt; to represent the entity.&lt;br&gt;
&lt;strong&gt;AVP&lt;/strong&gt;: Uses &lt;code&gt;identifier&lt;/code&gt; with &lt;code&gt;entityType&lt;/code&gt; and &lt;code&gt;entityId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attribute Types:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cedar&lt;/strong&gt;: Directly assigns values to attributes.&lt;br&gt;
&lt;strong&gt;AVP&lt;/strong&gt;: Attributes are typed, such as &lt;code&gt;{"long": 5}&lt;/code&gt; for the rating.&lt;br&gt;
&lt;strong&gt;Entity Relationships:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cedar&lt;/strong&gt;: Uses the &lt;code&gt;__entity&lt;/code&gt; key inside attributes to denote relationships.&lt;br&gt;
&lt;strong&gt;AVP&lt;/strong&gt;: Uses the &lt;code&gt;entityIdentifier&lt;/code&gt; key for relationships.&lt;br&gt;
Entity Naming:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cedar&lt;/strong&gt;: Uses concise names like "Seller".&lt;br&gt;
&lt;strong&gt;AVP&lt;/strong&gt;: Uses namespaced names like "EcommercePlatform::Seller".&lt;/p&gt;

&lt;h2&gt;
  
  
  Ecommerce example
&lt;/h2&gt;

&lt;p&gt;Let's take our ongoing example of an e-commerce system where we have Sellers, Customers, Products, and now, Departments. We've used these entities in our previous blog posts as well. This time, let's imagine we're dealing with a car dealership. Our sellers are car dealers, and they have actions like selling cars, giving discounts, and ordering new cars.&lt;/p&gt;

&lt;p&gt;We can define our entities like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Seller entity might have attributes like 'rating',  and 'department'. The 'department' attribute links the Seller to a Department entity, indicating which department the seller belongs to.&lt;/li&gt;
&lt;li&gt;A Department entity represents different departments within the dealership, each responsible for selling certain types of cars.&lt;/li&gt;
&lt;li&gt;A Product (in this case, a Car) entity might have attributes like 'price', and 'department'. The 'department' attribute links the Car to a Department entity, indicating which department is responsible for selling this car.&lt;/li&gt;
&lt;li&gt;A Customer entity might have attributes like and 'loyalty level'.
In this setup, we're going to implement two rules:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hierarchy Rule:&lt;/strong&gt; A seller can sell a car if the seller's &lt;code&gt;department&lt;/code&gt; matches the car's parent &lt;code&gt;department&lt;/code&gt;. This rule represents a hierarchical relationship between sellers, departments, and cars.&lt;br&gt;
&lt;strong&gt;ABAC Rule:&lt;/strong&gt; Moreover a seller can sell if the &lt;code&gt;rating&lt;/code&gt; (based on reputation) value is bigger than the specific value, as well whether the price is above some specific level. Those rules represent an attribute-based access control (ABAC) scenario where access decisions are made based on the attributes of the entities involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;We can either use &lt;a href="https://github.com/Pigius/avp-cli" rel="noopener noreferrer"&gt;AVP-CLI&lt;/a&gt; with scenario, or do it manually within the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  AVP-CLI approach
&lt;/h2&gt;

&lt;p&gt;I've prepared the &lt;a href="https://github.com/Pigius/avp-cli/tree/main/scenarios/ecommerceHierarchyAndAbacScenario" rel="noopener noreferrer"&gt;scenario&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Simply run it locally:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

➜  avp-cli git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; ✗ node index.js
Welcome to AVP CLI!
This tool is designed to &lt;span class="nb"&gt;help &lt;/span&gt;you interact with the AWS Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service. You can use it to create, manage, and delete policy stores, schemas, and policies.
Please ensure that you have &lt;span class="nb"&gt;set &lt;/span&gt;up your AWS credentials correctly to use this tool.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario Ecommerce with Hierarchy and ABAC Scenario


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a couple of seconds all resources will be deployed to AWS, grab the policy store ID from the output table and navigate to the AVP Test Bench to continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual approach
&lt;/h2&gt;

&lt;p&gt;Navigate to the AVP console, and create a new policy store with empty store. Open the Schema and paste it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"EcommercePlatform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Seller"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Long"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entity"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Car"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Long"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entity"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sell"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Car"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Seller"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonno0dy8cu99xhq2kfcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonno0dy8cu99xhq2kfcz.png" alt="Schema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy
&lt;/h2&gt;

&lt;p&gt;Now we can define policy as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

permit &lt;span class="o"&gt;(&lt;/span&gt;
    principal,
    action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;EcommercePlatform::Action::&lt;span class="s2"&gt;"Sell"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
    resource
&lt;span class="o"&gt;)&lt;/span&gt;
when
&lt;span class="o"&gt;{&lt;/span&gt;
    principal.department &lt;span class="o"&gt;==&lt;/span&gt; resource.department &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    principal.department.name &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"luxury"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    principal.rating &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; 8 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    resource.price &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 1000000
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;We can either test it with &lt;a href="https://github.com/Pigius/avp-cli/blob/main/scenarios/ecommerceHierarchyAndAbacScenario/ecommerceHierarchyAndAbacScenario.json#L12" rel="noopener noreferrer"&gt;AVP-CLI Test Scenario&lt;/a&gt;, or we can test it with Test Bench feature in AVP. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switch to json mode and fill it as follows:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Principal&lt;/strong&gt;: &lt;code&gt;EcommercePlatform::Seller&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;ID&lt;/strong&gt;: &lt;code&gt;1&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Resource&lt;/strong&gt;: &lt;code&gt;EcommercePlatform::Car&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;ID&lt;/strong&gt;: &lt;code&gt;porsche&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Action&lt;/strong&gt;: &lt;code&gt;EcommercePlatform::Action&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;ID&lt;/strong&gt;: &lt;code&gt;Sell&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrue0rnmpcsfrrosqls5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyrue0rnmpcsfrrosqls5.png" alt="Test Bench"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leave Context untouched.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Entities use:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Seller"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"entityIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Car"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"porsche"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"entityIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EcommercePlatform::Department"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"entityId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"luxury"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"parents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Above dataset defines entities for an e-commerce platform, specifically detailing sellers, cars, and departments. It outlines a seller with a rating and department affiliation, a luxury car with its price and associated department, and a department named "luxury" to which both the seller and the car are linked.&lt;/p&gt;

&lt;p&gt;Feel free to now test it, the decision should be "allow".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdz8innrymvb2sjoykm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdz8innrymvb2sjoykm7.png" alt="Allow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;That's it for today. In the upcoming &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-x-avp-cli-aih"&gt;article&lt;/a&gt;, I'll dive deeper into the avp-cli, exploring its capabilities and demonstrating how it can improve your AVP workflows. If there are specific topics related to Cedar or AVP you'd like me to cover, please let me know. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>cedar</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part VIII: Integration with Cognito</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Thu, 03 Aug 2023 15:43:44 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb</guid>
      <description>&lt;p&gt;Welcome back to my last blogpost of series on AWS Verified Permissions (AVP)! In the previous blogpost, we discussed the importance of &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vii-audit-and-pricing-2k5"&gt;auditing and pricing&lt;/a&gt; in an enterprise-grade authorization system. Today, we're going to explore how to integrate AVP with AWS Cognito, a powerful identity service that can help you manage user identities and authentication in your applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating AVP with AWS Cognito
&lt;/h2&gt;

&lt;p&gt;In any application, managing user identities and controlling their access to resources is a crucial aspect. Amazon Cognito is a service that helps you manage your users and their authentication. When integrated with AVP, Amazon Cognito can provide the identity context for your authorization policies. This means that you can use information from a user's Cognito identity, such as their user attributes, to make fine-grained access control decisions in AVP.&lt;/p&gt;

&lt;p&gt;However, it's important to note that AVP doesn't currently process the &lt;code&gt;cognito:groups&lt;/code&gt; claim, which means that Cognito integration can be used primarily for ABAC (Attribute-Based Access Control) rather than RBAC (Role-Based Access Control). The team is working on enabling support for group claims, which would allow for RBAC-type policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case: E-commerce Application
&lt;/h2&gt;

&lt;p&gt;Let's consider an e-commerce application where we have Sellers. Each seller has a custom attribute called &lt;code&gt;discountPrivilege&lt;/code&gt; which is a string indicating whether the seller has the privilege to give discounts or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Schema
&lt;/h3&gt;

&lt;p&gt;In AVP, we define the structure of the entities, actions, and context that the policy will use in a schema. For our use case, our schema will include a "Seller" entity type with a "custom:discountPrivilege" attribute, and a "Product" entity type. Our actions will include "Read" and "Discount".&lt;/p&gt;

&lt;p&gt;Here's how our schema looks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"MyEcommerceApp"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"entityTypes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Product"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"shape"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"Record"&lt;/span&gt;,
                    &lt;span class="s2"&gt;"attributes"&lt;/span&gt;: &lt;span class="o"&gt;{}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;,
            &lt;span class="s2"&gt;"Seller"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"shape"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"Record"&lt;/span&gt;,
                    &lt;span class="s2"&gt;"attributes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s2"&gt;"custom"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="s2"&gt;"attributes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                                &lt;span class="s2"&gt;"discountPrivilege"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                                    &lt;span class="s2"&gt;"required"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;,
                                    &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"String"&lt;/span&gt;
                                &lt;span class="o"&gt;}&lt;/span&gt;
                            &lt;span class="o"&gt;}&lt;/span&gt;,
                            &lt;span class="s2"&gt;"required"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;,
                            &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"Record"&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"actions"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Discount"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"appliesTo"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"resourceTypes"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"Product"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;,
                    &lt;span class="s2"&gt;"principalTypes"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"Seller"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;,
                    &lt;span class="s2"&gt;"context"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"SellerContext"&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;,
            &lt;span class="s2"&gt;"Read"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"appliesTo"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"resourceTypes"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"Product"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;,
                    &lt;span class="s2"&gt;"context"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"SellerContext"&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;,
                    &lt;span class="s2"&gt;"principalTypes"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"Seller"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="s2"&gt;"commonTypes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"SellerContext"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"attributes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"token"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="s2"&gt;"attributes"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="s2"&gt;"client_id"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                                &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"String"&lt;/span&gt;
                            &lt;span class="o"&gt;}&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;,
                        &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"Record"&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;,
                &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"Record"&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Setting Up the Identity Source with Cognito
&lt;/h3&gt;

&lt;p&gt;Before we can create our policy, we need to set up an identity source in AVP. The identity source is where AVP gets the identity context for authorization decisions. In our case, we're using Cognito as our identity source.&lt;/p&gt;

&lt;p&gt;Here are the steps to set up a Cognito identity source in AVP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the AVP console, navigate to "Identity sources" and click "Create identity source".&lt;/li&gt;
&lt;li&gt;For "Cognito user pool details" please select AWS Region and Cognito User Pool.&lt;/li&gt;
&lt;li&gt;For "Principal details" for "Principal type" select "MyEcommerceApp::Seller".
For "App client", enter the ID of the app client in your user pool that will be making requests to AVP.
For "Client application validation", select "Only accept tokens with matching client application IDs". This ensures that AVP only accepts tokens that were issued for the specified app client. Provide the "Client Application Id" (It's located in Cognito, we will cover it in the Testing section)
Click "Create identity source".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m1azjko7pp4meor5i3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m1azjko7pp4meor5i3z.png" alt="Identity source"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it should looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjob36hclh7je2tphwkjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjob36hclh7je2tphwkjl.png" alt="Created identity source"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the Policy
&lt;/h3&gt;

&lt;p&gt;Next, we define the rules for access control in a policy. Our policy allows a seller to apply discounts to a product when the seller's "custom:discountPrivilege" attribute is set to "agreed".&lt;/p&gt;

&lt;p&gt;Here's how our policy looks:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

permit &lt;span class="o"&gt;(&lt;/span&gt;
    principal,
    action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;MyEcommerceApp::Action::&lt;span class="s2"&gt;"Discount"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
    resource
&lt;span class="o"&gt;)&lt;/span&gt;
when &lt;span class="o"&gt;{&lt;/span&gt; principal.custom.discountPrivilege &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"agreed"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  How It All Works Together
&lt;/h2&gt;

&lt;p&gt;With our schema, identity source, and policy set up, here's how the authorization process works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; A &lt;code&gt;Seller&lt;/code&gt; logs in through Cognito and receives an ID token. This token includes the seller's user attributes, including the &lt;code&gt;custom:discountPrivilege&lt;/code&gt; attribute.&lt;/li&gt;
&lt;li&gt;The seller makes a request to our application to perform an action, such as applying a discount to a product. The request includes the seller's ID token.&lt;/li&gt;
&lt;li&gt;Our application sends the ID token to AVP along with the requested action and resource. This is done through the &lt;code&gt;IsAuthorizedWithToken&lt;/code&gt; API operation.&lt;/li&gt;
&lt;li&gt;AVP validates the ID token and extracts the identity context, which includes the custom:discountPrivilege attribute.&lt;/li&gt;
&lt;li&gt;AVP evaluates the policy using the identity context, action, and resource. If the policy permits the action (i.e., if the custom:discountPrivilege attribute is set to "agreed"), AVP returns an "ALLOW" decision. Otherwise, it returns a "DENY" decision.&lt;/li&gt;
&lt;li&gt;Our application uses the decision from AVP to either allow or deny the seller's request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process allows us to make fine-grained access control decisions based on user attributes from Cognito. It's a powerful way to implement attribute-based access control (ABAC) in our application.&lt;/p&gt;

&lt;p&gt;In the next section, we'll walk through how to test this setup to ensure everything is working as expected.&lt;/p&gt;


&lt;h2&gt;
  
  
  Testing the Setup
&lt;/h2&gt;

&lt;p&gt;This time we cannot use the Test Bench from AVP, we need to do it differently. We first need to create a Cognito user pool and an app client.&lt;br&gt;
Here's a quick guide on how to do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Cognito User Pool&lt;/strong&gt;: In the AWS Management Console, navigate to the Cognito service and click on "Manage User Pools". Click "Create a user pool", give it a name, and click "Review defaults". On the next page, click "Create pool".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fve44olnhaeuxswm4gfa6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fve44olnhaeuxswm4gfa6.png" alt="User pool creation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Password Policy&lt;/strong&gt;: Make it default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disable MFA&lt;/strong&gt;: In the "MFA and verifications" settings, set "Which second factors do you want to enable?" to "None". This is for simplicity in our testing setup; in a production environment, you would typically want to enable MFA for added security.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add Custom Attribute&lt;/strong&gt;: In the "Attributes" settings, click on "Add custom attribute". Set the attribute name to "discountPrivilege", the attribute type to "String", and check the "Mutable" box. This allows the attribute to be changed after the user is created.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11icxrfe6eygt81qhfp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11icxrfe6eygt81qhfp2.png" alt="custom attribute"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create an App Client&lt;/strong&gt;: In the "App clients" settings, click "Add an app client". Give it a name, uncheck all the "Auth Flows Configuration" options except for &lt;code&gt;ALLOW_ADMIN_USER_PASSWORD_AUTH&lt;/code&gt; and &lt;code&gt;ALLOW_USER_PASSWORD_AUTH&lt;/code&gt;, and click "Create app client".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy41gvwd097zx7fi6xn86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy41gvwd097zx7fi6xn86.png" alt="App client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our Cognito setup, we can create a user and assign them the &lt;code&gt;discountPrivilege&lt;/code&gt; attribute. Here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the Cognito user pool, navigate to "Users and groups" and click "Create user". Fill in the required fields, set "Email verified" to "True", and in the "Custom attributes" section, set &lt;code&gt;discountPrivilege&lt;/code&gt; to "agreed".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Note down the "App client id" from the "App client settings" in your user pool. We'll need this for testing (user pool as well).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Testing flow with AWS CLI
&lt;/h2&gt;

&lt;p&gt;With our Cognito setup ready, we can now test our AVP integration. Here's how:&lt;/p&gt;

&lt;p&gt;Before we can test our setup, we need to authenticate our user and obtain an ID token (&lt;strong&gt;Not the access token, as there will be not custom claims included&lt;/strong&gt;). When a user is created in Cognito, they are required to change their password after their first sign-in. This process involves initiating an authentication flow, responding to the new password challenge, and then authenticating again with the new password to get the ID token.&lt;/p&gt;

&lt;p&gt;The command to do it is like follow:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws cognito-idp admin-respond-to-auth-challenge &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--user-pool-id&lt;/span&gt; user-pool-id &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--client-id&lt;/span&gt; client-id &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--challenge-name&lt;/span&gt; NEW_PASSWORD_REQUIRED &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--challenge-responses&lt;/span&gt; &lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;username,NEW_PASSWORD&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'YourNewPassword'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--session&lt;/span&gt; &lt;span class="s2"&gt;"YourSessionString"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's how to do this with the AWS CLI:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initiate the Authentication Flow&lt;/strong&gt;: Use the &lt;code&gt;admin-initiate-auth&lt;/code&gt; command to initiate the authentication flow. This command requires the user pool ID, the app client ID, and the user's username and password.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws cognito-idp admin-initiate-auth &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--user-pool-id&lt;/span&gt; &amp;lt;user_pool_id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--client-id&lt;/span&gt; &amp;lt;client_id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--auth-flow&lt;/span&gt; ADMIN_USER_PASSWORD_AUTH &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--auth-parameters&lt;/span&gt; &lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;username&amp;gt;,PASSWORD&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;password&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deal with &lt;code&gt;New Password Challenge&lt;/code&gt;, and auth again. Then we should obtain the ID token, we will use it to test our AVP policy.&lt;/p&gt;

&lt;p&gt;If you decode it with jwt.io it should looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="s2"&gt;"email_verified"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;,
  &lt;span class="s2"&gt;"iss"&lt;/span&gt;: &lt;span class="s2"&gt;"https://cognito-idp.eu-west-1.amazonaws.com/eu-west-user-pool"&lt;/span&gt;,
  &lt;span class="s2"&gt;"cognito:username"&lt;/span&gt;: &lt;span class="s2"&gt;"92d514d4-0071-70fa-2ab7-201b7f22167a"&lt;/span&gt;,
  &lt;span class="s2"&gt;"custom:discountPrivilege"&lt;/span&gt;: &lt;span class="s2"&gt;"agreed"&lt;/span&gt;,
  &lt;span class="s2"&gt;"origin_jti"&lt;/span&gt;: &lt;span class="s2"&gt;"e166c8de-3798-49be-9e39-0ddfe3055cda"&lt;/span&gt;,
  &lt;span class="s2"&gt;"aud"&lt;/span&gt;: &lt;span class="s2"&gt;"4bagaej4rb8m1t028lv5vsio8o"&lt;/span&gt;,
  &lt;span class="s2"&gt;"event_id"&lt;/span&gt;: &lt;span class="s2"&gt;"519e9b73-2231-4afc-b881-f748b9d6000e"&lt;/span&gt;,
  &lt;span class="s2"&gt;"token_use"&lt;/span&gt;: &lt;span class="s2"&gt;"id"&lt;/span&gt;,
  &lt;span class="s2"&gt;"auth_time"&lt;/span&gt;: 1691072849,
  &lt;span class="s2"&gt;"exp"&lt;/span&gt;: 1691076449,
  &lt;span class="s2"&gt;"iat"&lt;/span&gt;: 1691072849,
  &lt;span class="s2"&gt;"jti"&lt;/span&gt;: &lt;span class="s2"&gt;"f33a5626-5f5d-45ce-8848-61a115bbdce7"&lt;/span&gt;,
  &lt;span class="s2"&gt;"email"&lt;/span&gt;: &lt;span class="s2"&gt;"example.com"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Testing the AVP Policy
&lt;/h2&gt;

&lt;p&gt;Now that we have our ID token, we can use the &lt;code&gt;is-authorized-with-token&lt;/code&gt; command to test our AVP policy (make sure you have updated AWS CLI). This command requires the policy store ID, the ID token, the action, the resource, and the context.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws verifiedpermissions is-authorized-with-token &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--policy-store-id&lt;/span&gt; &amp;lt;policy_store_id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--identity-token&lt;/span&gt; &amp;lt;id_token&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--action&lt;/span&gt; &lt;span class="nv"&gt;actionType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"MyEcommerceApp::Action"&lt;/span&gt;,actionId&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Discount"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource&lt;/span&gt; &lt;span class="nv"&gt;entityType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"MyEcommerceApp::Resource"&lt;/span&gt;,entityId&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--context&lt;/span&gt; &lt;span class="s1"&gt;'{"contextMap": {"custom.discountPrivilege": {"string": "agreed"}}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;region&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command will return a decision ("ALLOW" or "DENY") and the policies that determined the decision.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"decision"&lt;/span&gt;: &lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;,
    &lt;span class="s2"&gt;"determiningPolicies"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"policyId"&lt;/span&gt;: &lt;span class="s2"&gt;"XBN1W6aDjwYdDC1HQyVGXX"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;,
    &lt;span class="s2"&gt;"errors"&lt;/span&gt;: &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that's it! You've successfully integrated AVP with AWS Cognito and tested your setup using the AWS CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using avp-cli for the Scenario
&lt;/h2&gt;

&lt;p&gt;The scenario we've discussed in this post is included in the &lt;a href="https://www.npmjs.com/package/avp-cli" rel="noopener noreferrer"&gt;avp-cli&lt;/a&gt; tool. This command-line interface tool simplifies the process of creating and managing schemas, policies, and policy stores in AVP. However, to use the tool for this scenario, you need to have your Cognito setup ready as per the instructions provided in this post.&lt;/p&gt;

&lt;p&gt;In the library there is also support for &lt;code&gt;isAuthorizedWithToken&lt;/code&gt; so we can easily make an authorization request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In the next &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-ix-hierarchies-and-abac-8gm"&gt;blogpost&lt;/a&gt; we will focus on hierarchies. I'm also working on enhancing the &lt;a href="https://github.com/Pigius/avp-cli" rel="noopener noreferrer"&gt;avp-cli&lt;/a&gt; to add more functionalities to it, so stay tuned for updates!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>cognito</category>
      <category>authorization</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions - A New Way to Manage Permissions Part VII: Audit and Pricing</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Wed, 26 Jul 2023 18:45:43 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vii-audit-and-pricing-2k5</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vii-audit-and-pricing-2k5</guid>
      <description>&lt;p&gt;Welcome back to my series on AWS Verified Permissions (AVP)! In the previous blogpost, we delved into the concept of &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vi-policy-templates-3h4p"&gt;Policy Templates&lt;/a&gt; and how they can simplify policy management in your applications. Today, we're going to discuss two important aspects of any enterprise-grade authorization system: auditing and pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auditing with AVP
&lt;/h2&gt;

&lt;p&gt;In any enterprise-grade system, auditing is a crucial component. It allows you to track and record every action taken within your system, providing a clear and transparent record of who did what and when. This is not only important for security and compliance purposes, but also for troubleshooting and understanding user behavior.&lt;/p&gt;

&lt;p&gt;With AVP, you can leverage AWS CloudTrail to audit your authorization system. AWS CloudTrail is a service that enables governance, compliance, operational auditing, and risk auditing of your AWS account. It provides event history of your AWS account activity, including actions taken through the AWS Management Console, AWS SDKs, command line tools, and other AWS services.&lt;/p&gt;

&lt;p&gt;When integrated with AVP, CloudTrail can record all API calls made by or on behalf of AVP in your AWS account. This includes calls made by the AVP console and code calls to the AVP APIs. By using CloudTrail, you can log, continuously monitor, and retain information about these API calls for a period of time defined by your organization's requirements.&lt;/p&gt;

&lt;p&gt;Let's see how we can set up auditing for our AVP usage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, we need to ensure that AWS CloudTrail is enabled in our AWS account. You can do this by navigating to the CloudTrail console and following the prompts to create a new trail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once CloudTrail is enabled, it will automatically record all API calls made by AVP. These logs are stored in an Amazon S3 bucket specified during the setup of CloudTrail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To view the logs, navigate to the CloudTrail Dashboard (it displays an overview of your trails and recent events). Navigate to &lt;strong&gt;Event history&lt;/strong&gt; to see the most recent events in AWS account.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fks78rjaifba7zyswgtzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fks78rjaifba7zyswgtzb.png" alt="Dashboard" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open one of these events to view the details of the API calls. You'll see information such as the identity of the caller, the time of the call, the source IP address of the call, the request parameters, and the response elements returned by the AVP service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnrv13zcgx9inkrukowq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnrv13zcgx9inkrukowq.png" alt="Event" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can also use CloudTrail to set up alarms and notifications (CloudWatch) for specific API activities. This can be useful for monitoring specific actions or detecting unusual activity in your AVP usage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Feel free to generate some activity in AVP and see how it appears in our CloudTrail logs. You can use AVP CLI tool to create a policy store, add a schema, and create a policy. After running these commands, you can check our CloudTrail logs to see the recorded API calls.&lt;/p&gt;

&lt;p&gt;By auditing your AVP usage with CloudTrail, you can maintain a comprehensive record of all authorization activity in your application. This can help you meet compliance requirements, detect security incidents, and gain insights into user behavior.&lt;/p&gt;

&lt;p&gt;Feel free to read more about AVP with CloudTrail &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/userguide/cloudtrail.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing of AVP
&lt;/h2&gt;

&lt;p&gt;Understanding the cost of using a service like AVP is crucial for planning and budgeting your application's infrastructure. AVP pricing is based on the number of authorization requests and policy management actions your application performs each month. Let's break down these costs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization Requests:&lt;/strong&gt; These are calls to the &lt;code&gt;isAuthorized&lt;/code&gt; API operation. The cost depends on the number of requests, with the first 40 million requests per month costing $150 per million requests, the next 60 million requests costing $75 per million requests, and any additional requests costing $40 per million requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy Management Actions:&lt;/strong&gt; These are calls to API operations that manage policies, such as &lt;code&gt;CreatePolicy&lt;/code&gt;, &lt;code&gt;UpdatePolicy&lt;/code&gt;, &lt;code&gt;DeletePolicy&lt;/code&gt;, &lt;code&gt;GetPolicy&lt;/code&gt;, &lt;code&gt;ListPolicies&lt;/code&gt;, &lt;code&gt;CreatePolicyTemplate&lt;/code&gt;, &lt;code&gt;UpdatePolicyTemplate&lt;/code&gt;, &lt;code&gt;DeletePolicyTemplate&lt;/code&gt;, &lt;code&gt;GetPolicyTemplate&lt;/code&gt;, and &lt;code&gt;ListPolicyTemplates&lt;/code&gt;. These actions cost $40 per million requests, regardless of the number of requests.&lt;/p&gt;

&lt;p&gt;Now, let's consider two examples to understand how these costs might add up in real-world scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Small Application&lt;/strong&gt;&lt;br&gt;
Suppose you have a small application with 10,000 active users, each of whom makes 3 authorization requests per day. This adds up to 30,000 authorization requests per day, or 900,000 requests per month. In addition, let's say you perform 10,000 policy management actions per month. Your charges would be calculated as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authorization Requests: 900,000 requests * $150 / 1,000,000 = $135&lt;/li&gt;
&lt;li&gt;Policy Management Actions: 10,000 requests * $40 / 1,000,000 = $0.4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total Charges: $135.4/month&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: Large Application&lt;/strong&gt;&lt;br&gt;
Now, let's consider a larger application with 1 million active users, each of whom makes 2 authorization requests per day. This adds up to 2 million authorization requests per day, or 60 million requests per month. In addition, let's say you perform 1 million policy management actions per month. Your charges would be calculated as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First 40 million Authorization Requests: 40 million requests * $150 / 1,000,000 = $6,000&lt;/li&gt;
&lt;li&gt;Next 20 million Authorization Requests: 20 million requests * $75 / 1,000,000 = $1,500&lt;/li&gt;
&lt;li&gt;Policy Management Actions: 1 million requests * $40 / 1,000,000 = $40&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total Charges: $7,540/month&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing discussion
&lt;/h2&gt;

&lt;p&gt;The cost of using AVP can vary significantly depending on the scale of your application and the number of authorization requests and policy management actions you perform. It's important to consider these costs when planning your application's architecture and budget.&lt;/p&gt;

&lt;p&gt;However, it's also crucial to consider the alternative: building your own authorization system from scratch. This approach can be time-consuming and challenging, especially if your team is not familiar with Rust, the language in which Cedar is written. The development costs can also be high, as you'll need to invest significant resources into creating, testing, and maintaining your own system.&lt;/p&gt;

&lt;p&gt;Moreover, if you choose not to use AVP, you'll miss out on several key features. AVP provides a policy store, a test bench, configuration with identity sources, and auditing with AWS CloudTrail. If you build your own system using the Cedar engine, you'll only have the authorization decision functionality, and you'll need to implement these other features yourself.&lt;/p&gt;

&lt;p&gt;In contrast, using a managed service like AVP can save you a lot of time and effort. AVP is ready to use right out of the box, and it's designed to scale with your application as it grows. Plus, because AVP uses Cedar as its policy language, you have the flexibility to switch to a self-hosted Cedar system in the future if AVP becomes too costly.&lt;/p&gt;

&lt;p&gt;There's been a lot of discussion within the community about the pricing of AVP. Some developers are concerned about the potential costs of using a managed service, especially for larger applications. However, it's important to remember that building and maintaining your own authorization system also has costs, both in terms of time and money.&lt;/p&gt;

&lt;p&gt;When you're considering whether to use AVP, think about the resources you have available and the needs of your application. If you have a small team or a tight budget, using AVP could be a more cost-effective option than building your own system. If you have a larger team and more resources, you might prefer the flexibility and control of a self-hosted system.&lt;/p&gt;

&lt;p&gt;In the end, the best choice depends on your specific circumstances. But no matter which option you choose, using a policy language like Cedar can help you implement fine-grained, attribute-based access control in a secure and efficient way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;In the next blogpost, we'll continue exploring advanced features of AVP. We'll delve into another critical aspect of application security: identity management. We'll &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-viii-integration-with-cognito-pgb"&gt;explore&lt;/a&gt; how to integrate AVP with AWS Cognito.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>authorization</category>
      <category>awscommunitybuilder</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions: A New Way to Manage Permissions - Part VI - Policy Templates</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Thu, 20 Jul 2023 20:48:43 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vi-policy-templates-2dpb</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vi-policy-templates-2dpb</guid>
      <description>&lt;p&gt;Welcome back to my series on AWS Verified Permissions (AVP)! If you've been following along, you'll know that we've covered a lot of ground so far. We've explored the basics of AVP, looked at how to use the &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-v-test-bench-4emp"&gt;Test Bench&lt;/a&gt; feature, and much more. In this sixth blogpost, we're going to dive into a powerful feature of AVP: &lt;a href="https://docs.aws.amazon.com/verifiedpermissions/latest/userguide/policy-templates.html"&gt;Policy Templates&lt;/a&gt;. I'll explain what they are, why they're useful, and how to use them in the context of our ongoing ecommerce example. As always, we'll provide step-by-step instructions for both the AWS console and our handy &lt;a href="https://www.npmjs.com/package/avp-cli"&gt;AVP CLI tool&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Templates
&lt;/h2&gt;

&lt;p&gt;Policy Templates in AVP are reusable policy definitions that can be linked to multiple principals and resources. They are a way to define a policy once and then apply it to many different entities. This concept is from &lt;a href="https://docs.cedarpolicy.com/templates.html"&gt;Cedar&lt;/a&gt;, a policy management system that also uses templates to simplify policy creation and management.&lt;/p&gt;

&lt;p&gt;In the context of AVP, a Policy Template is a blueprint for a policy that can be applied to different principals and resources (but not for actions). It's a way to define the permissions once and then apply them to multiple entities, ensuring consistency and reducing the complexity of your policy management.&lt;/p&gt;

&lt;p&gt;For example, in our ecommerce system, we might have a policy that allows sellers to list products. Instead of creating a separate policy for each seller, we can create a single policy template and link it to each seller. This not only reduces the number of policies we need to manage, but also ensures consistency across all sellers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Policy Templates?
&lt;/h2&gt;

&lt;p&gt;Policy Templates offer several benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;: Instead of creating individual policies for each entity, you can create one policy template and link it to multiple entities. This can save time and reduce the complexity of your policy management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: By using a policy template, you ensure that all entities linked to the template have the same permissions. This can help prevent errors and inconsistencies that might arise from manually creating individual policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: Policy templates can be linked to different types of entities (e.g., users, roles, groups) and resources, providing a flexible way to manage permissions across your system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Granular Control&lt;/strong&gt;: Policy templates provide a more granular level of control compared to using groups or allowing all access. They allow you to specify exactly what actions a principal can perform on a resource, reducing the risk of over-permissioning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Policies vs Template-Linked Policies vs Policy Templates
&lt;/h2&gt;

&lt;p&gt;Before we dive into how to use policy templates, let's clarify the difference between static policies, template-linked policies, and policy templates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static Policies:&lt;/strong&gt; These are standalone policies that define permissions for a specific principal and resource. They are not linked to a template and can't be reused for other principals or resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Template-Linked Policies:&lt;/strong&gt; These are policies that are linked to a policy template. They inherit the permissions defined in the template and apply them to a specific principal and resource.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy Templates:&lt;/strong&gt; These are reusable policy definitions that can be linked to multiple principals and resources through template-linked policies. They define a set of permissions that can be applied consistently across multiple entities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Templates in action
&lt;/h2&gt;

&lt;p&gt;Let's walk through the process of creating and using a policy template for our ecommerce scenario.&lt;/p&gt;

&lt;p&gt;Two approaches:&lt;/p&gt;

&lt;h2&gt;
  
  
  Manually in AWS Console
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open the AWS Management Console, find the AVP service, and create a new policy store. Select Empty policy store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkg88pwmpdl9nyldqs04s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkg88pwmpdl9nyldqs04s.png" alt="Empty Policy Store" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to Schema and add below json:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"EcommercePlatform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Seller"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"List"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Seller"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Remove"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Seller"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Seller"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79lu0cofzgvkz4tbnwtb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79lu0cofzgvkz4tbnwtb.png" alt="Schema" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Navigate to the "Policy Templates" section. Click on "Create Policy Template". You'll be asked to provide a name and a policy definition. The policy definition should be a JSON object that describes the permissions granted by the policy. For our ecommerce example, we might create a policy template that allows a seller to list a product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For description use "Policy template that allows a seller to list a product", and for "Policy template body" use:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;permit &lt;span class="o"&gt;(&lt;/span&gt;
    principal &lt;span class="o"&gt;==&lt;/span&gt; ?principal,
    action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
        EcommercePlatform::Action::&lt;span class="s2"&gt;"List"&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;,
    resource &lt;span class="o"&gt;==&lt;/span&gt; ?resource
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdh7d9euxrqxow5bd83bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdh7d9euxrqxow5bd83bg.png" alt="Policy template" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the policy template is created, you can link it to principals and resources. Navigate to the "Polices" section  and click on "Create Template-Linked Policy". &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejlutbhe4iyq80wfsguj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejlutbhe4iyq80wfsguj.png" alt="Template" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select already existing policy template, and click next.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfppueyk1xd0c2mlivx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfppueyk1xd0c2mlivx4.png" alt="Select policy template" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now you need to provide values that are injected into the template to create the policy (principal - seller and resource - product), and create a policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnug9t0pikufuk4w196il.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnug9t0pikufuk4w196il.png" alt="values" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;After creating the template-linked policy, you can review it in the "Template-Linked Policies" section. You'll see the policy template, the principal, and the resource, along with any other template-linked policies you've created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;At the end we can test it in Test Bench section.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feardcdvmyi9n3q8m226s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feardcdvmyi9n3q8m226s.png" alt="Test Bench" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Via AVP-CLI
&lt;/h2&gt;

&lt;p&gt;We can also avoid doing it manually within the AWS console, and use &lt;a href="https://www.npmjs.com/package/avp-cli"&gt;avp-cli&lt;/a&gt; for deploying it via CLI.&lt;/p&gt;

&lt;p&gt;For the purpose of this blogpost I've created scenario &lt;a href="https://github.com/Pigius/avp-cli/tree/main/scenarios/ecommercePolicyTemplateScenario"&gt;Ecommerce policy template scenario&lt;/a&gt; which is the exact usecase.&lt;/p&gt;

&lt;p&gt;Simply download it, and run "Ecommerce with Template-Linked Policies Scenario" from the avaliable scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  avp-cli git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; node index.js
Welcome to AVP CLI!
This tool is designed to &lt;span class="nb"&gt;help &lt;/span&gt;you interact with the AWS Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service. You can use it to create, manage, and delete policy stores, schemas, and policies.
Please ensure that you have &lt;span class="nb"&gt;set &lt;/span&gt;up your AWS credentials correctly to use this tool.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario 
  Documents Scenario 
  Ecommerce with Context Scenario 
  Ecommerce with Group Scenario 
❯ Ecommerce with Template-Linked Policies Scenario 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After it will be successfully finished, open the AVP in AWS console to play around with that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;That's all for today. I encourage you to play around it more. In addition, I encourage you to try the &lt;a href="https://catalog.workshops.aws/verified-permissions-in-action/en-US"&gt;official AVP workshop from AWS&lt;/a&gt; where there are also policy templates.&lt;/p&gt;

&lt;p&gt;As for the next blogpost, I will &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vii-audit-and-pricing-2k5"&gt;describe&lt;/a&gt; the topics of audit and pricing of the service.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>cedar</category>
      <category>authorization</category>
    </item>
    <item>
      <title>Authorization and Amazon Verified Permissions: A New Way to Manage Permissions - Part V - Test Bench</title>
      <dc:creator>Daniel Aniszkiewicz</dc:creator>
      <pubDate>Tue, 11 Jul 2023 09:13:05 +0000</pubDate>
      <link>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-v-test-bench-4emp</link>
      <guid>https://forem.com/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-v-test-bench-4emp</guid>
      <description>&lt;p&gt;In the previous &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-iv-schema-3hlg"&gt;article&lt;/a&gt; of this series, we've been exploring Amazon Verified Permissions (AVP) and Cedar, its underlying policy language. We've learned how to define fine-grained, attribute-based access control policies, and how to structure our authorization system using AVP schemas. We've also delved into more advanced topics such as including context in our schemas and defining groups of entities.&lt;/p&gt;

&lt;p&gt;Now, it's time to put our policies to the test. In this article, we'll introduce the AVP Test Bench, a powerful tool for testing our policies. I'll explain what it is, how it works, and how to use it effectively to ensure our policies behave as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Test Bench?
&lt;/h2&gt;

&lt;p&gt;The Test Bench is a feature of AVP that allows you to test your policies before deploying them. It provides a controlled environment where you can simulate principal requests and see whether they would be allowed or denied based on your policies. This can help prevent potential security issues and save you from headaches down the line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhvs7wpgaf1zn04p7bsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhvs7wpgaf1zn04p7bsp.png" alt="headache" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use the Test Bench
&lt;/h2&gt;

&lt;p&gt;Using the Test Bench is straightforward. Here's a step-by-step guide:&lt;/p&gt;

&lt;p&gt;Navigate to the Test Bench: From the AVP console, select your policy store and click on the "Test Bench" tab.&lt;/p&gt;

&lt;p&gt;Set up your test: You'll need to specify a principal, an action, and a resource for the test. You can also include a context if your policies use one.&lt;/p&gt;

&lt;p&gt;Run the test: Click on the "Run Test" button. AVP will evaluate your policies and show whether the request would be allowed or denied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Policies with Context
&lt;/h2&gt;

&lt;p&gt;Let's take a look at how we can use the Test Bench to test policies with context. In our ecommerce scenario, we have a policy that allows customers to view products only when the context region is set to "US".&lt;/p&gt;

&lt;p&gt;In order for you to test this yourself, you need to have defined policy store, schema, and policies. To do it, you can do it in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;a href="https://www.npmjs.com/package/avp-cli"&gt;avp-cli&lt;/a&gt; It's a CLI for making life easier with AVP. Moreover there are prepared scenarios, and we can reuse them for the purpose of this article.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inside the GH is a manual. In a nutshell, download the repository, install dependencies, make sure you have AWS credentials added, then use in terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
Welcome to AVP CLI!
This tool is designed to &lt;span class="nb"&gt;help &lt;/span&gt;you interact with the AWS Verified Permissions &lt;span class="o"&gt;(&lt;/span&gt;AVP&lt;span class="o"&gt;)&lt;/span&gt; service. You can use it to create, manage, and delete policy stores, schemas, and policies.
Please ensure that you have &lt;span class="nb"&gt;set &lt;/span&gt;up your AWS credentials correctly to use this tool.
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario Ecommerce with Context Scenario
Starting creating scenario: Ecommerce with Context usage Scenario
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate for you a policy store, schema ecommerce, and a policy from context).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;manually add to the AWS console (in the AVP service), inside the policy store add schema and policy) and then go to test bench.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;First, either use an existing one or create a new policy store.&lt;/li&gt;
&lt;li&gt;Add schema:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"EcommercePlatform"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entityTypes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;

               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;

               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"View"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Edit"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;permit&lt;span class="o"&gt;(&lt;/span&gt;
  principal,
  action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;EcommercePlatform::Action::&lt;span class="s2"&gt;"View"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
  resource
&lt;span class="o"&gt;)&lt;/span&gt; when &lt;span class="o"&gt;{&lt;/span&gt;
  context.region &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"US"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can test it. Navigate to the AWS Console, open our policy store, and open "Test bench" in the left side panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzy8wd3n5hqsdilvk5o4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzy8wd3n5hqsdilvk5o4.png" alt="Test bench" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test this policy, we would set up a test with a principal of "Customer", an action of "View", and a resource of "Product". We would also include a context with a region of "US". Running this test should result in the request being allowed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuip78d2lktmwwndx6ef8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuip78d2lktmwwndx6ef8.png" alt="Filled form" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foldvka34tj9b7ge74ciy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foldvka34tj9b7ge74ciy.png" alt="Successful authorization decision" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we can change the context region to something other than "US" for instance "EU", and run the test again. This time, the request should be denied, demonstrating that our policy is working as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6yed7qi6cmun2vnqroj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6yed7qi6cmun2vnqroj.png" alt="Failed authorization decision" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Policies with Groups
&lt;/h2&gt;

&lt;p&gt;In AVP, you can also create policies that apply to groups of principals. For example, we might have a policy that allows customers who belong to the VIP group to preorder products.&lt;/p&gt;

&lt;p&gt;Again, two approaches to setup it in AVP.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With AVP CLI. This time select &lt;code&gt;Ecommerce with Group Usage Scenario&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  avp-cli git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;personal node index.js
Welcome to AVP CLI!
...
? What would you like to &lt;span class="k"&gt;do&lt;/span&gt;? Use prepared scenarios
? Choose a scenario Ecommerce with Group Scenario
Starting creating scenario: Ecommerce with Group Usage Scenario
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;manually add to the AWS console (in the AVP service), inside the policy store add schema and policy) and then go to test bench.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;First, create a new policy store.&lt;/li&gt;
&lt;li&gt;Add schema:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"EcommercePlatform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"entityTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"CustomerGroup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Record"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"memberOfTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="s2"&gt;"CustomerGroup"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Create"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Preorder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"CustomerGroup"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Delete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"View"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"appliesTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"principalTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"resourceTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;permit &lt;span class="o"&gt;(&lt;/span&gt;
    principal &lt;span class="k"&gt;in &lt;/span&gt;EcommercePlatform::CustomerGroup::&lt;span class="s2"&gt;"VIP"&lt;/span&gt;,
    action &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;EcommercePlatform::Action::&lt;span class="s2"&gt;"Preorder"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
    resource
&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can test it. Navigate to the AWS Console, open our policy store, and open "Test bench" in the left side panel.&lt;/p&gt;

&lt;p&gt;To test this policy, we would set up a test with a principal that is a member of the specified group ("VIP"), an action of "Preorder", and a resource of "Product". Running this test should result in the request being allowed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxqlya92ysy3bfwdy96v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxqlya92ysy3bfwdy96v.png" alt="success" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Importance of Deny Policies
&lt;/h2&gt;

&lt;p&gt;One important thing to note about AVP is that deny policies take precedence over allow policies. This means that if you have a policy that allows a certain action and another policy that denies the same action, the action will be denied.&lt;/p&gt;

&lt;p&gt;This can be useful for creating exceptions to general rules. For example, you might have a policy that allows all customers to view products, but a deny policy that prevents a specific customer from viewing products. Even though the allow policy would normally grant the customer access, the deny policy takes precedence and the customer's request is denied.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;In this article, we've explored the AVP Test Bench and how it can be used to test our policies. We've seen how to set up tests for policies with context and groups, and we've learned about the precedence of deny policies.&lt;/p&gt;

&lt;p&gt;As you continue to work with AVP, remember that testing your policies is a crucial step in ensuring that your authorization system behaves as expected. The Test Bench provides a powerful tool for doing this, and I encourage you to make full use of it.&lt;/p&gt;

&lt;p&gt;If you want to experiment with AVP and Cedar, consider using the &lt;a href="https://www.npmjs.com/package/avp-cli"&gt;avp-cli&lt;/a&gt; tool. It provides a convenient way to create, manage, and delete policy stores, schemas, and policies, and it includes prepared scenarios that you can use as a starting point for your own policies.&lt;/p&gt;

&lt;p&gt;In the next &lt;a href="https://dev.to/aws-builders/authorization-and-amazon-verified-permissions-a-new-way-to-manage-permissions-part-vi-policy-templates-2dpb"&gt;article&lt;/a&gt; of this series, we'll dive into policy templates in AVP. These templates allow you to define reusable policy patterns, making it easier to manage complex authorization systems. Stay tuned!&lt;/p&gt;

&lt;p&gt;Remember, the best way to learn is by doing. Don't be afraid to experiment with different policies and scenarios, and see what you can build with AVP and Cedar!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>avp</category>
      <category>cedar</category>
      <category>authorization</category>
    </item>
  </channel>
</rss>
