Skip to main content

Migrate from the v1 API to v2

Move an application from the deprecated Permit.io v1 API, v1 policy decision point (PDP), and v1 SDKs to v2. This page is for maintainers of code that calls the v1 API or runs a v1 PDP. The first half is the migration procedure, in the order to run it. The second half is a reference of the v2 object hierarchy, paths, and keys that the procedure uses.

Who needs to migrate

Migrate if your code does any of the following:

  • Calls the Permit REST API at a v1 path.
  • Runs a v1 PDP container.
  • Uses a v1 SDK.

The v1 API and v1 PDPs are deprecated. Features added in v2, such as attribute-based access control (ABAC) condition sets, are available only in the v2 API.

What changed in v2

Areav1v2
Object hierarchyObjects could live at the organization levelOrganizations contain projects, projects contain environments, and environments contain almost every other object. See v2 object hierarchy.
API rootsMixedGeneral objects at /v2/orgs and /v2/projects, schema objects under /v2/schema, and facts objects under /v2/facts
IdentifiersSlugs, custom_id values, and keys in different placesKeys everywhere. Every path accepts either the key or the Permit ID of an object. See Keys.
Organization-scoped schema objectsSupportedNot supported. Move them into an environment. See Move off organization-scoped objects.
SDK write callsv1 write APIA different write API. Code that writes through the SDK must change. See Upgrade the PDP and SDKs.
permit.check() and SDK initializationv1 callsSame calls as v1

The v1 and v2 APIs read and write the same data, so you can use both during the migration. The two APIs make different assumptions about the structure of data, so a v1 call can behave differently from the v2 call for the same object.

Migration order

  1. Move off organization-scoped objects, if you have any. Do this first, because a v2 PDP serves one environment and its policy.
  2. Upgrade each service's SDK and point it at a v2 PDP in the same change. Run the v2 PDP next to the v1 PDP until every service has moved.
  3. Update REST API calls at any point. The v1 and v2 APIs share data, so each call can move to v2 on its own schedule.

1. Move off organization-scoped objects

v2 does not support organization-scoped schema objects. Every schema object and facts object belongs to one environment, so a change in one environment can't break another.

A v2 PDP loads the policy and data of the environment that its PDP_API_KEY belongs to, so an object that sits in another environment takes no part in that PDP's decisions. See Run the PDP. Recreate the objects you defined outside your own environments in each environment that needs them before you point a service at a v2 PDP.

  1. List your projects and environments. With an organization API key, list the projects, then list the environments of each project:
curl -H 'Authorization: Bearer <YOUR_ORG_API_KEY>' https://api.permit.io/v2/projects
curl -H 'Authorization: Bearer <YOUR_ORG_API_KEY>' https://api.permit.io/v2/projects/{proj_id}/envs

Replace <YOUR_ORG_API_KEY> with an organization API key, and {proj_id} with a project key or ID from the first response. Compare both lists with the projects and environments you created. An environment that nobody on your team created holds objects that v1 defined outside your environments. Take its key from the response and use that key in the paths below. If every project and environment in the list is one you created, you have no organization-scoped objects. Skip to Upgrade the PDP and SDKs.

  1. List the roles and users in that environment, with its project key as {proj_id} and its own key as {env_id}:
curl -H 'Authorization: Bearer <YOUR_ORG_API_KEY>' https://api.permit.io/v2/schema/{proj_id}/{env_id}/roles
curl -H 'Authorization: Bearer <YOUR_ORG_API_KEY>' https://api.permit.io/v2/facts/{proj_id}/{env_id}/users

The roles endpoint returns an array of roles, or a paginated object with the roles in data. The users endpoint returns a paginated object with the users in data. Every entry is an object to move. If both lists are empty, that environment holds nothing to move.

  1. Recreate each role and user from that environment in every environment that uses it. Environments are self-contained, so adding an object to your own environment changes nothing in the environment you found it in, and your v1 PDPs keep serving the decisions they served before.
  2. Verify the move: run a permit.check() call against a v2 PDP for a user and role you recreated. Compare the decision with the decision the same check returns through your v1 PDP. The two decisions match when the move is complete.
  3. Delete the environment you didn't create, and the project that holds it if that project holds nothing else.
Deleting an environment deletes the objects inside it

Deleting an environment deletes the roles, users, and other objects it holds, and a PDP that loads that environment stops getting policy and data for them. Delete it only after you recreate its objects in your own environments and a permit.check() call through a v2 PDP returns the decision you expect.

2. Upgrade the PDP and SDKs

You can run several PDPs for the same environment without extra configuration. Run a v2 PDP next to your v1 PDP, and point each service at the v2 PDP when you upgrade its SDK.

  1. Start a v2 PDP. Use the command you use for the v1 PDP, with the image changed to permitio/pdp-v2. In this example, replace permit_key_abcdefghijklmnopqrstuvwxyz with your environment API key:
docker run -p 7766:7000 \
--env PDP_API_KEY=permit_key_abcdefghijklmnopqrstuvwxyz \
--env PDP_DEBUG=True \
permitio/pdp-v2:latest
  1. Upgrade each service to the v2 SDK, and set the SDK's PDP address to the v2 PDP in the same change. SDK initialization and permit.check() calls don't change.
  2. If the service writes data through the SDK, rewrite those calls for the v2 write API. See Rewrite SDK write calls.
  3. Verify the service: run a permit.check() call through the v2 PDP, and confirm it returns the expected decision. See Run the PDP for how to check that the PDP container is running.
  4. When every service uses the v2 SDK, stop the v1 PDP.

Rewrite SDK write calls

The v2 SDK write API is not compatible with the v1 write API. For example, in the Python SDK, a v1 user sync looks like this:

await permit.write(permit.api.sync_user(
user.customId,
user.first_name,
user.last_name,
user.email,
))

In v2, the same sync is one call:

await permit.api.sync_user(user)

user is a dict with the same fields as a user in the REST API. Only key is required. Also pass email, or first_name and last_name, so decision logs show a readable user name.

The Python SDK marks permit.api.sync_user() as deprecated and points to permit.api.users.sync(), which takes the same argument: a UserCreate object or a dict.

For the full SDK API, see the Node.js SDK quickstart and the Python SDK quickstart.

3. Update REST API calls

The v2 API reference documents v2 endpoints only, and there is no published table of v1 paths. Map each call by the object it acts on instead of by its old path:

  1. Identify the object type the v1 call reads or writes: user, tenant, role assignment, role, resource, or condition set.
  2. Find that object type in the table below, and build the path with your project and environment key.
  3. Replace v1 slugs and custom_id values with the object's key. See Keys.
  4. Confirm the method, the path parameters, and the request body against the object's tag in the Permit API reference.
  5. Run the v2 call, then read the object back with the matching GET request and compare it with what the v1 call returned.

v2 endpoints by object type

Object the call acts onv2 method and path
Users in an environmentGET and POST /v2/facts/{proj_id}/{env_id}/users
One user, including a full sync of the userGET, PUT, PATCH, and DELETE /v2/facts/{proj_id}/{env_id}/users/{user_id}
Roles of one userPOST and DELETE /v2/facts/{proj_id}/{env_id}/users/{user_id}/roles
Role assignmentsGET, POST, and DELETE /v2/facts/{proj_id}/{env_id}/role_assignments
TenantsGET and POST /v2/facts/{proj_id}/{env_id}/tenants, and /tenants/{tenant_id} for one tenant
Users of one tenantGET and POST /v2/facts/{proj_id}/{env_id}/tenants/{tenant_id}/users
Resource instancesGET and POST /v2/facts/{proj_id}/{env_id}/resource_instances
RolesGET and POST /v2/schema/{proj_id}/{env_id}/roles, and /roles/{role_id} for one role
Resources, with their actions and attributesGET and POST /v2/schema/{proj_id}/{env_id}/resources, and /resources/{resource_id} for one resource
Resource rolesGET and POST /v2/schema/{proj_id}/{env_id}/resources/{resource_id}/roles
Condition sets (ABAC user sets and resource sets)GET and POST /v2/schema/{proj_id}/{env_id}/condition_sets
Condition set rulesGET, POST, and DELETE /v2/facts/{proj_id}/{env_id}/set_rules
Many users or tenants in one callPOST and DELETE /v2/facts/{proj_id}/{env_id}/bulk/users and /bulk/tenants, and PUT /v2/facts/{proj_id}/{env_id}/bulk/users to replace users. See Bulk operations.

Permission checks don't go through this API. A check goes to the PDP, not to api.permit.io. See Check permissions.

If a v1 call has no clear v2 object, ask in the Permit Slack community with the v1 path you are replacing.

Confirm the migration is complete

The migration is done when all of the following hold:

  • Every project and environment that GET /v2/projects and GET /v2/projects/{proj_id}/envs return is one you created.
  • docker ps lists no v1 PDP container, and every running PDP container uses the permitio/pdp-v2 image.
  • A permit.check() call through each v2 PDP returns the decision you expect for a user you migrated.
  • A search of your code base for /v1/ and for v1 SDK write calls returns no hits.

v2 object hierarchy

v2 objects nest in a strict hierarchy:

LevelRepresentsExample
OrganizationYour companyAcme Corp
ProjectOne product of your company. Projects share little with each other.billing, crm
EnvironmentOne deployment stage of a project, such as production or stagingprod, staging

Environments are self-contained. A change in the staging environment does not affect the production environment. To copy policy from one environment to another, see Create, copy, and merge environments.

Object types

Objects inside an environment are either schema objects or facts objects:

TypeWhat it definesObjectsAPI root
Schema objectsWhat can exist and what is allowed: the rules of your policyResources (with their actions and attributes), roles (with their permissions), condition sets/v2/schema
Facts objectsWhat exists: the data your policy runs onTenants, users, role assignments, condition set rules/v2/facts

Organizations, projects, and environments are general objects.

General object paths

ObjectPath
Organizations/v2/orgs
Projects/v2/projects
Environments/v2/projects/{project_id}/envs

Projects are not nested under organizations in the path. Each API key belongs to a single organization, so the organization is implicit in every call. GET /v2/orgs returns the organization the API key belongs to.

Schema object paths

ObjectPath
Resources/v2/schema/{proj_id}/{env_id}/resources
Resource actions/v2/schema/{proj_id}/{env_id}/resources/{resource_id}/actions
Resource attributes/v2/schema/{proj_id}/{env_id}/resources/{resource_id}/attributes
Roles/v2/schema/{proj_id}/{env_id}/roles
Condition sets/v2/schema/{proj_id}/{env_id}/condition_sets

Facts object paths

ObjectPath
Users/v2/facts/{proj_id}/{env_id}/users
Tenants/v2/facts/{proj_id}/{env_id}/tenants
Tenant-user associations/v2/facts/{proj_id}/{env_id}/tenants/{tenant_id}/users
Role assignments/v2/facts/{proj_id}/{env_id}/role_assignments
Condition set rules/v2/facts/{proj_id}/{env_id}/set_rules

v2 path and key conventions

HTTP methods

Nested objects, such as tenant-user associations, live under the path of their parent object. v2 paths follow REST conventions:

RequestEffect
GET on an object typeLists the objects
GET on one objectReturns the object
POST on an object typeCreates an object
PATCH on one objectChanges only the fields in the request body
PUT on one objectReplaces the object. Fields missing from the request body reset to their defaults.
DELETE on one objectDeletes the object
POST on a sub-path of an objectRuns an action on the object, for example POST /v2/pdps/{proj_id}/{env_id}/configs/{pdp_id}/rotate-api-key rotates the API key of a PDP

v2 API calls authenticate with an API key in the same way as v1 calls. See Get your API key.

Keys

In v2, keys replace the v1 slugs and custom_id values. Every primary schema object and facts object has a key, and the key is required.

  • Most object keys accept the characters a-z, A-Z, 0-9, _, and -, so a UUID from your own system works as a key. A user key also accepts @, ., +, and |, so an email address works as a user key. For the exact pattern of one object type, see that object's schema in the Permit API reference.
  • A key can't change after you create the object. A key in a PUT body identifies the object to replace, and doesn't rename it.
  • A key is unique per object type within its namespace. For most objects the namespace is the environment. For an environment it is the project, and for a project it is the organization.
  • Permit uses a key only to look up the object and to check uniqueness. Wherever a path takes a Permit ID, it also accepts the key.

For example, one environment can hold a resource with the key john and a role with the key john, and two environments can each hold a resource with the key john. One environment can't hold two resources with the key john. Likewise, two projects can each have an environment with the key prod, but one project can't have two.

Example paths

ObjectPath
The document resource in the prod environment of the billing project, by key/v2/schema/billing/prod/resources/document
The same resource, by ID/v2/schema/billing/prod/resources/9014f244-9034-49a9-81ff-053a65f67ff1
The staging environment of the crm project, by key/v2/projects/crm/envs/staging
The same environment, by ID/v2/projects/crm/envs/1e9472f5-24d7-4b3b-b49b-39d2e8843913
The same environment, by project ID and environment ID/v2/projects/541e3523-2cdb-468a-8ca8-e7e8ccdb415d/envs/1e9472f5-24d7-4b3b-b49b-39d2e8843913

Get help

For migration questions, ask in the Permit Slack community.