Skip to main content
Version: 1.0.0

QuickStart - Add permissions to your Python app

If you are not using asyncio in your code, you can use the sync-python SDK.

In this tutorial, we will show you how to integrate Permit.io with your Application in just a few simple steps.

Setup your PDP (Policy Decision Point) Container

We provide you with a Policy-Decision-Point - aka an authorization microservice, as a container for you to use. Please follow the steps below to install and run the container on your local machine.

1. Pull our PDP container from Docker Hub

If you do not have Docker installed as of yet, click here to install Docker.

docker pull permitio/pdp:latest

2. Get the Permit.io API key

Navigate to the Project Management page with the Permit.io web interface. Find the active environment that is marked with a green dot on the icon. Copy the Secret Key.

Copy secret key from Projects management

Alternatively, while anyhwere on the Permit.io web interface, click on your user icon in the top right of the screen, and "Copy SDK Secret Key" from there.

Copy secret key from user menu

3. Run the container

Remember to replace <YOUR_API_KEY> with the Secret Key you have just obtained in the previous step.

docker run -p 7766:7000 --env PDP_API_KEY=<YOUR_API_KEY> permitio/pdp
info

Congratulations! You should now have a PDP container running. You can always check the status of the container by typing docker ps in your terminal.

Let's now add the Permit SDK to your app or use the following demo example below.


Add the SDK to your Python code

Initialise the Python SDK and check for permissions.

  1. Install the Permit.io SDK:
pip install permit
  1. Import the SDK into your code.
    Notice that you need to import the class Permit from permit.sync to get the sync-python SDK.
from permit.sync import Permit
  1. Create a new instance of the SDK.
    You can find instructions on getting a secret API key in the previous section.
# This line initializes the SDK and connects your python app
# to the Permit.io PDP container you've set up.
permit = Permit(
# in production, you might need to change this url to fit your deployment
pdp="http://localhost:7766",
# your secret API KEY
token="<your-api-key>",
)

Check for permissions using the API

You can run a permission check with permit.check(), passing in 3 arguments:

  • user_id: a unique string id that identifies the user doing the action.
  • action: the action performed.
  • resource: the resource (object) the action is performed on.

In the following example we are checking that a user with the unique id john@smith.com can create a document resource.

permitted = await permit.check("john@smith.com", "create", "document")

if permitted:
print("Jack is permitted to create a document")
else:
print("Jack is NOT PERMITTED to create document!")

Permission checks are being run against the PDP container with minimal latency and without leaving your network.


Write API

Running permit.write() will perform API calls against the Permit cloud and will modify the state of permissions and other objects in the system.

Sync user (create a user in the permissions system)

Before being able to check permissions with permit.check() - Permit must be able to identify the user and attach permissions and roles to that user. In order to declare a new user in the system, use permit.api.sync_user():

user = {
"key": "john@smith.com", # can be any unique string
"firstName": "John", # optional
"lastName": "Smith", # optional
"email": "john@smith.com", # optional
}
permit.write(permit.api.sync_user(user))

Sync user with initial roles

If you want to attach a role to a user in the same API call you can define initial roles by adding a role key. Each item in the initial role list will include a role key (the role name) and a tenant key.

user = {
"key": "john@smith.com",
"firstName": "John",
"lastName": "Smith",
"email": "john@smith.com",
# John will be assigned the admin role in the default tenant upon creation
"roles": [{"role":"admin", "tenant": "default"}]
}
permit.write(permit.api.sync_user(user))
note

If a user with such key already exists in Permit, we will not override the user roles and Permit will ignore the role key completely.


Create a tenant

Tenants represent user and resource boundaries in your system. Typically if you are building a multi tenant SaaS application where you are serving multiple customers from the same software instances, tenants allow you to create a boundary around one customer (i.e: tenant) such that users outside the tenant cannot access the tenant's associated resources.

Every one of your customers is typically a tenant that contains only that tenant's users.

To create a tenant, use permit.api.create_tenant():

cool_company_tenant = {
"key": "cool_company_inc",
"name": "Cool Company Inc"
}

permit.write(permit.api.create_tenant(cool_company_tenant))

Assign a role

You can assign a role to a user in a given tenant:

permit.write(
permit.api.assign_role("john@smith.com", "viewer", "cool_company_inc")
)

Chaining multiple mutations together

You can chain multiple write operations (or mutations), and permit.write() will run them according to the order you specify.

# runs the mutations in order:
permit.write(
# first creates the user "john"
permit.api.sync_user({
"key": "john@smith.com",
"firstName": "John",
"lastName": "Smith",
"email": "john@smith.com",
}),
# then, creates the "cool_company_inc" tenant
permit.api.create_tenant({
"key": "cool_company_inc",
"name": "Cool Company Inc"
}),
# finally, assigns the role "admin" to user "john" on the tenant "cool_company_inc"
permit.api.assign_role("john@smith.com", "admin", "cool_company_inc")
)

Full app example

Assuming a Python app made up of a single file, with the permit and FastAPI modules installed.

Create a new directory for your new python project.

mkdir hello-permissions && cd hello-permissions

Optionally, create a new virtual environment for your project - you might need to install pyenv and virtualenv.

pyenv virtualenv permissions && pyenv activate permissions

Now install the Permit.io SDK. We will also install flask package.

pip install permit flask

Create a file called test.py.

touch test.py

Copy the following code inside test.py and replace with your API KEY and user-object. You can find instructions on getting a secret API Key in the previous section.

import json

from permit.sync import Permit

from flask import Flask, Response

app = Flask(__name__)

# This line initializes the SDK and connects your python app
# to the Permit.io PDP container you've set up in the previous step.
permit = Permit(
# in production, you might need to change this url to fit your deployment
pdp="http://localhost:7766",
# your API KEY
token="[YOUR_API_KEY]",
)

def sync_objects():
# first let's create a user:
user = {
"key": "john@smith.com",
"firstName": "John",
"lastName": "Smith",
"email": "john@smith.com",
"roles": [{"role":"admin", "tenant": "default"}]
}
permit.write(permit.api.sync_user(user))

tenant2 = {
"key": "tenant2",
"name": "Second Tenant"
}

# create tenant 2 and assign role viewer to user john
permit.write(
permit.api.create_tenant(tenant2),
permit.api.assign_role("john@smith.com", "viewer", "tenant2")
)

sync_objects()

@app.route("/")
def check_permissions():
# After we created this user in the previous step, we also synced the user's identifier
# to permit.io servers with permit.write(permit.api.syncUser(user)). The user identifier
# can be anything (email, db id, etc.) but must be unique for each user. Now that the
# user is synced, we can use its identifier to check permissions with `permit.check()`.
permitted = permit.check("john@smith.com", "retrieve", "task") # default tenant is used
if not permitted:
return Response(json.dumps({
"result": f"John Smith is NOT PERMITTED to retrieve task!"
}), status=403, mimetype='application/json')

return Response(json.dumps({
"result": f"John Smith is PERMITTED to retrieve task!"
}), status=200, mimetype='application/json')

@app.route("/tenant2")
def check_permissions_tenant2():
# After we created this user in the previous step, we also synced the user's identifier
# to permit.io servers with permit.write(permit.api.syncUser(user)). The user identifier
# can be anything (email, db id, etc.) but must be unique for each user. Now that the
# user is synced, we can use its identifier to check permissions with `permit.check()`.
permitted = permit.check("john@smith.com", "create", {"type": "task", "tenant": "tenant2"}) # tenant2 is used
if not permitted:
return Response(json.dumps({
"result": f"John Smith is NOT PERMITTED to create task (tenant 2)!"
}), status=403, mimetype='application/json')

return Response(json.dumps({
"result": f"John Smith is PERMITTED to create task (tenant 2)!"
}), status=200, mimetype='application/json')

Now that your application is ready, let's run it!

FLASK_APP=test flask run --host=0.0.0.0

Finally, go to your applications localhost live deployment to see the outcome of the permission check.