QuickStart - Add permissions to your Python app
If you are not using asyncio in your code, you can use the sync-python SDK.
This tutorial is intended for users who have completed the basic setup of at least one policy in Permit. If you haven’t done that yet, check out this guide first.
1. Get your Permit Environment API Key
- In the Permit Dashboard, navigate to the Projects screen.
- Find the Project and Environment you wish to connect to.
- Click the icon on the top right of the environment card.
- Click Copy API Key.
You can also copy the Environment API Key of the active environment by clicking on the User Menu > Copy Environment Key
The API Key that you will copy from the user menu is linked to the active environment on the sidebar. Switching to another active environment and then clicking on the Copy Environment Key option will copy a different API Key - the API key of the newly activated environment.
2. Setup your PDP (Policy Decision Point) Container
Permit provides you with a Policy Decision Point, which functions as your microservice for authorization. The PDP is provided as a docker container ready for you to use, or as a cloud version for quick experimentation.
- Cloud PDP
- Container PDP
It is extremely simple to utilize the cloud PDP. As part of the initialization of the Permit instance, you need to pass the cloud PDP URL.
The cloud PDP is great for quick experimentation with Permit, to learn how the service works, and to quickly integrate the SDK.
In production deployments, it is best to deploy the Docker Container PDP for better latency and availability.
For time being, the cloud PDP is not compatible with Attribute-based Access Control policies (ABAC) and also Relationship-based Access Control policies (ReBAC).
// This line initializes the SDK and connects your app
// to the Permit.io Cloud PDP.
const permit = new Permit({
pdp: "https://cloudpdp.api.permit.io",
// your API Key
token: "[YOUR_API_KEY]",
});
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-v2:latest
2. Run the container
Remember to replace <YOUR_API_KEY>
with the Secret Key you obtained in the previous step.
docker run -it -p 7766:7000 --env PDP_DEBUG=True --env PDP_API_KEY=<YOUR_API_KEY> permitio/pdp-v2:latest
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 add the Permit SDK to your app or use the demo example below.
Add the SDK to your Python code
Initialise the Python SDK and check for permissions.
- Install the Permit.io SDK:
pip install permit
- Import the SDK into your code.
Notice that you need to import the classPermit
frompermit.sync
to get the sync-python SDK.
from permit.sync import Permit
- 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 SDK
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("John is permitted to create a document")
else:
print("John is NOT PERMITTED to create document!")
Usually instead of an email you'd use the unique identifier provided by your chosen authentication solution. You can also pass the entire decoded JWT, to include attributes about the user.
In cases where you are dealing with more than one tenant in your application, permit.check()
can pass the tenant as part of the resource.
The tenant passed in needs to be either the tenant id or the tenant key.
You can use the list_tenants API to get the ids and keys set for your tenants.
tenant
: a unique tenant id or tenant key that you have defined within Permit.
permitted = await permit.check("userId", "action", { type: "resource", tenant: "tenant" })
Check permissions against ABAC policies
Above we have checked for permissions against an RBAC policy - but what if we have an ABAC policy we want to run a permission check for? An ABAC policy is made up of User Sets and Resource Sets, which you can read more about here.
With ABAC we define conditions based on pre-configured attributes.
If we are running a permit.check()
for an ABAC policy, we replace the userId
and the resource
with objects, containing attributes.
permitted = await permit.check(
# User Set
{
userId: "check@permit.io",
attributes: {
location: "England",
department: "Engineering",
},
},
# Action
"action",
# Resource Set
{
type: "resource",
attributes: {
hasApproval: "true",
},
tenant: "tenant",
}
)
Permission checks are being run against the PDP container that's running locally on your machine - offering minimal latency and without leaving your network.
This means that your user data never goes outside your system, keeping security high.
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==1.0.0rc1 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.