Controlling access to app resources
Learn how apps control access to their resources with policies.
When developers implement service apps, they must choose how the app's routes can be accessed. There are two kinds of policies: role-based and resource-based. The following table summarizes how each policy type works.
| Role-based | Resource-based | |
| Who can make the request? | Only other IO apps (acting on their own or on behalf of other apps). |
|
| Supported API types |
| REST |
| How other apps access the resource | They must declare the required policies in their manifest.json file and use VTEX clients to make API requests. | No policy declaration is required. They only need to use VTEX clients. |
| How users and integrations (API keys) access the resource | Not applicable. | By calling the route and including an authentication token in the header. |
Policies control access only for the owner of the authentication token. In scenarios where an IO app makes an API call to another app and uses an authentication token in the VtexIdclientAutCookie header, the policy will only have an allowing or denying effect for the token owner, regardless of whether they are a third-party app, a user, or an API key. Policies won't affect access control for the app making the API call in these scenarios.
Defining role-based policies
Role-based policies are associated with a role in the platform. Each policy specifies which resources (routes) and actions (HTTP methods) are allowed or denied. Apps must declare role-based policies to securely expose their resources when the requesters aren't specified. Role-based policies control access to the resource only for other apps.
If you are developing an app that requires access to resources with these policies, you must declare the policies in the manifest.json file for the desired resources and access them using a client. For more information, see Accessing external resources within a VTEX IO app.
Recommendations for using role-based policies:
- The requesters are only apps that make requests independently or on behalf of other apps. Don't use role-based policies when requesters are users, integrations, or other apps making requests on behalf of users.
- Required for exposing GraphQL endpoints and optional for REST endpoints.
- Compared to resource-based policies, apps that want to access exposed resources must declare the necessary permissions in the
manifest.jsonfile.
To define access control for users and integrations, use resource-based policies for REST APIs and the
@authdirective for GraphQL APIs.
To declare a role-based policy for an app, create a policies.json file in the app's root folder. The basic structure of this file is as follows:
Note that, in this example, a policy named resolve-graphql was declared, allowing an app to resolve a GraphQL request.
Besides a name and a description, this policy includes the statements property.
Statements are used to indicate whether to "allow/deny these actions to be performed on these resources under these conditions".
Therefore, considering the given example, the declared resolve-graphql policy allows POST and GET requests on the vrn:vtex.store-graphql:{{region}}:{{account}}:{{workspace}}:/_v/graphql resource.
The keys that compose a statement are:
-
effect: Describes the effect of allowing (allow) or denying (deny) a resource to be accessed. -
actions: Describes the actions (HTTP methods) related to a given effect and resource.Depending on the resource, different actions can be performed on it. For RESTful APIs, this could map to HTTP verbs. However, actions aren't restricted to them, and the service may accept any string as an action.
-
resources: lists the resources expressed by a VTEX Resource Name (VRN) to which the statement refers.
Defining resource-based policies
Resource-based policies are applied to routes defined in the service.json file. Routes can be public or private. Public routes are always accessible to everyone and don't require an authentication token. Private routes require authentication, and their policies define which actions (HTTP methods) are permitted by whom. If a private route has no policies, no one is allowed to perform any action on this route.
Apps must declare resource-based policies to securely expose their private resources (routes) for specific requesters (users, integrations, or other apps). Apps accessing the exposed resources don't need to declare policies in the manifest.json file.
Recommendations for using resource-based policies:
- Required when the requesters are users, integrations, or other apps making requests on behalf of users. Optional for other apps that make requests by themselves or on behalf of other apps.
- Optional for exposing REST endpoints. Incompatible with GraphQL endpoints.
- Compared to role-based policies, apps exposing resources can control which other apps can access private routes through resource-based policies.
To create a resource-based policy, the resource itself must list who it trusts. Therefore, since the resource's routes are declared in a service.json file, a resource-based policy must be declared in this file as a routes property.
The service.json file must have something similar to the following:
Note that, in this example, a resource-based policy related to the /orders route was declared. The effect, actions, and principals properties under policies can be interpreted as: "allow/deny these actions to be performed by these principals on this route", where principals are the applications able to make requests on a given resource.
Hence, for the given example, a policy related to the /orders resource allows the example.marketplace app to perform a POST request on its route.
The keys that compose this kind of policy are:
effect: Describes the effect of allowing (allow) or denying (deny) a principal to perform a set of actions on a route.actions: Describes the actions related to a given effect, principal, and route.principals: Lists the principals allowed or denied to perform requests to a given route. Like resources,principalsare also expressed by a VTEX Resource Name (VRN).
Policies denying access have priority over those allowing access. If actions and principals intersect across different policies for a route, this subset of principals will be denied access for these actions.
Principal types
The following table summarizes the resource-based policy usage for each type of principal.
| Principal type | service (VRN element) | path (VRN element) |
|---|---|---|
| Other apps | apps | app/{vendor}.{app-name}@{app-version} |
| Users | vtex.vtex-id | user/{email} |
| Integrations (API keys) | vtex.vtex-id | user/vtexappkey-{account}-{hash} |
The following sections show how VRNs are used for each type of principal, with examples.
Other apps
By default, other apps aren't allowed to access private resources exposed through resource-based policies unless they are included in the principals list of a policy allowing it ("effect": "allow").
To include other apps in the principals list, use the following VRN syntax:
- Set the
serviceelement of the VRN toapps. - The
pathelement uses the formatapp/{vendor}.{app-name}@{app-version}. The*wildcard can be used. For instance: app/*covers all appsapp/{vendor}.*covers all apps of a specific vendorapp/{vendor}.{app-name}@*covers all versions of a specific appapp/{vendor}.{app-name}@{major}.*covers all versions of a specific app's major version
The example below illustrates two policies with intersecting principals that use wildcards. The first policy allows all apps to use the POST method on a route. The second policy denies access to the same route and method, but for all versions of two specific apps.
Users and integrations
By default, users and integrations (API keys) aren't allowed to access private resources exposed through resource-based policies unless they are included in the principals list of a policy allowing it ("effect": "allow").
To include users and integrations in a principal, use the following VRN syntax:
- Set the
serviceelement of the VRN asvtex.vtex-id. - The
pathelement uses the formatuser/{username}.{username}can be the user email or theappkeyof the integration in the formatvtexappkey-{account}-{hash}. You can use the*wildcard. For example: user/*covers all users and appkeysuser/*@*covers all usersuser/*@gmail.comcovers all users with the email domaingmail.comuser/vtexappkey-*covers all appkeysuser/vtexappkey-{account}-*covers all appkeys of a specific account