Aftercall is a wave of deceptive Android apps on Google Play that pose as everyday tools while bombarding users with pop-up ads after every phone call.
When an unexpected ad pops up every time you hang up a call, it will slowly drive you crazy, especially if you can’t figure out what’s causing it. The ads appear outside the app’s normal context, making it difficult for users to identify and remove the culprit.
Researchers investigating the campaign discovered a collection of these apps that masquerade as alarm clocks, calendars, and other seemingly harmless apps. After installation, they ask for permission to “appear on top” of other apps. That means they can show a full-screen ad every time you end a call, then hide themselves, making them difficult for users to find and uninstall.
Because the ads appear after you end a call, the researchers dubbed the campaign “Aftercall.”
How the Aftercall scheme works
Think of these apps as fake helpers that piggyback on your phone calls purely to generate ad impressions.
The apps disguise themselves as alarm clocks, calendars, note-taking apps, cleaners, or “super fast” messaging apps and are distributed through the Google Play Store. Researchers found dozens of new apps released every month, collectively responsible for hundreds of millions of ad impressions.
They trick users into granting overlay permissions. Because Android doesn’t allow this permission to be granted through a standard pop-up, the app has to direct users into Settings, where they must enable it manually. To persuade them, the apps invent plausible reasons. One researcher explained:
“In one example, the alarm app explains that it needs to go off even when the phone is locked – without granting permission, alarms might not appear correctly. Another app, a calendar, doesn’t even leave users a choice – it simply closes, unless they grant the permission.”
Some of these apps also request full-screen notification permissions, allowing them to show ads even when the device is locked.
Aftercall apps monitor the phone’s call state. When it changes from “ringing” to “idle,” indicating that a call has ended, they immediately launch an activity using their overlay permission to pop a screen over everything else and show an ad.
To make the ads seem more legitimate, they wrap them in a fake “call info” screen, complete with caller details, a fake profile picture, and text suggesting the ad relates to the app’s functionality. For the user, this feels like some new post-call feature rather than an unrelated app showing adverts.
They hide to avoid detection and removal. Aftercall apps remove themselves from the “Recent apps” list so when users try the usual “swipe away the suspicious app” approach, they don’t see anything obvious.
How to stay safe
Besides being incredibly annoying for users, the Aftercall campaign also wastes advertisers’ money. After all, would you buy something pushed in this way?
If you see ads pop up right after you end a call, especially alongside fake “call info,” check which apps have the “appear on top” or overlay permissions.
The exact steps vary depending on your phone manufacturer and Android version, but you can usually find them by looking at Settings > Apps > More options (3 vertical dots) > Special access > Appear on top.
Look for apps you don’t recognize, rarely use, or that shouldn’t need overlay access, such as a simple notes app, clock, or cleaner. Disable their “Allow to appear on top” or “Display over other apps” permission. If you’re confident you’ve identified the culprit, uninstall it.
Use an up-to-date, real-time anti-malware app for your device to detect and remove malicious apps.
When installing apps, think carefully before granting permissions. Does the app really need the access it’s asking for to perform its function?
Finally, make sure Google Play Protect is enabled so it can regularly scan apps for known malicious behavior.
Open the Google Play Store app on your phone.
Tap your profile icon in the top-right corner.
Tap Play Protect.
Look at the main screen or tap the Settings gear icon to see if Scan apps with Play Protect is turned on.
Scammers know more about you than you think.
Malwarebytes Mobile Security protects you from phishing, scam texts, malicious sites, and more. With real-time AI-powered Scam Guard built right in.
Aftercall is a wave of deceptive Android apps on Google Play that pose as everyday tools while bombarding users with pop-up ads after every phone call.
When an unexpected ad pops up every time you hang up a call, it will slowly drive you crazy, especially if you can’t figure out what’s causing it. The ads appear outside the app’s normal context, making it difficult for users to identify and remove the culprit.
Researchers investigating the campaign discovered a collection of these apps that masquerade as alarm clocks, calendars, and other seemingly harmless apps. After installation, they ask for permission to “appear on top” of other apps. That means they can show a full-screen ad every time you end a call, then hide themselves, making them difficult for users to find and uninstall.
Because the ads appear after you end a call, the researchers dubbed the campaign “Aftercall.”
How the Aftercall scheme works
Think of these apps as fake helpers that piggyback on your phone calls purely to generate ad impressions.
The apps disguise themselves as alarm clocks, calendars, note-taking apps, cleaners, or “super fast” messaging apps and are distributed through the Google Play Store. Researchers found dozens of new apps released every month, collectively responsible for hundreds of millions of ad impressions.
They trick users into granting overlay permissions. Because Android doesn’t allow this permission to be granted through a standard pop-up, the app has to direct users into Settings, where they must enable it manually. To persuade them, the apps invent plausible reasons. One researcher explained:
“In one example, the alarm app explains that it needs to go off even when the phone is locked – without granting permission, alarms might not appear correctly. Another app, a calendar, doesn’t even leave users a choice – it simply closes, unless they grant the permission.”
Some of these apps also request full-screen notification permissions, allowing them to show ads even when the device is locked.
Aftercall apps monitor the phone’s call state. When it changes from “ringing” to “idle,” indicating that a call has ended, they immediately launch an activity using their overlay permission to pop a screen over everything else and show an ad.
To make the ads seem more legitimate, they wrap them in a fake “call info” screen, complete with caller details, a fake profile picture, and text suggesting the ad relates to the app’s functionality. For the user, this feels like some new post-call feature rather than an unrelated app showing adverts.
They hide to avoid detection and removal. Aftercall apps remove themselves from the “Recent apps” list so when users try the usual “swipe away the suspicious app” approach, they don’t see anything obvious.
How to stay safe
Besides being incredibly annoying for users, the Aftercall campaign also wastes advertisers’ money. After all, would you buy something pushed in this way?
If you see ads pop up right after you end a call, especially alongside fake “call info,” check which apps have the “appear on top” or overlay permissions.
The exact steps vary depending on your phone manufacturer and Android version, but you can usually find them by looking at Settings > Apps > More options (3 vertical dots) > Special access > Appear on top.
Look for apps you don’t recognize, rarely use, or that shouldn’t need overlay access, such as a simple notes app, clock, or cleaner. Disable their “Allow to appear on top” or “Display over other apps” permission. If you’re confident you’ve identified the culprit, uninstall it.
Use an up-to-date, real-time anti-malware app for your device to detect and remove malicious apps.
When installing apps, think carefully before granting permissions. Does the app really need the access it’s asking for to perform its function?
Finally, make sure Google Play Protect is enabled so it can regularly scan apps for known malicious behavior.
Open the Google Play Store app on your phone.
Tap your profile icon in the top-right corner.
Tap Play Protect.
Look at the main screen or tap the Settings gear icon to see if Scan apps with Play Protect is turned on.
Scammers know more about you than you think.
Malwarebytes Mobile Security protects you from phishing, scam texts, malicious sites, and more. With real-time AI-powered Scam Guard built right in.
If you’re building multi-agent AI systems, you need to prevent authorization scope from silently expanding as agents delegate tasks through multi-hop chains. Without proper controls, an agent can potentially act beyond what the originating user authorized, even when role-based access control (RBAC) policies are in place. The OWASP Top 10 for Agentic Applications classifies this risk as ASI03: Identity & Privilege Abuse.
This post shows you how to address the potential risk using a three-layer policy model built with Cedar, an open source authorization policy language, deployed on Amazon Web Services (AWS). The reference implementation uses OAuth 2.0 for authentication and Cedar for authorization. A trusted identity provider authenticates the originating user, then Cedar policies enforce authorization across three layers using verified token claims.
Reference implementation overview
To enforce authorization at each hop in a multi-agent delegation chain, the reference implementation uses two AWS Lambda functions in sequence. A Model Context Protocol (MCP) adapter Lambda function normalizes inbound requests and cryptographically signs the originating user context. This prevents downstream tampering. A Cedar evaluator Lambda function evaluates three independent policy layers sequentially, halting on the first deny.
Table 1: Three-layer Cedar policy evaluation model
Layer
What it checks
Principal to resource
L1 – Agent-to-tool
Whether the invoking agent has a sufficient trust score (1–5), belongs to the correct namespace (for example, payments), and is in the production lifecycle stage
Agent to tool
L2 – Agent-to-agent delegation
Whether the delegation hop count is within the hard limit of five, and whether requested tasks are a subset of the target agent’s registered capabilities
Agent to agent
L3 – Originating user authorization
Whether the human who initiated the chain has the required role (for example, admin), has completed MFA, and is within the allowed delegation depth
Agent to tool (user in context)
Architecture
Cedar evaluates authorization but doesn’t establish identity. Before Cedar can evaluate context.originating_user.role or context.originating_user.mfa_verified, a trusted authentication layer must establish the user’s identity and produce verifiable claims. Steps 1–3 handle authentication; steps 4–10 handle authorization. The architecture shown in Figure 1 is described in the following lists:
Authentication (steps 1–3)
The originating user authenticates with an OIDC-compliant identity provider (in this reference implementation, Amazon Cognito with TOTP multi-factor authentication (MFA)). The identity provider (IdP) issues a signed JSON Web Token (JWT) containing claims such as sub, role, amr (authentication methods), and session_id.
Amazon Cognito returns the signed JWT to the user.
The user passes the JWT and task request to the AI agent (MCP client). The agent carries the originating user context in the MCP _meta envelope.
Authorization pipeline (steps 4–10)
The AI agent sends a Model Context Protocol (MCP) request to AWS WAF, which filters using CommonRuleSet, SQLiRuleSet, rate limiting, and body size constraints.
Amazon API Gateway (with Amazon Cognito authorizer) verifies the JWT signature against the user pool’s public keys and rejects invalid or expired tokens. Valid requests are forwarded to the MCP protocol adapter Lambda function, which applies Amazon Bedrock Guardrails content filtering.
The adapter extracts verified claims from the token and maps them to Cedar context attributes:
JWT role claim : context.originating_user.role
JWT amr includes MFA method: context.originating_user.mfa_verified = true
JWT sub: context.originating_user.user_id
JWT sid: context.originating_user.session_id
JWT amr claim: context.originating_user.authentication_method
The adapter then computes an HMAC-SHA256 signature over the user context (user_id, role, mfa_verified, authentication_method, and session_id in canonical order) using a key from AWS Secrets Manager.
The adapter constructs a signed request envelope and invokes the Cedar evaluator Lambda function.
The evaluator verifies the HMAC-SHA256 signature, retrieves L2 and L3 Cedar policies from Amazon Verified Permissions, and evaluates all three layers (L1, L2, and L3), halting on the first deny.
Two mechanisms work together to protect identity across hops:
Hash-based Message Authentication Code (HMAC-SHA256) ensures integrity and authenticity. Every downstream evaluator verifies this signature before trusting the context.
OAuth 2.0 Token Exchange (RFC 8693) sets delegation scope using the on-behalf-of (OBO) pattern. When the orchestrator delegates to a downstream agent (data-bot), it exchanges the original token for a scoped OBO token that records who’s acting on behalf of whom and with what authority. The Cedar policies (detailed in Step 2: Three-layer policies) then check whether that scoped delegation is permitted and verify the originating user claims carried in the OBO token. Token exchange limits each downstream agent to only the delegated task’s scope instead of passing through the full original token. For enterprise deployments, use token exchange alongside HMAC. OAuth tracks who is acting on behalf of whom and with what scope. HMAC verifies that the context hasn’t been tampered with and came from a trusted source.
Prerequisites
The following prerequisites are needed to deploy the reference implementation. Before you begin, clone the repository:
git clone https://github.com/aws-samples/sample-cedar-agentic-ai-authorization.git
cd sample-cedar-agentic-ai-authorization
In this walkthrough, you define the Cedar entity schema and policies, deploy the infrastructure with AWS CDK, and integrate your identity provider.
To define the Cedar entity schema
In this step, you define a schema with two entity types (Agent and Tool) and two actions (invoke_tool and delegate_task) in the AgentAuthz namespace. Notice that there is no User entity. Instead, you carry the originating user’s identity in the evaluation context record, which is a structured data object passed alongside each authorization request.
This schema is deployed to an Amazon Verified Permissions policy store by the VerifiedPermissionsStack CDK stack. In the reference implementation, the schema file is located at cedar-entity-schema.json.
Agent topology and attributes
The following tables show the agents and tools registered in this reference implementation, along with the attributes the Cedar evaluator function retrieves from the entity store. The test scenarios that follow trace requests through this topology.
Table 2: Agent attributes
Entity
Type
trust_level
namespace
lifecycle_stage
registered_capabilities
orchestrator
Agent
5
orchestration
production
delegate_task
route_request
finance-agent
Agent
3
payments
production
process_payment
refund
data-bot
Agent
4
data
production
query_records
delete_records
Table 3: Tool attributes
Tool
namespace
risk_level
process_payment
payments
medium
delete_records
data
high
query_records
data
low
The orchestrator can delegate to both data-bot and finance-agent. Each agent can only invoke tools within its registered capabilities. The test scenarios below trace requests through these delegation paths.
To create three-layer Cedar policies
The following policies are deployed to the same Verified Permissions policy store. In the reference implementation, policy files are located under cedar/policies/ organized by layer: layer1-agent-to-tool/, layer2-agent-to-agent/, and layer3-originating-user-auth/.
Layer 1 (agent-to-tool): This policy permits the finance-agent to invoke the process_payment tool only when three conditions are met: the agent’s trust score is at least 3, it belongs to the payments namespace, and it’s deployed in the production lifecycle stage. If any condition fails, the request is denied. The agent’s trust_level, namespace, and lifecycle_stage aren’t self-reported in a production deployment. Instead, the evaluator retrieves these attributes from the Verified Permissions entity store using the agent_id as a lookup key.
Important: The reference implementation accepts these values from the request payload for simplicity. Production deployments must validate agent attributes against an authoritative source to prevent a compromised agent from escalating its own trust.
The trust_level attribute uses a 1–5 integer scale that represents an agent’s verified maturity: 1 for newly registered and untested agents, 3 for agents that have passed integration testing and security review, and 5 for agents with a proven production track record. Organizations assign trust levels through their agent promotion pipeline, not through self-declaration. The lifecycle_stage attribute (development, staging, production) prevents pre-production agents from invoking production tools, even if they have the correct namespace and trust score.
Layer 2 (agent-to-agent delegation) enforces depth limits and capability constraints. The orchestrator agent delegates tasks to data-bot only when the delegation chain is three hops or fewer and the requested capabilities are a subset of data-bot’s registered capabilities. A separate forbid policy (L2-004) enforces a hard system-wide limit of five hops regardless of which agents are involved.
// L2-002: Orchestrator can delegate to data agent
permit(
principal == AgentAuthz::Agent::"orchestrator",
action == AgentAuthz::Action::"delegate_task",
resource == AgentAuthz::Agent::"data-bot"
) when {
context.delegation_depth <= 3 &&
context.target_capabilities.containsAll(context.requested_capabilities)
};
Layer 3 (originating user authorization) keeps the agent as the principal, but the policy evaluates context.originating_user to validate the human who initiated the request. data-bot invokes the delete_records tool only when the originating user has the admin role, has verified MFA, and the delegation chain is at most two hops deep. Without this layer, an agent with the right capabilities could invoke destructive tools regardless of who initiated the request.
Key design point: The principal remains the agent, not a user entity. The user’s role and MFA status are checked through context attributes, keeping the schema to two entity types and two actions.
Integrate your IdP
The reference implementation uses Amazon Cognito with TOTP MFA, but most OIDC-compliant providers (Okta, Microsoft Entra ID, Auth0, or AWS IAM Identity Center) work with this pattern. The authentication-to-signing flow is described in the preceding Authentication before authorization section. To use a different IdP, replace the Cognito authorizer on API Gateway with a Lambda or JWT authorizer for your IdP’s issuer URL. Cedar policies remain unchanged.
Deploy the infrastructure with AWS CDK
The reference implementation deploys five CloudFormation stacks: KmsStack, VerifiedPermissionsStack, LambdaStack, SecurityLakeStack, and MonitoringStack. The following commands deploy the stacks in dependency order:
The end-to-end tests cover the three scenarios described in the following sections. Each test sends a request through the deployed API and validates the per-layer authorization decisions.
Scenario A: Layer 3 enforcement
A support-role user (no MFA) requests record deletion through orchestrator and data-bot.
Layer
Decision
Reason
L1: Agent-to-tool
PERMIT
data-bot has trust level 4, namespace data, and lifecycle production
L2: Agent-to-agent
PERMIT
orchestrator is authorized to delegate to data-bot, depth within limits
L3: Originating user
DENY
User role is support, not admin; MFA not verified
Overall
DENY
Denying layer: L3
Without Layer 3, this request would have been permitted based on agent capabilities alone, demonstrating why originating user authorization is essential.
Scenario B: Authorized admin request
An admin user with MFA requests the same operation through the same chain.
Layer
Decision
Reason
L1
PERMIT
Agent attributes match
L2
PERMIT
Delegation path authorized
L3
PERMIT
Role is admin, MFA verified, depth is less than or equal to 2
Overall
PERMIT
All three layers permit
Scenario C: Delegation depth limit
An admin with MFA requests the same operation, but the delegation chain has six hops. This scenario tests the Layer 2 depth constraint independently of user authorization.
Layer
Decision
Reason
L1
PERMIT
Agent attributes match
L2
DENY
Depth of six exceeds the hard limit of five
Overall
DENY
Denying layer: L2 (L3 not evaluated – halt)
Even an authorized admin can’t bypass the delegation depth constraint.
Alignment with the security principles for agentic AI
Property-based testing (Hypothesis) for adversarial input fuzzing, Cedar policy formal verification with strict schema validation, end-to-end scenarios testing policy bypass and privilege escalation paths, and infrastructure-as-code (IaC) with AWS CDK.
Traditional security controls remain applicable
AWS WAF, Amazon VPC isolation, AWS Key Management Service (AWS KMS) encryption, Amazon Cognito MFA, and Secrets Manager; NIST SP 800-53 control mapping.
Deterministic external controls (security box)
Three-layer Cedar evaluation runs outside the agent’s reasoning loop in a separate Lambda function. HMAC-signed context prevents tampering. Verified Permissions (the managed Cedar evaluation service) enforces L2 and L3 at the infrastructure level.
Greater autonomy earned through evaluation
trust_level and lifecycle_stage policy attributes calibrate agent capabilities; OCSF 99001 audit events and Amazon CloudWatch dashboards provide the evidence base for expanding autonomy.
Monitoring and audit compliance
Each evaluation produces an OCSF 99001 audit event with request ID, user identity, delegation chain, per-layer decisions, and latency.
The following table maps this implementation to NIST SP 800-53 Rev. 5 controls. Customers are responsible for evaluating whether it meets their compliance requirements.
NIST control
Control name
How the reference implementation addresses it
AC-4
Information Flow Enforcement
User context flows immutably through HMAC-signed envelopes
AC-6
Least Privilege
Three-layer evaluation requires both agent capability and user role
AC-6(1)
Authorize Access to Security Functions
MFA required for high-risk tools in Layer 3
AC-6(5)
Privileged Accounts
Destructive operations restricted to admin with MFA verified
AU-2
Event Logging
Each evaluation is logged as OCSF 99001
AU-3
Content of Audit Records
Events include identity, chain, action, resource, decisions, and latency
SI-10
Information Input Validation
HMAC verified before evaluation; Amazon Bedrock Guardrails on inbound
IA-2(1)
Multi-factor Authentication
Layer 3 enforces MFA for high-risk operations
SC-12
Cryptographic Key Management
Signing key in Secrets Manager with rotation
SC-28
Protection of Information at Rest
Policies in Verified Permissions with STRICT validation
Scaling to multi-account environments
Deploy the Cedar policy store in a central security account and use cross-account IAM roles for workload accounts to call verifiedpermissions:IsAuthorized. Use AWS Organizations service control policies (SCPs) to prevent workload accounts from creating their own policy stores. For standardizing user identity attributes across the organization, consider IAM Identity Center or a centralized OIDC provider that issues consistent claims to your workload accounts. This helps ensure that the context.originating_user attributes are uniform across accounts and agents.
Multi-agent AI systems need authorization boundaries at every delegation hop. The three-layer Cedar policy model with OAuth 2.0 authentication provides that protection while maintaining least-privilege access. Combining a trusted IdP (AuthN) with Cedar policy evaluation (AuthZ) creates an authorization boundary around each tool invocation, verifying agent capability (L1), delegation path (L2), and originating user authority (L3). The pattern works with an OIDC-compliant IdP and a compute platform that can call Amazon Verified Permissions. Clone the reference implementation and adapt the Cedar policies to your organization’s requirements. For more information, see the Cedar policy language documentation and the Amazon Verified Permissions User Guide.
Modern web applications require robust security controls to protect user data and application resources. Authentication and authorization are two fundamental pillars of application security that answer critical questions: Who are you? and What are you allowed to do? Implementing these controls correctly can be challenging for developers, especially when building data-intensive applications with frameworks like Streamlit (an open-source Python framework for building interactive web applications) or when requiring fine-grained access control. Key challenges include protecting access to application resources, implementing application identity with multi-factor authentication (MFA), and implementing usage-based controls.
In this post, you will learn how to build fine-grained access controls for a sample Streamlit application using Amazon Cognito for authentication and Amazon Verified Permissions with Cedar policies for authorization. This architecture provides enterprise-grade security with minimal development effort, so you can focus on your application’s core functionality. You will learn how to reduce development time for secure applications, implement enterprise-grade authentication, through proper access management, and scale security with growing user bases.
Security architecture overview
The reference architecture follows a layered security design with four key components; separating identity verification, authorization evaluation, application logic, and enforcement boundaries. By assigning clear responsibilities to each layer, the architecture limits blast radius and ensures that a failure in any single control does not compromise the overall system.
Authentication layer: Amazon Cognito handles user authentication with secure credential validation and JSON web tokens (JWTs). It provides built-in password policies, account lockout protection, and session management.
Authorization layer: Verified Permissions uses the Cedar policy engine to evaluate fine-grained access requests based on centrally stored policies.
Application layer: The Streamlit frontend integrates with both services, managing user sessions and enforcing access controls in the user interface.
Security boundaries: Multiple layers of security controls protect against unauthorized access, privilege escalation, authentication verification, authorization checks, and input validation.
This separation of concerns enables authentication and authorization to function as complementary security controls, following defense-in-depth principles. Figure 1 illustrates the end-to-end authentication and authorization workflow, showing how a user’s sign-in request flows through Amazon Cognito for identity verification, then through Verified Permissions for Cedar policy-based access decisions, before the application enforces the result.
Figure 1: Solution architecture and workflow
The following workflow demonstrates how the three architecture layers work together: the authentication layer (steps 1–3) handles identity verification using Amazon Cognito, the authorization layer (steps 4–6) evaluates Cedar policies using Verified Permissions, and the application layer (steps 7–8) enforces the decision in Streamlit.
The user sends a sign-in request, which is submitted through Streamlit
The request is authenticated by Amazon Cognito
An access token is sent back to Streamlit
An authorization request is sent to Verified Permissions
The Cedar policy engine evaluates the request
A decision is sent back by the policy engine
The instruction to allow or deny is sent back to Streamlit
If the instruction is to allow, access is provided
Understanding authorization with Cedar
While authentication establishes user identity, authorization determines what actions users can perform. Verified Permissions provides a scalable authorization service based on Cedar, a policy language specifically designed for fine-grained access control.
Cedar policies follow a structured format that defines who can perform which actions on what resources. Let’s examine the anatomy of a Cedar policy:
permit(
principal == ?principal,
action == application::Action::"ViewGrade",
resource == ?resource
) when {
principal has role == "Student" &&
resource.student == principal.entityId
};
Policy components
Effect: permitor forbid determines whether the policy allows or denies access
Principal: The entity (user) making the request, represented by ?principal as a variable
Action: The operation being performed, scoped to your application namespace
Resource: The target of the action, also represented as a variable
Conditions: The when clause contains logical expressions that must evaluate to true
Advanced Cedar policy patterns
This section describes commonly used Cedar policy patterns for implementing fine-grained authorization with Amazon Verified Permissions. The examples illustrate how to model ownership, role-based access, hierarchical permissions, and administrative controls in real-world applications
Resource ownership control
This pattern helps ensure that users can only access resources they own:
permit(
principal == ?principal,
action == application::Action::"ViewGrade",
resource == ?resource
) when {
principal has role == "Student" &&
resource.student == principal.entityId
};
What it does – This policy allows students to view only their own grades by:
Checking that the user has the Student role
Verifying that the grade resource’s student attribute matches the student’s entityId
Preventing students from accessing other students’ grades while allowing access to their own academic performance
Role-based access with resource type
This pattern grants access based on role and resource type:
permit(
principal == ?principal,
action == application::Action::"EditCourse",
resource == ?resource
) when {
principal has role == "Faculty" &&
resource has resourceType == "Course" &&
resource.instructor == principal.entityId
};
What it does – This policy allows faculty members to edit courses they teach by:
Verifying the user has the Faculty role
Confirming the resource is of type Course
Verifying that the course’s instructor attribute matches the faculty member’s entityId
Restricting faculty to modify only their own courses, not courses taught by other instructors
Hierarchical authorization
This pattern allows department heads to manage faculty in their department:
permit(
principal == ?principal,
action == application::Action::"ManageFaculty",
resource == ?resource
) when {
principal has role == "DepartmentHead" &&
resource has role == "Faculty" &&
resource.department == principal.department
};
What it does – This policy implements departmental hierarchy controls by:
Requiring the user to be a DepartmentHead
Verifying the resource is a faculty member
Matching the faculty member’s department with the department head’s department
Preventing department heads from managing faculty in other departments
Administrative override
This pattern provides emergency access with proper justification:
permit(
principal == ?principal,
action == ?action,
resource == ?resource
) when {
principal has role == "Administrator" &&
context has emergencyAccess == true &&
context has justification
};
What it does – This policy provides emergency access capabilities by:
Allowing administrators to perform any action on any resource
Requiring an emergency access flag to be set to true
Requiring a justification for emergency access
Supporting accountability through required documentation while enabling emergency operations
Cedar policy evaluation flow
Understanding how policies are evaluated helps design effective authorization systems. Figure 2 shows a common evaluation pattern for an academic scenario
Note: A policy match evaluates to the policy’s effect (permit or forbid). Forbid policies take precedence: if any forbid policy matches, access is denied regardless of permit policies.
Figure 2: Policy evaluation process
The policy evaluation process follows these steps:
User attempts to access a protected resource
Application sends an authorization request to Verified Permissions
Verified Permissions retrieves applicable Cedar policies from the policy store
The Cedar policy engine evaluates each policy against the request
If any forbid policy matches, access is denied immediately
If any permit policy matches and no forbid policies match, access is allowed
If no policies match, access is denied by default
The evaluation result (ALLOW or DENY) is returned to the application
Application enforces the authorization decision
Cedar policy language
Cedar is an Amazon open source policy language designed for fine-grained authorization. Every policy defines who (principal) can perform what action on which resource under what conditions, as shown in Figure 3.
Figure 3: Cedar policy definitions
Policy interaction
The following table shows how different policies interact in complex scenarios where multiple policies could apply:
Scenario
Student policy
Faculty policy
Department head policy
Admin policy
Student accessing own grade
Permit
N/A
N/A
Override
Faculty editing course
N/A
Permit
N/A
Override
Department head managing faculty
N/A
N/A
Permit
Override
Emergency admin access
N/A
N/A
N/A
Permit
Legend:
Permit – Policy allows access
N/A – Policy doesn’t apply
Override – Emergency admin access
The preceding table shows how each role’s policy applies to different scenarios, with admin access having override capabilities across most situations except for emergency admin access where it’s the primary permit authority. The Override column specifically indicates that the administrator’s emergency access policy can supersede other role-specific policies, but only when the emergencyAccess context flag is explicitly set and a justification is provided. This is not an automatic override.
Policy optimization tips:
Order conditions by likelihood of success – Place the most frequently true conditions first in your when clause to enable short-circuit evaluation. For example, check role before resource ownership, because role mismatches are caught earlier. See Cedar best practices.
Use indexed attributes for faster lookups – Use entity attributes that Verified Permissions indexes natively (entityId, role, resource type) as primary conditions. Best practices for designing an authorization model
Cache policy evaluations when appropriate
Monitor evaluation metrics and performance
Real-world application: Academic system
Consider an academic system with different user roles and their corresponding permissions:
Student: View own grades
Policy helps ensure students can only access grade resources where they are listed as the student
The policy verifies the student’s role and matches the resource owner to the principal’s entity ID
Faculty: Edit course content, manage grades
Policy allows faculty to edit courses they teach
Faculty can view and modify grades for students in their courses
Teaching assistant (TA): Grade management and course support
Policy permits TAs to manage grades for courses they assist with
Access is limited to specific courses assigned to the TA
Department head: Manage faculty assignments
Policy allows department heads to manage faculty in their department
Access is scoped to the department hierarchy
Administrator: System-wide access
Policy provides emergency access with proper justification
Administrative actions are logged and audited
Prerequisites
To implement the preceding Academic system application, you need an active AWS account, Python 3.8 or later, basic Streamlit knowledge, and AWS Identity and Access Management (IAM) permissions for Amazon Cognito and Verified Permissions.
./deploy-demo-environment.sh
Do you want to start the demo now? (Y/N): Y
This provisions an Amazon Cognito user pool, a Verified Permissions policy store, and any sample resources needed for the demo.
Verify the login screen:
Figure 4: Verify login credentials
Demo walkthrough and shut down: Interact with the demo and test the policies and features. When you’re ready to exit, press Ctrl+C to shut down and stop.
Define your Cedar policies: Start with basic policies and gradually add complexity as you understand the evaluation model.
Implement authentication: Integrate Amazon Cognito authentication into your application with proper error handling.
Add authorization checks: Implement authorization checks at critical access points in your application. For authentication, implement proper error handling for expired tokens, failed MFA challenges, and account lockouts. Use the Amazon Cognito built-in token refresh flow. For authorization, place Verified Permissions checks at every API endpoint and UI component that accesses protected resources.
Test thoroughly: Create test scenarios for each user role and permission combination.
When implementing this architecture, follow these best practices to support security:
Layer your security controls: Use both authentication and authorization as complementary controls rather than relying on a single mechanism.
Follow least privilege principles: Grant only the permissions needed for specific user roles. Start with minimal permissions and add more as needed.
Implement proper session management: Set appropriate token expiration and refresh policies. Amazon Cognito handles much of this automatically, but you should configure timeouts based on your security requirements.
Validate all inputs: Sanitize user inputs to prevent injection attacks. Don’t rely on client-side validation alone.
Monitor authentication events: Set up logging and alerts for suspicious activities such as repeated failed login attempts or unusual access patterns.
Conduct regular security reviews: Periodically audit your policies and security configurations to verify they still meet your requirements and follow current best practices.
Implement secure error handling: Avoid information disclosure through error messages. Provide helpful feedback to users without revealing system details that could aid attackers.
Conclusion
Implementing proper authentication and authorization is critical for application security. By using Amazon Cognito and Amazon Verified Permissions, you can build robust security controls without complex custom code. Through this approach, you can implement enterprise-grade authentication with minimal effort, define and enforce fine-grained authorization policies, scale your security controls as your application grows, and centrally manage and audit security policies.
To get started with your implementation, create your AWS resources including an Amazon Cognito user pool and Verified Permissions policy store. Define your Cedar policies based on your application’s access requirements. Integrate authentication and authorization checks into your application flow. Test thoroughly with different user roles and access scenarios. Finally, monitor and refine your security controls based on usage patterns.
As breach costs go up and attackers focus on common web features like dashboards, admin panels, customer portals, and APIs, weak access control quickly leads to lost data, broken trust, and costly incidents. The worst part is that many failures are not rare technical flaws but simple mistakes, such as missing permission checks, roles with too much power, or predictable IDs in URLs.
This post aims to help you control who can access different parts of your website and explain why it matters.
David Fletcher // Weak NTFS permissions can allow a number of different attacks within a target environment. This can include: Access to sensitive information Modification of system binaries and configuration […]