-
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
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,131 @@ | ||
| --- | ||
| 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. | ||
|
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) This intro paragraph reads a bit awkward to me. Not sure what "access" means.... also I'd mention the inspiration from "sandboxed" apps on mobile permissions.
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) | ||
|
|
||
| ::: | ||
|
|
||
| ### Declaring permissions | ||
|
|
||
| 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 | ||
|
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. This is a repetition of the "Impact of Permission Level" section below. Maybe just remove this and move the screenshot to that section? 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. 3a0c308 Decided to leave the end user experience section and move the implications section(+your suggestions) to the warning admonition. |
||
|
|
||
| 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 | ||
|
|
||
| Actor permissions are a new feature. With the initial release, the distinction between full-permissions and limited-permissions Actors is primarily informational, but it will become increasingly significant over time. | ||
|
|
||
| Future changes may include: | ||
| - Stronger confirmations and/or warnings added when running full-permissions Actors | ||
| - Actors requiring full permissions may receive a lower [Actor Quality score](../../publishing/quality_score.mdx), which can reduce their ranking in the store. | ||
| - Some platform features and recommendations may prioritize limited-permissions Actors by default. | ||
|
|
||
| Whenever possible, design your Actors to use limited permissions and request only access they truly need. | ||
|
|
||
| ::: | ||
|
|
||
|
|
||
| ### Accessing user provided storages | ||
|
|
||
| Limited-permissions Actors can access storages that users explicitly provide via the Actor input. 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"`. | ||
|
|
||
| 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. | ||
| - The same `resourcePermissions` apply to each selected resource. | ||
|
|
||
| ```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 | ||
|
|
||
| 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.com/invite/crawlee-apify-801163717915574323). | ||
|
|
||
| ::: | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| --- | ||
| 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). | ||
|
|
||
| Recommended minimum SDK versions: | ||
|
|
||
| - JavaScript SDK: [apify@3.4.4](https://github.com/apify/apify-sdk-js/releases/tag/apify%403.4.4) | ||
| - 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 permission impose](index.md#how-actor-permissions-work). | ||
|
|
||
| ## How to test my Actor with limited permissions before migrating | ||
|
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. How to test your Actor... (for consistency with the rest of the copy) |
||
|
|
||
| You can override permission level for a single run using run options under Actor Source tab in Console: | ||
|
|
||
|  | ||
|
|
||
| Force Actor permissions for a single runs. | ||
|
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. This line is extraneous I think. Remove. |
||
|
|
||
| You can do the same using Apify Client as well: | ||
|
|
||
| ```tsx | ||
| await apifyClient.actor(actorId).call(input, { | ||
| forcePermissionLevel: ACTOR_PERMISSION_LEVEL.LIMITED_PERMISSIONS, | ||
| }); | ||
| ``` | ||
|
|
||
| Or using just 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)**. Below you can read a guide that covers various, more advanced cases. | ||
|
|
||
| Once you have updated and [tested](#how-to-test-my-actor-with-limited-permissions-before-migrating) your Actor, you can change the permissions in the Actor setting. The setting will take immediate effect. | ||
|
Comment on lines
+48
to
+50
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. Maybe flip these two paragraphs, so that the scenarios follow directly after the line "Below you can read a guide..." |
||
|
|
||
| ### 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 | ||
|
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. H3 (###) |
||
|
|
||
| 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 | ||
|
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. H3 (###) |
||
|
|
||
| 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 the Actor’s scope so that it can access it. | ||
|
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. ...to the Actor's scope... |
||
|
|
||
| :::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 | ||
|
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. H3 (###) |
||
|
|
||
| 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. | ||
|
|
||
| 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 is critical for your Actor to keep functioning for the existing users** (as in, you can’t afford removing the storage), reach out to us. We can discuss the available options. | ||
|
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. If the existing contents of the named storage are critical... Also, is the emphasis necessary for such a long part of the sentence? |
||
|
|
||
| ## The Actor needs to know whether the user is paying | ||
|
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. H3 (###) |
||
|
|
||
| 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: | ||
|
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. ...don't have access to that endpoint. To get this information, ... |
||
|
|
||
| ```ts | ||
| const { userIsPaying } = Actor.getEnv(); | ||
| ``` | ||
|
|
||
| ## The Actor uses proxy | ||
|
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. H3 (###) |
||
|
|
||
| Similarly, if your Actor needs 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 just rely on the SDK to take care of the documentation. | ||
|
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. ...endpoint, or preferably (remove double space after 'or') |
||
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.