Core

Prev Next

This article provides a comprehensive overview of integrating and using the PlainID Authorization Platform Python package within your application. It covers essential setup steps, including installation and authentication, and explains core concepts such as identity context, permission retrieval, and Policy enforcement.

It also introduces advanced capabilities such as category-based prompt filtering, anonymization of sensitive data, and SQL query authorization.

Installation

Prerequisites

  • Python 3.10–3.12
  • PlainID package

To install the PlainID package:

  1. Run the following command:

    pip install core-plainid
    

Authentication

All components support three authentication modes. At least one must be available at request time.

Mode When to Use
Client credentials Provide client_id and client_secret at construction time.
JWT token Provide client_id and pass an auth_token per request via RequestContext.
IDP provider Provide client_id and an IdpAuthProvider for automatic OAuth2 token management.

A per-request auth_token always takes precedence. If no auth_token is provided, the IDP provider is used to fetch a token. Only when neither is available does the client fall back to client_secret.

The IdpAuthProvider obtains and caches OAuth2 access tokens from an external Identity Provider. Tokens are fetched lazily in the background and automatically refreshed when they expire. When idp_auth_provider is set and no auth_token is provided per request, the provider automatically fetches a token from the IDP and uses it for authentication.

The following steps describe how to configure authentication using an IDP provider.

To configure authentication using an IDP provider:

  1. Import the IdpAuthProvider:

    from core_plainid.utils.idp_auth_provider import IdpAuthProvider
    
  2. Initialize the provider with your Identity Provider details:

    idp_provider = IdpAuthProvider(
        token_url="https://your-idp.com/oauth/token",
        client_id="your_idp_client_id",
        client_secret="your_idp_client_secret",
        audience="https://your-api-audience.com",
        resource="my-resource",
    )
    
  3. Pass the provider to the PlainIDPermissionsProvider:

    permissions_provider = PlainIDPermissionsProvider(
        base_url="https://platform-product.us1.plainid.io",
        client_id="your_client_id",
        idp_auth_provider=idp_provider,
    )
    
Parameter Type Required Description
token_url str Yes The IDP token endpoint URL
client_id str Yes OAuth2 client ID for the IDP
client_secret str Yes OAuth2 client secret for the IDP
grant_type str No OAuth2 grant type, default is "client_credentials"
audience str No Audience parameter included in the token request
**kwargs No Additional fields included in the token request body

Identity Context

PlainID supports two identity resolution modes:

  • Explicit identity via entity_id, entity_type_id, and optionally additional_identities in the request body.
  • Header-based identity via the headers field, which forwards headers directly to the PlainID API. These headers are matched against configured values to resolve relevant entities. In this mode, entity_id, entity_type_id, and additional_identities are not required.

Integration Flow

This section walks through initializing the client, defining identity, and retrieving permissions. The PlainIDPermissionsProvider is the main integration entry point.

To integrate PlainID into your application:

  1. Initialize the PlainIDPermissionsProvider:

    from core_plainid.utils.plainid_permissions_provider import PlainIDPermissionsProvider
    
    permissions_provider = PlainIDPermissionsProvider(
        base_url="https://platform-product.us1.plainid.io",
        client_id="your_client_id",
        client_secret="your_client_secret",
    )
    
  2. Define the RequestContext representing the identity:

    from core_plainid.models.context.request_context import RequestContext
    
    request_context = RequestContext(
        entity_id="user_123",
        entity_type_id="user",
    )
    
  3. For agent-based or delegated execution flows, include additional identities (optional):

    from core_plainid.models.context.request_context import (
        AdditionalIdentity,
        RequestContext,
    )
    
    request_context = RequestContext(
        entity_id="user_123",
        entity_id_type="user",
        additional_identities=[
            AdditionalIdentity(
                entity_id="agent_456",
                entity_type_id="agent",
            ),
        ],
    )
    
  4. Retrieve permissions from PlainID:

    permissions = await permissions_provider.aget_permissions(request_context)
    
    allowed_tools = permissions.tools
    allowed_categories = permissions.categories
    allowed_entities = permissions.entities
    

Category Filtering

The Categorizer classifies prompts into categories and validates them against PlainID Policies. If the prompt categories are not permitted, a PlainIDCategorizerException is raised. Multiple identities are supported through RequestContext.

Before using this feature, configure a Ruleset in PlainID using the Prompt_Control template and define categories as Assets, for example contract, HR, and finance.

To configure and use category filtering:

  1. Create a Ruleset in PlainID:

    # METADATA
    # custom:
    # plainid:
    # kind: Ruleset
    # name: All
    ruleset(asset, identity, requestParams, action) if {
        asset.template == "Prompt_Control"
    }
    
  2. Import the required classes:

    from core_plainid.categorization.categorizer import Categorizer
    from core_plainid.utils.plainid_permissions_provider import PlainIDPermissionsProvider
    from core_plainid.models.context.request_context import RequestContext
    
  3. Initialize dependencies:

    permissions_provider = PlainIDPermissionsProvider(
        base_url="https://platform-product.us1.plainid.io",
        client_id="your_client_id",
        client_secret="your_client_secret",
    )
    
    categorizer = Categorizer(
        classifier_provider=classifier,
        permissions_provider=permissions_provider,
        all_categories=["contract", "HR", "finance"],
    )
    
  4. Define the RequestContext:

    request_context = RequestContext(
        entity_id="your_entity_id",
        entity_type_id="your_entity_type",
    )
    
  5. Run categorization:

    result = await categorizer.acategorize(
        "I'd like to know the weather forecast for today",
        request_context=request_context,
    )
    

Category Classifiers

Two built-in classifiers are available.

LLMCategoryClassifierProvider
Uses an LLM to classify prompts. Model calls are powered by LiteLLM, which supports multiple LLM providers through a unified interface.

# OpenAI
export OPENAI_API_KEY="your_openai_api_key"

# Anthropic
export ANTHROPIC_API_KEY="your_anthropic_api_key"

# Azure OpenAI
export AZURE_API_KEY="your_azure_api_key"
export AZURE_API_BASE="https://your-resource.openai.azure.com"
export AZURE_API_VERSION="2024-02-01"
from core_plainid.categorization.llm_category_classifier_provider import LLMCategoryClassifierProvider

llm_classifier = LLMCategoryClassifierProvider(model="openai/gpt-4o")

The model parameter follows LiteLLM naming conventions. Classification quality depends on the selected model. Prefer larger or specialized models for better results.

ZeroShotCategoryClassifierProvider
Uses a Hugging Face zero-shot classification model. The model is downloaded automatically on first use.

from core_plainid.categorization.zeroshot_category_classifier_provider import ZeroShotCategoryClassifierProvider

zeroshot_classifier = ZeroShotCategoryClassifierProvider(
    model_name="facebook/bart-large-mnli",
    threshold=0.5,
)

The threshold parameter default is 0.5 and controls the minimum confidence score required for a category to be included. Use this classifier if you want better classification results without relying on an external LLM API, but note it requires disk space for the downloaded model.

Anonymization

The PresidioAnonymizer detects and anonymizes PII in text using Microsoft Presidio. It supports two actions: MASK (replaces PII with ***) and ENCRYPT (encrypts the detected PII using a provided key).

PlainID Setup
To use anonymization, configure Rulesets in PlainID using the Output_Control template.

To configure anonymization Rulesets:

  1. Define a Ruleset for each entity type:

    # METADATA
    # custom:
    #   plainid:
    #     kind: Ruleset
    #     name: PERSON
    ruleset(asset, identity, requestParams, action) if {
        asset.template == "Output_Control"
        asset["path"] == "PERSON"
        action.id in ["MASK"]
    }
    
  2. Configure custom regex entities in PlainID with a REGEX path prefix and a regexValue attribute containing the pattern:

    # METADATA
    # custom:
    #   plainid:
    #     kind: Ruleset
    #     name: REGEX_EMAIL
    ruleset(asset, identity, requestParams, action) if {
        asset.template == "Output_Control"
        asset["path"] == "REGEX_EMAIL"
        asset["regexValue"] == "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
        action.id in ["MASK"]
    }
    
  3. Configure AHDS entities as an example:

    # METADATA
    # custom:
    #   plainid:
    #     kind: Ruleset
    #     name: DOCTOR
    ruleset(asset, identity, requestParams, action) if {
        asset.template == "Output_Control"
        asset["path"] == "DOCTOR"
        action.id in ["MASK"]
    }
    

For medical or health data, you can enable Azure Health Data Services de-identification to detect PHI entities such as DOCTOR, PATIENT, and AGE. Configure them in PlainID the same way.

To use anonymization in your application:

  1. Initialize the PresidioAnonymizer:

    from core_plainid.anonymization.presidio_anonymizer import PresidioAnonymizer
    from core_plainid.utils.plainid_permissions_provider import PlainIDPermissionsProvider
    from core_plainid.models.context.request_context import RequestContext
    
    permissions_provider = PlainIDPermissionsProvider(
        base_url="https://platform-product.us1.plainid.io",
        client_id="your_client_id",
        client_secret="your_client_secret",
    )
    
    anonymizer = PresidioAnonymizer(
        permissions_provider=permissions_provider,
        encrypt_key="your_16_char_key!",
    )
    
  2. Define the RequestContext:

    request_context = RequestContext(
        entity_id="your_entity_id",
        entity_type_id="your_entity_type",
    )
    
  3. Run anonymization:

    result = await anonymizer.aanonymize(
        "John Smith lives in New York",
        request_context=request_context,
    )
    print(result)
    

The encrypt_key parameter is optional and only required if you use the ENCRYPT action. The key is used for AES encryption and must be 128, 192, or 256 bits long (16, 24, or 32 characters).

To enable Azure Health De-identification (AHDS) (example):

  1. Set the required environment variables:

    export AHDS_ENDPOINT="https://your-deid-service.api.deid.azure.com"
    export AZURE_TENANT_ID="your_azure_tenant_id"
    export AZURE_CLIENT_ID="your_azure_client_id"
    export AZURE_CLIENT_SECRET="your_azure_client_secret"
    
  2. Enable AHDS in the anonymizer:

    anonymizer = PresidioAnonymizer(
        permissions_provider=permissions_provider,
        encrypt_key="your_16_char_key!",
        enable_ahds=True,
    )
    

SQL Database Authorizer

The PlainIDSQLAuthorizerClient dynamically modifies SQL queries based on authorization Policies, enforcing Row-Level Security and Column-Level Security at query time.

Note: This component supports only a single identity per request.

Authentication
The client supports two authentication modes:

  • Client credentials provide client_id and client_secret at construction time.
  • JWT token provides an auth_token per request. The Bearer prefix is added automatically if missing.

To use the SQL Authorizer:

  1. Initialize the client:

    from core_plainid.clients.plainid_sql_authorizer_client import PlainIDSQLAuthorizerClient
    from core_plainid.models.request.sql_authorizer_request import (
        SQLAuthorizerRequest,
        SQLAuthorizerFlags,
        PoliciesJoinOperation,
    )
    
    sql_authorizer = PlainIDSQLAuthorizerClient(
        base_url="https://your-sql-authz.plainid.cloud",
        client_id="your_client_id",
        client_secret="your_client_secret",
    )
    
  2. Create the request:

    request = SQLAuthorizerRequest(
        sql="SELECT * FROM accounts WHERE country = 'US'",
        entity_id="your_entity_id",
        entity_type_id="your_entity_type",
        flags=SQLAuthorizerFlags(
            empty_rls_treat_as_denied=True,
            empty_cls_treat_as_permitted=True,
            expand_star_column=True,
            policies_join_operation=PoliciesJoinOperation.OR,
        ),
    )
    
  3. Execute authorization:

    response = sql_authorizer.authorize_sql(request)
    print(response.sql)
    print(response.was_modified)
    
  4. Optionally, use JWT authentication per request:

    sql_authorizer = PlainIDSQLAuthorizerClient(
        base_url="https://your-sql-authz.plainid.cloud",
        client_id="your_client_id",
    )
    
    response = sql_authorizer.authorize_sql(request, auth_token="your_jwt_token")
    

© 2026 PlainID LTD. All rights reserved.