Overview
Services let you build apps that connect users with your data. Sometimes you want to give different users different experiences inside your app, such as
- tailoring how they view the data,
- restricting which data they have access to, or
- restricting what actions they can take.
Permission Sets allow you to store and manage each user’s permissions in Platform. Whenever a user views your app, it can retrieve their permissions via the Platform API and act accordingly.
A permission set encapsulates a set of Resources, which conceptually represent things in your app that you want to control access to. Resources are identified by simple strings, and they can be permissioned just like Platform objects: users and groups can be shared on them with ‘Viewer’, ‘Editor’, or ‘Manager’ access, and if a user has a higher level permission, they automatically have any lower permissions too. It's up to your app to define what these access levels mean.
For example, let’s say your app interacts with data from different US states. You can create a permission set with 50 resources named “alabama_data”, “alaska_data”, etc. Then you can write code in your app so that if a user has ‘Viewer’ permission on “alaska_data”, they can view all the data for Alaska, and if they have ‘Editor’ permission on “alaska_data”, they can both view and modify the data for Alaska.
Once you have created a permission set, attach it to your service so that your service can use it. If users require the same permissions on multiple services, you can attach a single permission set to all of them. This keeps changes to permissions consistent across apps.
Creating a permission set
On your service’s configuration page, open the “Advanced” dropdown at the bottom of the page and find the “Permission Set” section. There you’ll be able to attach existing permission sets, or create a new one which will automatically be attached to this service. Once a permission set is attached, you can click a link to go to its configuration page.
Adding and editing resources
An empty permission set isn’t very useful, so let’s add some resources. Click the “Add Resource” button to open a pane that allows you to input a resource name and description. The resource name will be a unique identifier that your app can look up permissions by. Only ASCII letters (A-Z and a-z), numbers (0-9), dashes (-), and underscores (_) are allowed, and the name cannot be changed once set. The description is optional, but useful for keeping track of what this resource represents in your app.
Once you have created a resource, you can edit it by clicking its name in the table to open the Manage Resource pane. You can delete a resource by clicking the dots in the rightmost column of the table, and clicking the “Delete” button - but note that this delete is permanent!
Only users shared to the permission set with “Manager” permission can add, edit, or delete resources.
Giving users and groups permissions on the resources
You can edit who has access to a resource by clicking its name in the table to open the Manage Resource pane. This pane has controls for sharing new users and groups to the resource, adjusting what level of access a user or group has, and revoking access completely.
Similar to Platform objects, resources have three levels of access that you can share to a user or group: “Viewer”, “Editor”, and “Manager”. If a user has “Editor” permission, they also have “Viewer” permission, and if a user has “Manager” permission, they also have both “Viewer” and “Editor.” What these levels of permissions mean is for you to decide when you code your app. However, unlike with the permission set and other Platform objects, users who have “Manager” permission on a resource do not gain the ability to share other users to the resource.
Only users shared on the permission set with “Editor” or “Manager” permission can edit permissions on resources. Note that you can only view and edit permissions for users and groups that you can view.
Using permission sets in your app
When a user views your app, you’ll want to retrieve the data stored in the attached permission set to determine what they have access to. Have your app make this call to the Platform API:
GET https://api.civisanalytics.com/permission_sets/<permission_set_id>/users/<user_id>/permissions |
The ID of the attached permission set is supplied to your app as the environment variable CIVIS_PERMISSION_SET_ID. For every call to your app, Platform adds the ID of the user as the query parameter civisuserid. Additionally, the Platform API key that your app uses to make this call needs to have “Viewer” permission on both the attached permission set and the user that it is looking up.
A successful response has status code 200 and a JSON array of the form
[ { "resource_name": "alabama_data", "read": true, "write": true, "manage": false }, { "resource_name": "alaska_data", "read": true, "write": false, "manage": false } ] |
with an entry for each resource the user has any level of access to. The three boolean values in each entry signify whether the user has that permission on the resource.
If the API key your app is using does not have read permission on the attached permission set, or does not have read permission on the user, the API will respond with status code 404.
As an example, this is a very simple (without error handling) Python/Flask app showing how to retrieve the permissions and use them. Here we require that the user has “write” permission on resource “alaska_data” in order to do something:
from flask import Flask, request import civis import os
app = Flask(__name__) client = civis.APIClient() permission_set_id = int(os.environ["CIVIS_PERMISSION_SET_ID"])
def retrieve_permissions(user_id): client.permission_sets.list_users_permissions(permission_set_id, user_id)
def check(permissions, resource_name, permission_level): any([p[permission_level] for p in permissions if p["resource_name"] == resource_name])
@app.route('/do_something') def do_something(): user_id = int(request.args.get("civisuserid") permissions = retrieve_permissions(user_id) if check(permissions, "alaska_data", "write"): return "I did something!" |
Clever app developers may cache the permissions data between calls, so that their app does not have to make a call to the Platform API every time a user hits it. This speeds up the response time of the app, since it doesn't have to wait for the Platform API call to return, and helps avoid running into rate limiting on the Platform API.
Comments
0 comments
Please sign in to leave a comment.