-
Notifications
You must be signed in to change notification settings - Fork 135
feat: Public Actor Permissions #2053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e735867
8035620
bac8219
baaed7d
8881e0e
1f052a3
740e220
4bd040b
66d6606
9e3884e
4c27a81
8a6bd79
ea0e652
c7d849e
f8027bf
5b8c483
f0e0ded
1e10169
3a0c308
993ae5d
7f5f9c9
922ce11
8c02113
abbcddc
9bd30ca
400fd21
56ec09f
b8784ac
b6d6eb8
1f40484
7413720
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| --- | ||
| title: Permissions | ||
| description: Learn how to declare and manage permissions for your Actor, what access levels mean, and how to build secure, trusted Actors for Apify users. | ||
| sidebar_position: 7.5 | ||
| slug: /actors/development/permissions | ||
| --- | ||
|
|
||
| **Learn how to declare and manage permissions for your Actor, what permission levels mean, and how to build secure, trusted Actors for Apify users.** | ||
|
|
||
| --- | ||
|
|
||
| Every time a user runs your Actor, it runs under their Apify account. **Actor Permissions** is an Actor level setting that defines the level of access your Actor needs to be able to run. This gives users transparency and control over what data your Actor can access, building trust in your tools. | ||
raethlo marked this conversation as resolved.
Show resolved
Hide resolved
raethlo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| There are two levels of access your Actors can request: | ||
|
|
||
| - **Limited permissions (default):** Actors with this permission level have restricted access, primarily to their own storages and the data they generate. They cannot access other user data on the Apify platform. | ||
| - **Full permissions:** This level grants an Actor access to all of a user's Apify account data. | ||
|
|
||
| Most Actors should use limited permissions to request only the specific access they need and reserve full permissions for exceptional cases where the Actor cannot function otherwise. | ||
|
|
||
| ## How Actor permissions work | ||
|
|
||
| When a user runs an Actor, it receives an Apify API token. This token is injected to the Actor's runtime and has a scope of access as requested by the Actor's permission level. | ||
|
|
||
| Actors with **full permissions** receive a token that grants complete access to the user's Apify account via the Apify API. | ||
|
|
||
| Actors with **limited permissions** receive [a restricted scoped token](../../../integrations/programming/api.md#api-tokens-with-limited-permissions). This token only allows the Actor to perform a specific set of actions, which covers the vast majority of common use cases. | ||
|
|
||
| A limited-permission Actor can: | ||
|
|
||
| - Read and write to its default storages. | ||
| - Update the current run’s status, abort the run, or [metamorph](../programming_interface/metamorph.md) to another Actor (as long as it also has limited permissions). | ||
| - Read basic user information (whether the user is paying, their proxy password or public profile) from the environment. | ||
| - Read and/or write to storages provided via Actor input (sample scenario: the user provides the Actor with a dataset that the Actor should write into). | ||
| - Run any other Actor with limited permissions. | ||
| - Create any additional storage, and write to that storage. | ||
| - Read and write to storages created in previous runs. | ||
|
|
||
| This approach ensures your Actor has everything it needs to function while protecting user data from unnecessary exposure. | ||
|
|
||
| :::info | ||
|
|
||
| To learn how to migrate your Actors to run under limited permissions, see the [Migration guide](./migration_guide.md) | ||
|
|
||
| ::: | ||
|
|
||
| ### Configuring Actor permissions level | ||
raethlo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| You can set the permission level for your Actor in the Apify Console under its **Settings** tab. All the existing Actors are configured to use full permissions, but the plan is to make limited permissions the default for all new Actors. | ||
|
|
||
|  | ||
|
|
||
| ### End-user experience | ||
raethlo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Currently, users will see a visible permission badge on your Actor's detail page indicating whether it requires "Limited permissions" or "Full permissions". At this stage, the experience of running an Actor will not change for the user. | ||
|
|
||
|  | ||
|
|
||
|  | ||
|
|
||
| :::warning | ||
|
|
||
| Whenever possible, design your Actors to use limited permissions and request only access they truly need. Actors requiring full permissions may receive a lower [Actor Quality score](../../publishing/quality_score.mdx), which can reduce their ranking in the store. | ||
|
|
||
| ::: | ||
|
|
||
|
|
||
| ### Accessing user provided storages | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (opt): This section feels strange for me. In the article we're talking about how Actor permissions work and than in this section we switch to just limited permissions, also we kind of repeat ourselves a bit, because there's a very similar information in the migration, maybe this section should be in migration? But on the other hand this section would make sense for me, if we'll also speak about how it currently works for full permissions:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, I've added a bit about full permissions here b6d6eb8 |
||
|
|
||
| By default, limited-permissions Actors can't access user storages. However, they can access storages that users explicitly provide via the Actor input. To do so, use the input schema to add a storage picker and declare exactly which operations your Actor needs. | ||
|
|
||
| - Add a field with `editor: "resourcePicker"`. | ||
| - Set `resourceType` to one of `dataset`, `keyValueStore`, or `requestQueue`. | ||
| - Specify `resourcePermissions` with the minimal required scope: `"READ"` or `"READ", "WRITE"`. | ||
|
|
||
| Actors running under full permissions are assumed to have full (i.e. read/write/manage) access to user storages. In that case the `resourcePermissions` field does not have to be set. | ||
|
|
||
| Example input schema field (single resource): | ||
|
|
||
| ```json | ||
| { | ||
| "title": "Output dataset", | ||
| "type": "string", | ||
| "editor": "resourcePicker", | ||
| "resourceType": "dataset", | ||
| "resourcePermissions": ["READ", "WRITE"] | ||
| } | ||
| ``` | ||
|
|
||
| Selecting multiple resources: | ||
|
|
||
| - Use `type: "array"` to let users choose more than one storage. | ||
| - Each selected resource will have the same `resourcePermissions` | ||
|
|
||
| ```json | ||
| { | ||
| "title": "Source datasets", | ||
| "type": "array", | ||
| "editor": "resourcePicker", | ||
| "resourceType": "dataset", | ||
| "resourcePermissions": ["READ"], | ||
| "minItems": 1 | ||
| } | ||
| ``` | ||
|
|
||
| Behavior at run time: | ||
|
|
||
| - The user’s selection is injected into the run input, and the run token is expanded to allow only the requested operations on the selected storages. | ||
| - If your code attempts an operation not covered by `resourcePermissions` (for example, writing with only `READ`), the platform returns an insufficient-permissions error. | ||
|
|
||
| See the full [input schema reference for details.](../actor_definition/input_schema/specification.md). | ||
|
|
||
| ### Requesting full permissions | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Title doesn't correspond to what we write in the paragraph. Who is requesting full permissions? Sounds confusing. Maybe Keeping full permissions?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also not sure, maybe move to migrations? |
||
|
|
||
| Designing your Actors to work under limited permissions is the recommended approach, it helps improve your Actor’s [Actor Quality score](../../publishing/quality_score.mdx#trustworthiness) and increases user trust and adoption. However, some use cases do legitimately require broader access to user data (e.g., to perform administrative tasks or orchestrate other Actors). If your Actor falls in this category or cannot function with limited permissions for another reason: | ||
|
|
||
| - Explain why you need full permissions in your Actor's README. This will help keep user trust and set correct user expectations. | ||
| - Set the permission level in the Actor’s **Settings** in Console to **Full permissions**. | ||
| - Be aware of the [UX implications](#end-user-experience) and impact on [Actor Quality score](../../publishing/quality_score.mdx) for full-permission Actors. | ||
|
|
||
|
|
||
| :::info | ||
|
|
||
| Actor permissions are a new feature. If something is preventing you from migrating to limited permissions or you have a use case that you think should work under limited permissions and it does not, please reach out to support or talk to us on [the community forum](https://discord.gg/eN73Xdhtqc). | ||
|
|
||
| ::: | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,148 @@ | ||||||||
| --- | ||||||||
| title: Migration guide | ||||||||
| description: How to migrate your Actor to limited permissions. Common migration paths, code examples, and common issues. | ||||||||
| sidebar_position: 9 | ||||||||
| slug: /actors/development/permissions/migration-guide | ||||||||
| --- | ||||||||
|
|
||||||||
| **Migrate your Actor to limited permissions, review common migration paths, code examples, and solutions to common issues.** | ||||||||
|
|
||||||||
| --- | ||||||||
|
|
||||||||
| Use this guide to migrate existing Actors to use [limited permissions](index.md#how-actor-permissions-work). The general prerequisite is to update to the latest [Apify SDK](https://docs.apify.com/sdk). | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (nit):
Suggested change
|
||||||||
|
|
||||||||
| Recommended minimum SDK versions: | ||||||||
|
|
||||||||
| - JavaScript SDK: [apify@3.4.4](https://github.com/apify/apify-sdk-js/releases/tag/apify%403.4.4) | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (nit): why versions are inconsistent, let's just keep numbers ? 3.4.4 and 3.0.0 |
||||||||
| - Python SDK: [v3.0.0](https://github.com/apify/apify-sdk-python/releases/tag/v3.0.0) | ||||||||
|
|
||||||||
| Before you start it's helpful to understand [what access restrictions limited permissions impose](index.md#how-actor-permissions-work). | ||||||||
|
|
||||||||
| ## How to test your Actor with limited permissions before migrating | ||||||||
|
|
||||||||
| You can override permission level for a single run using run options under Actor Source tab in Console: | ||||||||
|
|
||||||||
|  | ||||||||
|
|
||||||||
| You can do the same using the Apify Client as well: | ||||||||
|
|
||||||||
| ```tsx | ||||||||
| await apifyClient.actor(actorId).call(input, { | ||||||||
| forcePermissionLevel: ACTOR_PERMISSION_LEVEL.LIMITED_PERMISSIONS, | ||||||||
| }); | ||||||||
| ``` | ||||||||
|
|
||||||||
| Or just using the API: | ||||||||
|
|
||||||||
| ```tsx | ||||||||
| POST https://api.apify.com/v2/acts/<actor_id>/runs?**forcePermissionLevel=LIMITED_PERMISSIONS** | ||||||||
| ``` | ||||||||
|
|
||||||||
|
|
||||||||
| ## Common migration paths | ||||||||
|
|
||||||||
| We expect that most public Actors can be migrated to limited permissions with minor, if any, adjustments. The general prerequisite is to **update the Actor to use the latest [Apify SDK](https://docs.apify.com/sdk)**. To assess what, if anything, needs to change in your Actor, review these areas: | ||||||||
|
|
||||||||
| - How your actor uses storages (e.g. named storages and storages provided via input) | ||||||||
| - Whether it requests correct resource access for user-provided storages | ||||||||
| - Whether it needs to access information about the user (namely if the user is paying or access their proxy configuration) | ||||||||
|
|
||||||||
| Once you have updated and [tested](#how-to-test-your-actor-with-limited-permissions-before-migrating) your Actor, you can change the permissions in the Actor settings. The setting will take immediate effect. | ||||||||
|
|
||||||||
| Below you can read a guide covering common migration paths for more advanced cases in greater detail. | ||||||||
|
|
||||||||
| ### The Actor only pushes data to default storages | ||||||||
|
|
||||||||
| This is the most common and simplest use case. If your Actor only reads its input and writes results to its default dataset, key-value store, or request queue, **no changes are needed**. Limited permissions fully support this behavior out of the box. | ||||||||
|
|
||||||||
| ### The Actor calls other Actors | ||||||||
|
|
||||||||
| An Actor with limited permissions can only call other Actors that also have limited permissions. If your Actor calls another one, you will need to ensure the target Actor has been migrated first. | ||||||||
|
|
||||||||
| ### The Actor accesses storages provided by the user | ||||||||
|
|
||||||||
| If your Actor is designed to read from or write to a storage that the user provides via an input field, you must explicitly declare what access you need in Actor’s schema. | ||||||||
|
|
||||||||
| 1. Populate `resourceType` property on the field to enable the native resource picker. | ||||||||
| 2. Populate `resourcePermissions` with permissions you need for the resource. | ||||||||
|
|
||||||||
| Let’s say your Actor allows the user to provide a custom dataset that your Actor should output its result to. Your `input_schema.json` might contain something like this: | ||||||||
|
|
||||||||
| ```json | ||||||||
| { | ||||||||
| "title": "Output", | ||||||||
| "type": "string", | ||||||||
| "description": "Select a dataset for the Actor results", | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| To support limited permissions, change it to this: | ||||||||
|
|
||||||||
| ```json | ||||||||
| { | ||||||||
| "title": "Output", | ||||||||
| "type": "string", | ||||||||
| "description": "Select a dataset for the Actor results", | ||||||||
| "resourceType": "dataset", | ||||||||
| "resourcePermissions": ["READ", "WRITE"], | ||||||||
| "editor": "textfield", // If you want to preserve the plain "string" input UI, instead of rich resource picker. | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| Now when the platform runs your Actor, it’ll automatically add the user provided storage to the Actor’s scope so that it can access it. | ||||||||
|
|
||||||||
| :::info Backward compatibility | ||||||||
|
|
||||||||
| The user can provide the resource both via its name and its ID. If you have existing users with existing inputs that specify the resource via its name, this change to the input schema won’t break it. | ||||||||
|
|
||||||||
| ::: | ||||||||
|
|
||||||||
| ### The Actor accesses named storages | ||||||||
|
|
||||||||
| Actors sometimes use named storages for caching or persisting state across runs. With limited permissions, an Actor can create a named storage on its first run and will automatically retain access to it in all subsequent runs by the same user. | ||||||||
|
|
||||||||
| If your Actor previously relied on accessing a pre-existing named storage, you will need to rename it in your code. This will cause the Actor to recreate the storage under the new system on its next run. | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (nit): oh, I am afraid that no one would do it, it seems complicated 😄 Maybe I would also add to this section something like avoid using hardcoded storages and just update the input, so user can provide it(and link to "The actor accesses storages provided by users" or to current "Accessing user provided storages")?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a pretty good idea how to migrate existing storages 👍🏻 |
||||||||
|
|
||||||||
| In order to achieve a smooth migration without disrupting your Actor’s users, you will need to make sure that your Actor can handle the transition. The suggested approach is the following: | ||||||||
|
|
||||||||
| 1. Adjust the code of the Actor so that it can run with both limited and full permissions. | ||||||||
| 2. Change the Actor setting to limited permissions. | ||||||||
| 3. Clean up the migration code. | ||||||||
|
|
||||||||
| ```ts | ||||||||
| const OLD_CACHE_STORE_NAME = 'my-actor-cache'; | ||||||||
| const NEW_CACHE_STORE_NAME = 'my-actor-cache-updated'; | ||||||||
|
|
||||||||
| let store; | ||||||||
|
|
||||||||
| if (process.env.ACTOR_PERMISSION_LEVEL === 'LIMITED_PERMISSIONS') { | ||||||||
| // If the Actor is running with limited permissions and we need to create | ||||||||
| // a new store. The platform will remember that the store was created by this Actor | ||||||||
| // and will allow access in all follow-up runs. | ||||||||
| store = await Actor.openKeyValueStore(NEW_CACHE_STORE_NAME); | ||||||||
| } else { | ||||||||
| // If the Actor is still running with full permissions and we should use | ||||||||
| // the existing store. | ||||||||
| store = await Actor.openKeyValueStore(OLD_CACHE_STORE_NAME); | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| :::info Re-create cache only under limited permissions. | ||||||||
|
|
||||||||
| The goal here is to create the new storage **only once the Actor runs with limited permissions**. Only that way the access is retained in follow-up runs. | ||||||||
|
|
||||||||
| ::: | ||||||||
|
|
||||||||
| If the existing contents of the named storage are critical for your Actor to keep functioning for the existing users and it is impossible, costly or highly impractical to migrate, contact support or reach out to us [on the community forum](https://discord.gg/eN73Xdhtqc). We can discuss the available options. | ||||||||
|
|
||||||||
| ### The Actor needs to know whether the user is paying | ||||||||
|
|
||||||||
| Some Actors have different logic for free and paying users. Previously you could retrieve this information by calling the `/users/me` API endpoint. However, Actors running under limited permissions don't have access to that endpoint. To get this information, your Actor should read the `APIFY_USER_IS_PAYING` environment variable, or directly use the SDK to obtain the value: | ||||||||
|
|
||||||||
| ```ts | ||||||||
| const { userIsPaying } = Actor.getEnv(); | ||||||||
| ``` | ||||||||
|
|
||||||||
| ### The Actor uses Proxy | ||||||||
|
|
||||||||
| Similarly, if your Actor uses [Proxy](../../../proxy/index.md) and needs to retrieve the user's proxy password, it should get it from the `APIFY_PROXY_PASSWORD` environment variable instead of calling the `/users/me` endpoint or, preferably, rely directly on the SDK to handle proxy configuration automatically. | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the copy that needs to be updated. Let's not forget about updating this screenshot as well.