Using Veza APIs to add custom data and identity providers to the Veza Entity Catalog
The Open Authorization API (OAA) is used to publish information about identities, authorization, and resources to the Veza Access Graph, making custom-built or otherwise-unsupported applications available for search, workflows, and monitoring. A typical motivation for using OAA is the need to integrate with enterprise applications that don't have an official Veza integration, such as a custom identity broker or source control management system.
Each built-in Veza integration has a fixed schema unique to the provider. Integrations created with OAA can use either the Custom Identity Provider or Custom Application schema, both of which are flexible enough to model a wide range of data and identity sources.
Several community connectors built on OAA are already available for immediate use, enabling easy connection to SaaS providers such as GitHub, SalesForce, and others. You can also develop a custom connector using the Veza-provided Python SDK oaaclient or your language of choice.
To integrate a custom application using OAA, you will typically rely on an API (or another method) to list identities and resources within the host system, and retrieve entity and authorization metadata such as permissions, roles, and activity status. You must then structure this information according to one of the supported OAA templates. Once you have assembled the JSON payload, you can publish it using REST API calls or the oaaclient CLI.
Use Cases
Customers have utilized the Open Authorization API to accommodate many different scenarios. A few use cases include:
Using the GitHub connector to ensure that repositories holding critical source code are correctly configured.
Collecting infrastructure-as-a-code (IaC) configurations to audit which users can log in to important hosts.
Auditing the permissions granted by an internal developer portal.
Automating Lifecycle Management and Access Requests for custom applications that expose SCIM endpoints, enabling provisioning workflows for home-grown systems (see Custom Application with SCIM).
First Steps
Getting Started introduces important OAA workflows, the custom application template, and common API operations. When planning your connector, you may also want to review the Best Practices for more information about naming considerations, mapping custom applications to the OAA schema, and other topics.
Veza provides a Python SDK and working example connectors, which you can download using GitHub or pip install oaaclient. Examples and documentation are included with the source code.
Alternatively, you can parse a data source, compile the JSON payload, and publish it using your language of choice. For detailed documentation on the OAA schema and API operations, see:
API reference - operations for creating, updating, and deleting OAA providers and data sources
Getting Started
Overview and first steps for building an Open Authorization API connector
A built-in Veza integration or OAA connector might not be available for an application or identity provider you want to connect to Veza. However, you can still use the Open Authorization API to integrate compatible applications and identity providers with the rest of your Veza data catalog.
The adaptable OAA schema can model a wide range of authorization models and resource hierarchies, and you will typically have several options for sourcing authorization metadata from the application provider. To integrate a custom application with Veza, you will need to be able to:
using an API, command line, or another method to collect the needed authorization-related data.
Depending on the application, this could include data resources and sub-resources as well as local users, groups, roles, permissions, and correlation to federated identities or external IDs.
Best Practices
Strategies and best practices for OAA connector development
See the included topics for more information about developing an Open Authorization API connector.
Choosing your development environment and deploying an OAA connector
The Open Authorization API enables developers to push metadata to the Veza Access Graph using a standard JSON schema. To automate this process, you will need a way to periodically query the data source you want to integrate, populate the schema, and publish the populated template payload to your Veza instance using API calls.
You can interact with the Veza API from your client or language of choice. OAA connectors can (and have) been developed in a variety of languages. The only requirements are the ability to:
query the source application (or , or another method) to collect identity, resource, and authorization metadata
Providers, Data Sources, Names and Types
Naming, typing, and searching for top OAA entities
Custom providers and data sources
Before uploading entity metadata for an OAA integration, you must create a custom provider and at least one data source under that provider. The provider represents the type of application (such as "Jira Server") and determines the template used for all data sources (e.g."dev", "prod")created under that provider.
The OAA payload is pushed to a specific data source and updates the existing data.
A display icon can be set for the provider, shown throughout the Veza UI to identify the integration and its entities.
Naming the provider and data source is an important step in integration creation. In general,
The provider name should be unique to the integration. Avoid common terms such as "application". Separating providers for systems with several instances such as "production" and "development" can be a good idea.
The provider or data source value should be unique to the integration and incorporate an identifier such as hostname or other instance ID. This ensures that multiple instances of the integration can be separated if necessary.
Do not user random or date values in provider or data source names. Each run of the connector should result in the same provider and data source name, based on discovered values or a configuration parameter.
Each OAA Template supports a concept of name and type. The type enables search for all instances of a specific entity. For example, the Application Type identifies application entities such as users, groups, roles, and resources. It will enable search for all entities in an application. Setting the application type to Widget will allow for search Widget Users, Widget Groups, and other entity types:
The app name appears when searching for individual entities, and, to differentiate more than one instances of the same system. For example two instances of an application "Widget - Production" and "Widget - Stagging".
Sourcing and Extracting Metadata
Strategies for extracting authorization, identity, and resource metadata
When planning an OAA connector, consider how you will gather the information you want to import into Veza. Refer to the application’s documentation to confirm you can obtain the required metadata from the host application.
Ideally, you will be able to list and collect metadata for:
User records
Group memberships
User roles and permissions
Resource names and metadata
For example, the Veza-GitHub connector utilizes the following endpoints (in addition to basic authentication and authorization APIs):
Web-based APIs are a common solution for SaaS apps, but not required for an OAA integration. Just because an endpoint exists does not mean that it returns useful information (some APIs are more designed for client automation than audits). Possible choices for sourcing metadata include:
From a database: Is data for a hosted app available in a database your connector can query?
File-based extraction: is the metadata available in source code or a configuration file, or an exportable report (such as CSV)?
Other options: does the provider have an SDK or CLI interface you can use to retrieve data?
If no machine-readable data is readily available, even screen scraping could be a solution. There are many creative options for extracting the information to populate the template, although an API will typically be the most usable option.
Naming and Identifying OAA Entities
Setting unique identifiers and human-readable names using OAA templates
Veza requires each entity to have a unique identifier, used within the template to reference entities (which groups a user is a member of) and for Veza to use to track and display the entity. This is true for both the Application and IdP templates
By default the templates use the name field for this purpose. However, names are not unique within some applications. In this case the templates offer an optional id as a unique identifier, allowing name to function as a non-unique display name.
Custom Application
Local User, Local Group and Local Role have an optional value id that can be provided for each entity that serves as the unique identifier.
To use id all Local Users, Local Groups and Local Roles must be defined with an ID. The name and id can be the same value as long it is unique for the entity type. For example a local role can have admin for both the name and id.
The
Using ids for mapping, instead of name is recommended in most cases, especially if any of the following are true:
Entity names aren't unique in the application (if two users can have the name "Joe Doe" but each have a unique user id such as email or login or the applications unique id).
The API references users, resources, and other entities by an ID instead of name. Using the same ID for the OAA payload will limit scenarios where you need to maintain a mapping of id to name in your connector.
For Custom Application to use id for Local Users, Groups and Roles all entities must use the id field. To use the id field for Resources all Resources and Sub-Resources must have an id
Resources and Sub-resource each can have an optional id value. When provided, the resource name does not need to be unique. To use id, all resources and sub-resources must be defined with a unique ID. The id value will be used to assign resource permissions in identity_to_permissions.
Custom IdP also supports a optional unique identifier value identity for Users and Groups. If not used, the entity name must be unique and will be the primary identifier.
Tagging with OAA
Both custom properties and can be used to add rich metadata and apply labeling strategies across entities in the Veza Access Graph. Both can be viewed by checking an entity's details, and are fully available when searching and filtering results.
Veza tags can be assigned to objects in an OAA payload. One typical use case for tagging within the OAA payload is assigning with Veza SYSTEM_resource_managers tags.
Tags are applied by providing a key and an optional value for each. A new tag will be created if a matching one doesn't already exist.
Due to superior integration with other Veza functionality and ease of updates, custom properties are recommended as the best approach for adding metadata to OAA entities, unless tagging is required as part of a larger campaign.
Cross Service IdP Connections
Mapping OAA objects to external and federated identities
In Veza, the Identity Provider (IdP) serves as the representation of the source of an identity (human or otherwise). That identity can have access to many applications, clouds and other data sources. By connecting OAA entities to source IdP identities, Veza can show all the access for that identity. This can also enable powerful correlation queries such as finding deactivated Okta Users with active application accounts.
Veza makes these connections based on the identity information provided in the OAA payload.
Veza Supports Mapping for the following Identity Providers:
Active Directory
Structures
Copyright 2023 Veza Technologies Inc.
Use of this source code is governed by the MIT license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
classCaseInsensitiveDict
Case Insensitive Key Dictionary
Dictionary like object with case insensitive keys for types that support .lower() such as strings.
Keys do not have to be strings, in the case where the key type does not support .lower() such as integers the value is used as is.
Example:from oaaclient.structures import CaseInsensitiveDict >>> x = CaseInsensitiveDict() >>> x["User"] = "value" >>> x.get("user") 'value' >>> "USER" in x True >>> print(x) {'user': 'value'} >>> x CaseInsensitiveDict({'user': 'value'})
Example Connectors
Open Authorization API usage examples
The official Veza connectors are useful references for understanding the decisions and strategies that come into play when building a custom Open Authorization API (OAA) integration.
Each connector is similar in basic function, yet adapts to the resource hierarchies and interfaces unique to the technology provider. Each uses the Python package to construct a payload, create a custom provider and data source, and publish the extracted metadata.
Veza provides working connectors and source code for:
GitHub
id
value becomes the key for referencing local users, groups and roles in the
identity_to_permissions
section of the payload and for referencing group memberships.
See the GitHub repository for setup instructions and the most recent releases. The repository also includes sample applications demonstrating basic oaaclient usage. You can also browse these examples in the User Guide.
For all Identity Providers, the IdP Unique ID and email attributes are used to match the source identity to an OAA principal. Some entity types have additional properties usable for identity mapping:
Active Directory
Account Name
Distinguished Name
Azure AD
Principal Name
On Premises SAM Account Name
Okta
User Login
The Application Template's Local User entity represents a user within the application. That Local User can map to an Identity Provider (IdP) by setting the identity value(s) in the Local Users identities array. Veza will use these identities to create an association between the IdP Identity and the Local User.
Setting external IdP Group identities is also supported on Local Groups. This should be used when there are no Local User records in the application that correlate to the external user identities. Veza will create a connection between the IdP Group and the Local Group, indicating that all IdP users from that group will have the access granted to the Local Group.
Unknown identities set on users will result in a warning that the identity can not be found. The OAA Local User will still be successfully created.
Note on Identity Mapping from the IdP: You can confirm these values by finding the corresponding entity in Veza search or the data catalog and checking the identities Idp Unique Id and other fields in the details view. Identities that cannot be resolved are returned as warnings when the application payload is pushed.
For applications that use Okta for SSO, you can also enrich local users with last login timestamps from Okta activity data. Set okta_app_id on the application object to enable this enrichment — Veza uses the same identities values to match local users to their Okta profiles. See Okta SSO last login enrichment.
OAA Identity Provider Users can be connected to other IdPs by using the source_identity property on the IdP users. For details see Source Identity Assignments
Veza will automatically correlate HRIS Employee records and IdP identities based on the HRIS employee's email property. The HRIS employee has an optional parameter for identity_id if the required value is different from the user's email.
Application Template
Identity Provider (IdP) Template
Human Resources Information System (HRIS) Template
assemble a dict or similar data structure and convert to JSON
make REST API calls to publish the payload
Veza provides a Python SDK oaaclient. This package provides functions for generating and submitting the JSON payload. The Veza developed community connectors use this toolkit, along with all integrations built by active customer developers.
You can run OAAClient as a manual CLI tool for trial purposes, but should automate any long-running OAA implementation. A DevOps or SecOps team is typically responsible for establishing continuous integration of a Veza connector.
Customers are responsible for running their own connectors. The frequency your app must run will depend on use case, ranging from daily to hourly. Veza typically refreshes metadata for built-in integrations on an hourly basis. However, you can decide to publish OAA payloads on any schedule.
At a minimum, a deployed OAA connector should be able to:
Parse the data source and push an updated payload on a schedule
Securely handle secrets such as API keys
Teams should follow their preferred processes and use familiar or existing platforms. Some options include:
AWS Lambda function
Docker/k8s-based container
cron task
GitHub action
Veza expects the default push to contain a full payload. This will overwrite all information in the updated data source.
During development, it is usually most efficient to design your parser for a full discovery. It will be easiest to design the connector to assemble and push the full payload, and use the same code to publish updates.
OAA does support incremental update as an optional behavior–if your custom data source or identity provider provides a way to get individual changes over time, you could design your connector to parse only new or changed entities, and push updates individually (perhaps in response to detected changes). However, this approach will be more complicated. A full parse-and-push will be more efficient, unless there's a method to query the provider for differences since the last push.
To use incremental updates:
Set the is_incremental flag in the payload to true
Add an add, modify or delete operation to all entities
Choosing between full push and incremental updates
- orgs/{org_name} - Get Organization information
- orgs/{org_name}/members - List members for an organization
- orgs/{org_name}/teams - List teams for an organization
- orgs/{org_name}/teams/{team}/members - List members for a given team
- orgs/{org_name}/repos - List organization repositories
- repos/{org_name}/{repo}/teams - List Team permissions for repository
- repos/{org_name}/{repo}/collaborators?affiliation=direct - List team members with direct permissions
__init__(data=None, **kwargs) → None
method__init__
Note that while tags can be removed using the Tags API, tags applied within the template are persistent: an existing tag won't be deleted when pushing a payload with a new tag or empty tag.
After the initial metadata push (which must contain the full payload), you can modify, add, or remove the domain, users, and groups without resubmitting other entities. An incremental update is enabled by setting "incremental_change": true in the json_data push payload, and specifying the update operation for each entity to change.
The operation field indicates the change to make. Valid operations are:
"add", "modify", "delete" to create, change, or remove an entity.
"add_tag", "delete_tag" to update a tag without altering the entity.
Generate a payload describing the users, resources, and permissions, according to a standard JSON schema.
The payload can describe any number of application resources and sub-resources, along with information about identities, groups, permissions, and relationships to other graph entities.
Publish the payload for processing using Veza APIs (after registering a new custom provider and data source if they don't already exist).
The process of retrieving user records, along with lists of resources, group and permissions information, will be unique to each technology and OAA connector. You may also need to consider how to adapt the application's implementation of roles, federated identities, and resource hierarchies to fit the OAA template.
Most programming languages offer ways to populate and manipulate a JSON schema. You can also use the Python SDK for prebuilt functions:
Below is an example of a populated application template. It demonstrates the basic principles of modeling local user permissions on application resources. For more details on all the available entities and properties see the full Custom Application reference:
In addition to built-in properties such as department or last_login_at, most entities can have additional user-defined custom properties. Using custom properties enables integrations to capture application-specific data that can be useful for reporting and provide additional insight during investigations.
You can also apply Veza tags to entities within the payload.
You will use the Veza REST API to create, delete, and update a custom data source under v1/providers/custom/{provider_id}/{datasource_id}. Before you can push an OAA payload, you will need to:
Add a custom Provider to represent the generic application provider (such as "GitHub"), and set the name and template (application or IdP).
Bind a custom Data Source to the new custom Provider (such as "GitHub Organization") to activate it in the data pipeline. The data source will be the destination for future pushes and updates, and should usually represent the top-level instance of the modeled application.
Push the payload to populate the Veza Access Graph with new entities and metadata for the custom data source.
Identity Providers and HR Information Systems can be used as identity sources in Lifecycle Management Policies by marking the Provider as a provisioning source. Identities from these sources will be available when configuring LCM Policies.
Applications integrated via OAA can be managed through LCM Workflows via one of two methods:
SCIM - If the application supports SCIM provisioning, you can configure Veza to manage application access directly through SCIM. See Custom Application with SCIM (OAA) for more information.
REST - For applications that support REST API calls to manage access, Send REST Request actions can be created in LCM Workflows to manage access.
To update the data, push a new payload to the original provider ID and data source ID. By default, Veza will overwrite any existing data. The previous state will be available in the graph history, based on Veza's snapshot retention schedule.
Optionally, subsequent changes can be incremental updates, where the payload only contains entities to modify, add, or remove.
The module oaaclient.client can be used to instantiate a Veza connection and manage OAA providers:
Alternatively, you can make the required REST API calls using the client of your choice or by invoking oaaclient as a command-line tool.
Typically, the provider should represent the provider name (such as "CustomSCM"). Any payload pushes will target the data source ("CustomSCMInstance") under the custom provider. The pushed payload can include many nested resources (such as multiple repositories). The template also supports resources with a variety of different types within a single application.
The data source and provider name are primarily for internal use. The application_type specified in the template is used when viewing and searching the custom app from the Veza UI.
Veza enforces strict validation of the json_data field containing the OAA payload. Three checks are performed:
All required fields must be present.
String fields must be valid UTF-8 strings, no larger than 512 characters for names and IDs, and 4,096 for all other string values.
The maximum single payload size is 100MB. If you need to compress the payload, you can enable the option when creating the OAA data source. You can use multi-part upload for large payloads.
A successful response may include warnings for issues that didn't prevent the processing of OAA data but should still be investigated. When mapping identities to an external id, a warning will be raised if a matching IdP group name or user principal name can't be found.
To validate an AzureAD or other type of user, go to the Access Graph, search for the node of interest, select Show Details, and confirm the principal name is correct.
To validate the identifier for a group, find the node for the group and verify the name is as expected.
Veza will always return the warnings key in the response. If a response is empty, there are no warnings.
For all Veza APIs, error messages include an error code (in standard gRPC error, such as 3 for Invalid Argument) and a descriptive error message. The error message consists of two parts:
from oaaclient.client import OAAClient
from oaaclient.templates import CustomApplication, OAAPermission
# creates a connection class to communicate with Veza
veza_con = OAAClient(url=veza_url, token=veza_api_key)
# creates a new Custom Application model
custom_app = CustomApplication(name="Sample App", application_type="sample")
You can use the to simplify the process of populating the payload, connecting to Veza, and managing OAA providers and data sources.
1. Extracting metadata from the source application
Typically, the required information will be available from an API, but you should consult the provider's documentation to ensure the information is available, and consider an alternative method for sourcing the data, if not.
2. Generating a sample payload
Custom Application Payload
Custom Properties
3. Creating and Updating Custom Providers and Data Sources
Enabling for Life Cycle Management (optional)
Identity Providers and HR Information Systems
Applications
Updates
You can use GET to retrieve any existing provider and data source IDs. For more information about managing Providers and Data Sources see .
Using oaaclient
Notes
Troubleshooting
Warnings
Errors
OAA Python SDK
Building blocks for your custom OAA integration
The `oaaclient` package provides data models, methods and a command-line interface for using the . You can use it to populate OAA templates including as Application, IdP, and HRIS, pushing OAA data to Veza and even as a general Veza API client.
The oaaclient SDK includes the following components:
oaaclient.client: Veza API communication (data provider management, payload push, etc.). Requires an API key for authentication.
For example usage, please see modules and the samples directory.
Sample Workflow
Create the Veza API connection and a new custom application:
Once the CustomApplication class is instantiated, you can use the public methods to populate the new app with local users, groups, resources, and permissions metadata:
Once all identities, permissions and resources are added to the CustomApplication object, the client connection handles the final push to Veza:
The OAAClient class handles API connections to Veza. If there are errors connecting or the API returns errors OAAClient will raise an OAAClientError exception. If the payload doesn't conform to the template requirements the OAAClientError.details will contain a list of any issues encountered.
Since any given source application or service will have different methods for retrieving entities, authorization, and other required metadata, each OAA connector will be slightly different. You should consult the API documentation for your application when considering how you will source the information, and refer to existing Veza-supported OAA connectors for real-world examples.
Connector source code and oaaclientmodules are thoroughly annotated, for reference when building your own integrations.
For additional information about developing a custom OAA integration, please see Open Authorization API section of the User Guide.
oaaclient can be downloaded from GitHub, or installed with pip3 install oaaclient.
from oaaclient.client import OAAClient
from oaaclient.templates import CustomApplication, OAAPermission
# creates a connection class to communicate with Veza
veza_con = OAAClient(url=veza_url, token=veza_api_key)
# creates a new Custom Application model
custom_app = CustomApplication(name="Sample App", application_type="sample")
# define a permission
custom_app.add_custom_permission("owner", [OAAPermission.DataRead, OAAPermission.DataWrite])
# create a local user
jsmith = custom_app.add_local_user(unique_id="jsmith", name="Jane Smith", identities=["jane@example.com"])
# create a resource
resource1 = custom_app.add_resource(name="Resource 1", resource_type="Thing")
# assign a user to a resource
jsmith.add_permission(permission="owner", resources=[resource1])
try:
response = veza_con.push_application(provider_name=provider_name,
data_source_name=data_source_name,
application_object=custom_app,
)
if response.get("warnings"):
print("Push succeeded with warnings:")
for w in response["warnings"]:
print(w)
except OAAClientError as e:
print(f"Error: {e.error}: {e.message} ({e.status_code})", file=sys.stderr)
if hasattr(e, "details"):
for d in e.details:
print(d, file=sys.stderr)
Utils
oaaclient utility functions.
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
helper functions commonly used by OAA integrations
Helper function for logging errors when loading parameters
Helper function used to create consistent messages in connectors when required parameters can be set at command line or as environment variables.
Message can include information on parameter and/or environment variable but must provide one.
Args:
log (object): logging facility object to log to
arg (str, optional): Command line option for parameter such as --veza-url. Defaults to None.
env
Raises:
Exception: if neither arg or env are supplied
Load JSON from file
Args:
json_path (str): path to JSON file on disk
Raises:
Exception: Unable to process JSON
Exception: Error reading JSON file
Returns:
dict: JSON decoded to dictionary
read an icon file to a base64 encoded string
Args:
icon_path (str): Path to icon file on disk
Returns:
str: base64 encoding of file
Creates or updates a Veza report from a dictionary
Creates a report and containing queries from a dictionary definition. Function will create any queries it does not find based on name. If a query with the same name already exists the existing query will be added to the report.
If a report already exists with the same name any missing queries will be added to the report.
report_definition must be a dictionary with name for the report and queries list of Veza query definitions:
{"name": "My Report", "queries": [{..},{...}]}
Args:
veza_con (OAAClient): OAAClient connection to make Veza API calls
report_definition (dict): Report definition
Raises:
ValueError: Missing name or queries key
Returns:
dict: API response from Report creation or update
Helper function to truncate strings
Helper function to truncate strings to conform to maximum length requirements for templates.
Returns a string that is the first N bytes of the source string
Args:
source_str (str): Source string to truncate
length (int, optional): Length to shorten to. Defaults to 256.
Returns:
str: truncated string
OAA Templates
JSON schemas for describing custom applications, identity providers, principals, and secret stores
OAA utilizes templates (JSON schema) for structuring authorization and identity metadata, combined with a REST API to register, update and manage the data. Once uploaded, Veza processes the template payload and incorporates the entities and permissions into the Authorization Metadata Graph.
Choosing the appropriate template is the first step in creating a new integration with OAA. The template provides a schema for describing the identities, resources, and authorization relationships local to the OAA data source.
Custom Application
For most applications, SaaS Apps and systems the Custom Application Template provides a generic and flexible model to capture authorization data for users and groups to the system and its resources.
A custom application is structured with the following main entities:
Application
Resource
Sub-resource
Sub-resource
Local Permissions
Identity-to-permissions binding
Intended for modeling sources of users, group, and federated identity metadata, the can be used to enumerate users and groups that access other external applications and resources, similar to built-in connectors for Okta and AzureAD. These users and groups typically represent the top-level corporate identities within an organization.
A Custom Identity Provider can have the following entities:
Domains
Users
Groups
The Custom IdP template also includes the option to define AWS Roles that are assumable by users and groups and can work with Access Review Workflows to auto-assign resource managers.
For modeling sources of identities (users, groups, and tenants) that connect to other OAA data sources on the same provider, the provides a lightweight identity model. Unlike the Custom IdP, which models a full identity provider with domains, the Principal template is designed to feed users and groups into Custom Application or other templates on the same provider.
A Custom Principal is structured with:
Tenant
Users
Groups
For modeling secret and credential management systems, the captures vaults, entries, permissions, and identity access mappings. Use this template to connect custom or self-hosted credential management systems that are not covered by a native Veza integration.
A Secret Store is structured with:
Secret Store
Permissions
Vaults
The adds custom property values to entities that already exist in the Veza authorization graph from other integrations. Use this template to attach supplemental metadata (such as compliance status, cost center, or internal identifiers) to entities discovered by native integrations.
Enriched entities (entity references with property values)
OAA .NET SDK
Building blocks for your custom OAA integration
You can download the Veza C# SDK from .
The Veza package provides data models, methods, and helpers for using the Open Authorization API. It provides helper methods to populate OAA templates for custom applications, filesystems, HRIS systems, and identity providers, and push the payloads to Veza. The SDK can also be used as a generic Veza API client.
The Veza SDK includes the following core components:
Veza.Sdk.Client: A base API client for making REST calls to a Veza tenant
Veza.OAA.Client: An OAA API client for interacting with integration providers, data sources, and pushing OAA metadata to a Veza tenant.
For example usage, see .
Sample Workflow
Create the Veza API connection and a new custom application:
Once the CustomApplication class is instantiated, you can use its public methods to populate the new app with users, groups, resources, and permissions metadata:
Once all identities, permissions, and resources are added to the CustomApplication object, use the client connection to push the data to Veza:
See the directory for full examples.
The Veza.OAA namespace provides exception types for common errors that occur when interacting with Veza APIs.
An OAAClientException is raised if there are errors interacting with the Veza API.
A TemplateException is raised if a provided payload does not conform to the template requirements. The inner exception will contain details about the exact issues encountered.
Each OAA connector will be slightly different, depending on the methods each source application or service provides for retrieving entities, authorization, and other required metadata. You should consult the API documentation for your application when considering how you will source the information, and refer to existing Veza-supported OAA connectors for real-world examples.
OAA connector source code and Veza components are thoroughly annotated for reference when building your own integrations.
For additional information about developing a custom OAA integration, please see section of the User Guide.
Modeling Users, Permissions, and Roles
Using local roles, local users, and canonical permissions to describe access
Using local_users to describe local and federated identities and service accounts
Most applications will have some concept of a “local user” that can have varying permissions to data and metadata. Most modern cloud applications offer some form of single sign-on. In some cases, local user accounts correspond to an external federated identity, or even only exist ephemerally.
The Open Authorization API is able to represent local users, local groups, and external identities. An external identity could be an user connecting directly to a resource through Single Sign On, or an SSO group. A local user could be a just-in-time account created when an IdP user first connects.
You should represent system users using local_user objects, even for apps that are SSO-enabled. The local user object is able to contain useful attributes such as activity status and timestamps, enabling rich search on those entities. A local user can also reference a federated identity, creating graph relationships between IdP entities and local users and groups when the payload is parsed. Veza handles these cross service connections similarly to built-in integrations such as Snowflake.
The OAA template supports direct permissions from IdP users to resources. However, including a local user entity in your OAA mapping strategy is still recommended when possible.
Users can also be grouped and assigned permissions with .
Veza understands an identity's level access to a resource in terms of raw system permissions in the provider's terms (such as AWS IAM s3:DeleteBucket), and canonical permissions (such asDATA DELETE). This allows Veza to answer the questions: "Who has MERGE permission on production repositories?" and "who can read data from any resource flagged for PII compliance?".
OAA requires you to map each granular application permission (like "view ticket" or "close ticket") to its corresponding C/R/U/D permission. This enables search and audit of effective and configured access.
Raw ("System") Permission
Canonical Permission
SaaS apps tend to be role-based, and organizations that follow security best practices will typically restrict the assignment of permissions directly to users. Following standard RBAC concepts, an OAA role represents a collection of permissions which can be scoped to individual resources or specific resource types.
If permissions granted by a role only apply to specific resource types or sub-resources, create the custom permissions individually and add them to the role in a list:
Under the custom application OAA schema, users can have direct permissions and role-based permissions to resources. Modeling these role-based permission assignments will enable searches such as "show all users with the maintain role in GitHub."
Note that “roles” in some apps actually function more like groups (lists of users), in which case they should be modeled using local_groups.
For payloads where permissions apply for the entire application, you can create a single custom permission for a role, containing all the associated canonical permissions:
As demonstrated in the OAA PagerDuty connector, this is a quick way to model authorization structures such as:
Custom Application Role
Custom App Permission
Canonical Permission
Multipart Upload
Upload large OAA payloads using chunked multipart requests
For OAA payloads that exceed 100 MB after compression, you can use multipart upload to split the payload into smaller chunks and upload them sequentially. The Veza platform assembles the chunks server-side before processing.
Multipart upload is useful when:
The payload is too large for a single HTTP request
Network reliability is a concern for large transfers
Incremental Updates
Modifying custom providers using a partial OAA payload
After the initial metadata push, you can modify, add, or remove OAA entities, permissions, and properties without needing to submit the full payload each time. A first push can't be an incremental update.
An incremental update is specified by setting "incremental_change": true in the json_data push payload and adding an update operation for each entity to change. Most payload objects support incremental update operations:
Custom Application
Custom Identity Provider
Using OAA Templates
How to use the Application Template to represent various types of application
The OAA Application template allows for representing the basic elements of an application and is flexible to allow for multiple different patterns.
The custom application template provides a framework for describing:
The operation field indicates the change to make. Valid operations are:
"add", "modify", "delete" to create, change, or remove an entity.
"add_resource", "delete_resource" to modify resources in applications, permissions and role scopes.
"add_tag", "delete_tag" to update a tag without altering the entity.
The object to update must contain an ID (name or identity) and the properties to create or modify. An error response will provide more details if an operation is invalid or unavailable.
When modifying dynamic properties, all five properties must be present.
add and modify can't be used on the same object. For example, to update both tags and properties on an entity, use:
The following JSON example for custom application includes a range of update operations. Note that when modifying tags, only include the identity and tags (no other properties such as manager_id can be present).
When developing your OAA integration, whether to implement incremental updates depends on your use case. If you don't have a convenient way to track provider-side changes, it is typically easier to do a full extraction and metadata push, to not miss changes within the app or IdP.
You need to monitor upload progress for very large data sources
Start the upload by sending a start request — the server creates an upload session and returns an upload_id.
Upload chunks sequentially, each base64-encoding a raw slice of the payload. Include the upload_id from step 1 and an incrementing sequence_number.
Finalize by sending a complete request with the upload_id and total sequence_count.
Each chunk must be base64-encoded from raw bytes before sending. The server decodes and reassembles chunks in sequence order when the complete operation is received.
Field
Type
Description
operation
string
Must be start
The response returns an upload_id (UUID string) to use in all subsequent requests for this upload session.
Field
Type
Description
operation
string
Must be upload
upload_id
string
UUID returned by the start response
Send a separate POST to the same endpoint after all chunks are uploaded:
Field
Type
Description
operation
string
Must be complete
upload_id
string
UUID from the start response
The oaaclient Python SDK handles multipart upload automatically when enabled:
When enable_multipart is set to True, the SDK automatically switches to multipart for payloads exceeding 50 MB (uncompressed) and:
Splits the payload into chunks and base64-encodes each one individually
Starts an upload session and tracks the upload_id
Uploads each chunk sequentially with the correct sequence_number
Sends the completion operation to trigger server-side assembly
All chunks for a given upload_id must be uploaded before sending the completion operation.
You can re-upload a chunk with the same sequence_number and upload_id if needed — the last upload for a given sequence number is used. All chunks must be present before the completion operation is sent.
Chunk order is determined by sequence_number, not upload order.
Overview
POST /api/v1/providers/custom/{id}/datasources/{data_source_id}:parts
PAYLOAD_FILE="large_payload.json"
CHUNK_SIZE=10485760 # 10 MB per chunk
# 1. Start the upload session
RESPONSE=$(curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"operation":"start"}')
UPLOAD_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['upload_id'])")
# 2. Split into raw chunks and upload each
SEQUENCE=0
split -b $CHUNK_SIZE "$PAYLOAD_FILE" /tmp/oaa_chunk_
for CHUNK_FILE in $(ls /tmp/oaa_chunk_* | sort); do
SEQUENCE=$((SEQUENCE + 1))
ENCODED=$(base64 -w 0 < "$CHUNK_FILE") # use -b 0 on macOS
curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"operation\": \"upload\",
\"upload_id\": \"$UPLOAD_ID\",
\"sequence_number\": $SEQUENCE,
\"data\": \"$ENCODED\"
}"
done
# 3. Finalize the upload
curl -s -X POST "https://$VEZA_URL/api/v1/providers/custom/$PROVIDER_ID/datasources/$DATASOURCE_ID:parts" \
-H "authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"operation\": \"complete\",
\"upload_id\": \"$UPLOAD_ID\",
\"sequence_count\": $SEQUENCE
}"
rm /tmp/oaa_chunk_*
from oaaclient.client import OAAClient
client = OAAClient(url=veza_url, token=veza_api_key)
client.enable_multipart = True
# Push as usual - the SDK automatically chunks large payloads
client.push_application(provider_name, data_source_name, application_object=app)
The standard :push endpoint supports payloads up to 100 MB (compressed or uncompressed). Use multipart upload when your payload approaches or exceeds this limit, or when you need more reliable transfer for large payloads.
The Application itself is the first entity as part of the Application submission. The application has a name and a type. The name can be specific such as "West Production" and the type is typically the vendor, technology, or product such as "GitLab". Veza will group the rest of the entities by the application type such as "GitLab Users" across all instances of an application type, however, entities will only be directly associated with the application they are submitted with. Applications additionally can have custom properties assigned to further enrich the data. This can be especially useful to distinguish between multiple instances of an application type.
Local Users
Users example
The Local User object represents the local user of the application. It can store application-specific information such as the identifier, name, active status, last login time, and custom properties specific to the application. An external Identity can be associated with the user, enabling Veza to connect the source Identity Provider (IdP). This creates a connection in Access Graph between the application user and a source identity such as Okta or Active Directory. Users can be added to groups, or have roles and permissions directly assigned.
Local Groups
Local Groups represent a collection of users. Groups can store additional metadata about the group to support search and filters. Groups can also contain other groups, to model applications that support nested groups. Groups can have role and permission assignments in the application.
Local Roles
Local Roles represent a collection of permissions within an application. When a user or group is assigned a role, that user or group is assigned all the permissions from the role. Like other entities, roles can contain additional properties to enrich the metadata of the role, such as description or application-specific attributes.
Permissions
OAA allows for expressing the permissions of the application in its own terms. In the Application Template, permissions are defined by application-specific terms such as "Close Ticket" or "Approve User". These permissions will also allow for setting corresponding Veza Canonical Permissions such as "Data Read", "Data Write", or "Metadata Read". This enables search and filters across permissions using CRUD-like equivalents.
Resources can be used to model components within applications that users can be assigned roles or permissions on. For example, an OAA resource may be used to model a Project in an application like Jira. Users can have different roles in different projects, by assigning the correct users or groups their respective roles on the resources. Each resource has a Type which Veza uses when displaying and searching the resources for an application. Applications can have multiple types of Resources. Like other entities, resources can have properties containing additional resource metadata.
Below are some examples of how applications may be modeled in OAA. These examples have all been implemented using the Application template.
PagerDuty is an example of an application where users can have roles at the application level (global roles) but also within the PageDuty Teams that a user is a member of. Understanding which Users are part of which Teams and what level of access they have in those Teams is important for reviewing access in an application like PagerDuty. The OAA Application template can be used to model this type of application using the following mappings.
PagerDuty Entity
OAA Application
Notes
User
Local User
Team
Local Group
With this model, Veza can show the levels of access users have within the overall Application and their individual Teams. In this example, we can see the User Gary Ward has the Role "Restricted Access" in the PagerDuty Application, and the "Observer" Role in the "Support" Team Resource.
PagerDuty App
Python Code for the PagerDuty connector can be referenced on the Veza GitHub
GitLab is a good example of a more complex application that can be modeled using the Veza OAA Application Template. By correctly modeling the applications, Veza can show which users have access to GitLab Groups and Projects to show details beyond just "who has access to GitLab?"
GitLab
OAA Application
User
Local User
Group
Resource
Project
Sub Resource
GitLab App
Each GitLab User is represented with the Application Local User. GitLab assigns each user a unique ID number to each user, using this as the ID for the Local User makes it easier when associating groups and roles to Projects later. The Local User also allows for setting properties to represent the user's state such as is_active or last_login_at, custom properties to represent GitLab-specific properties can also be utilized like if the user is licensed or not. The identity for the Local User is set to enable OAA connection to source Identity Providers configured in Veza.
A GitLab Group represents both a collection of Users, a collection of Projects, and possibly other sub-groups. This is a good example of where some mapping needs to be done to represent GitLab using the Application Template. Since GitLab Users have a specific role in the GitLab Group, it is correct to represent the GitLab Group as an OAA Resource. Members are assigned an OAA Local Role to the Resource that represents the GitLab Group, denoting their level of access (Owner, Developer, Guest, and so on). Veza can return all the members of a GitLab Group by querying for the relation between the OAA User and the OAA Resource. Additionally, the role within the GitLab Group is preserved by the OAA Role.
GitLab Roles are assigned to users or Groups as part of a Group or Project. GitLab is an example of an application with fixed roles where the roles and behaviors are coded directly into the application. For the OAA Application Template, the corresponding Local Roles are also coded directly into the connector by reviewing the on available roles and the permissions associated with the roles. It is not always necessary to capture every Permission as part of the Local Role. Which permissions are important and how much detail is needed will be determined by the queries you intend to run, and the scope of Access Reviews that will be conducted in Veza.
GitLab Projects are also represented as an OAA Sub-Resource with the type set to Project. The Project Sub-Resource is added to the corresponding Group resource. Local User and Local Groups can be assigned roles on the project based on their direct assignments. In the case of GitLab, permissions can be inherited from above. This is an optional behavior for permissions, which can be set to automatically apply to sub-resources, or only apply directly to the assigned resources. Additionally, permissions can be set to apply to certain types of resources so that roles can be used across resources and only the correct permissions will be applied.
Python Code for the GitLab connector can be referenced on the Veza GitHub
Examples
PagerDuty
GitLab
oaaclient modules
Modules
client: Classes for calling Veza APIs and managing OAA providers and data sources.
templates: Classes for constructing an OAA JSON payload (Custom "Application" or "IdP").
: Returns a list of unique strings from input list case insensitive
Okta SSO Last Login Enrichment
Enrich OAA custom application users with SSO last login timestamps from Okta
Veza can enrich users with SSO last login timestamps by correlating Okta sign-in activity with your application's local users. When enabled, each local user in the Veza graph gains a sso_last_login_at property showing the last time that user accessed the application through Okta SSO.
This is useful for identifying dormant accounts, auditing access patterns, and supporting access reviews.
You specify the Okta Application ID (okta_app_id) for your custom application.
OAA Entity Owners
Setting Entity Owners in OAA Payloads
OAA supports setting on OAA Entities as part of the submission for some templates. This enables a single operation to submit the OAA Entity and its owner.
Entity Owners enable automated assignment and accountability in access management and other workflows:
Owners can be used by Access Workflows for
Assigning owners for entities that represent non-human identities enables visibility into those users on the Non-Human Identities (NHI) overview page.
OAA Operations
API calls for managing and updating custom data sources
Use these REST API calls to manage and update custom providers and data sources with .
Creates a custom provider and returns the provider ID.
Lists all configured custom providers.
Returns details for an individual custom provider.
Delete a custom provider by ID.
Return all data sources for a Custom Provider ID.
You can constrain large responses by adding a filter to the request query string. Include the operator (eq), and value, for example:
sequence_number
integer
Sequence number for this chunk, starting from 1. Maximum 99 chunks per upload.
Veza matches your OAA local users to Okta users using a configurable matching property (set via the Veza API in Step 2).
On each data push, Veza looks up Okta SSO activity for your application and writes the last login timestamp to matching local user nodes.
Enrichment runs in the OAA service after data submission. If Okta activity data is unavailable, the push completes normally without SSO timestamps — no data is lost.
An active Okta integration in Veza with audit logs enabled. Audit log data is the source for sso_last_login_at timestamps.
A custom application (OAA) integration, using either API push or CSV upload.
Your OAA local users must have identities values that match a property on your Okta user profiles (such as email address or a custom attribute).
Contact your Veza representative or support team and request:
Enable the INTEG_OAA_SSO_LAST_LOGIN feature flag on our tenant.
This flag is Veza-administered and cannot be self-enabled.
Configure which Okta user property Veza uses to correlate Okta users with your application's local users. You can set this yourself using the Veza API.
The string you pass as value specifies which OktaUser attribute to use for identity mapping. The attribute value on each Okta user must match the identities field on the linked OAA local users.
For example, if local users have identities: ["jane.doe@company.com"] and OktaUser nodes have login: "jane.doe@company.com", use login.
Custom attributes (e.g., customprop_employee_id) are also supported.
To set the property, send a PUT request with an API key that has the admin or system_monitoring role:
Replace <okta_user_property_name> with the OktaUser property to match on (e.g., login, email, or a custom attribute such as customprop_idx_uid).
To verify the current value:
Look for the okta_sso_user_matching_property key in the response.
Locate the Okta Application ID (0oa…) for the application you want to enrich:
Log in to your Okta Admin Console.
Navigate to Applications > Applications.
Select the application.
Copy the application ID from the URL (format: 0oaXXXXXXXXXXXXXXXX).
The method depends on how you push data to Veza.
Add the okta_app_id field to your application payload at the application level:
okta_app_id (application level): Your Okta Application ID.
identities (user level): One or more identity strings matched against the configured Okta user property.
Navigate to Integrations > Custom Application (CSV).
Enter your Okta Application ID in the Okta App ID field in the application configuration form.
Upload your CSV as usual, ensuring users have identity values that match their Okta profiles.
After pushing data, verify enrichment is working:
Open Query Builder in Veza.
Query for your custom application's local users.
Check the sso_last_login_at column on user nodes.
Users whose identities matched an Okta user with SSO activity for your application will have a sso_last_login_at timestamp. Users without a match (such as service accounts or users not in Okta) will not have this property — this is expected.
Matching is case-insensitive.Jane.Doe@company.com and jane.doe@company.com are treated as the same identity.
First match wins. If a user has multiple identities, the first one that matches an Okta user is used.
Enrichment is non-blocking. If Okta data is unavailable, the push completes without SSO timestamps. No data is lost.
Timestamps reflect Okta access pattern data. The sso_last_login_at value comes from Okta's recorded activity for your specific application.
Issue
Possible cause
Resolution
sso_last_login_at not appearing on any users
Feature flag not enabled
Contact Veza support to verify INTEG_OAA_SSO_LAST_LOGIN is enabled
sso_last_login_at not appearing on any users
Matching property not configured
Use the API in Step 2 to set okta_sso_user_matching_property, or contact Veza support to verify it is set
Early Access: This feature is not enabled by default. Contact your Veza support team to enable the INTEG_OAA_SSO_LAST_LOGIN flag for your tenant.
/api/private/ endpoints are not part of the public API contract and may change between releases.
Step 3: Find your Okta application ID
Step 4: Add the Okta app ID to your custom application
API push (JSON)
CSV upload
The Okta App ID field in the CSV configuration form is only visible when the INTEG_OAA_SSO_LAST_LOGIN feature flag is enabled on your tenant.
Verifying enrichment
Behavior notes
Troubleshooting
If Veza assigns a Risk Score to the entity, an owner assignment can help identify the user best able to remediate the risk.
Currently supported OAA Templates and entity types for Entity Owners:
Application Template:
Application (owners can be set at the application level itself)
Users
Groups
Roles
Resources
Access Credentials
Requirements:
Entity Owners must be a User entity type from an Identity Provider integration enabled in Veza. If a Global Identity provider is configured, the owner must be a user entity from the Global IDP.
Identity-provider application entities (such as OktaApp and AzureADEnterpriseApplication) also support entity owners, but owners are not set in the OAA payload. See Supported entity types for owner assignment for the full list and assignment methods.
Use the owners property on supported entities to specify entity owners as an array of objects.
Attribute
Value
external_id
The ID of the owner from the IDP. External ID supports the same lookup attributes as
owner_type
The node type of the owner (case insensitive). For custom identity providers, use format OAA.{idp_type}.IDPUser, where {idp_type} is the value specified when creating the custom IdP provider. To find your idp_type value, use the . The attribute is optional when the Global IDP is configured
primary
If true, user is the primary owner, defaults to false
For example, setting the owner on a role may look like the following:
For custom identity providers, you will need to determine the correct owner_type format to identify the entities in Veza Graph. You can find this information through the Veza UI or using an API request:
In the Veza UI:
Go to Access Visibility > Graph
Search for a user from your custom identity provider
Click on the user to open the sidebar and choose Basic Actions > View Details
The entity type is displayed in the user details (e.g., "OAA.Custom_IDP.IDPUser")
Use this exact node type as your owner_type value
Alternately, you can use GET /api/v1/providers/custom to list all custom providers and their idp_type values. The owner_type format should be OAA.{idp_type}.IDPUser
See the table below for common IdP types and corresponding owner entity types:
Provider Type
idp_type Value
owner_type Format
Standard Okta
"Okta"
OktaUser
Standard Azure AD
"AzureAD"
If an Owner entry is malformed, references an unsupported owner type, or conflicts with the Global IDP setting a Field Violation error will be returned and the OAA payload will be rejected.
If an owner identity cannot be found, a warning will be returned with the successful response and the OAA payload will be accepted and processed with the unknown owner(s) being ignored.
Entity owners must originate from the primary Global IdP source. Users from alternate manager lookup sources cannot be used as entity owners.
After submitting an OAA payload with entity owners, verify the assignment by locating the entity in Query Builder or Graph Search. You can then configure automatic reviewer assignment to use these owners in access review workflows.
Early Access: OAA Entity Owners functionality is currently in Early Access for automatic assignment of entity ownership during OAA payload submission. Please contact our customer success team to enable this feature for your environment.
Register a new datasource for a custom provider. There can be more than one datasource for a single provider.
Returns details for a single datasource.
Unbind a datasource from a custom provider, and delete it.
To push authorization metadata for a custom datasource, you can specify the source and provider IDs, and upload a payload with the entities and permissions in JSON format.
A warning is returned for any non-critical errors during payload processing. These can indicate incomplete or inaccurate data in the payload that do not prevent processing, but may warrant attention.
For large payloads that exceed 100 MB, use the multipart upload endpoint to upload the payload in chunks. See Multipart Upload for details, examples, and Python SDK usage.
For CSV Upload Integrations, this endpoint pushes CSV data to an existing datasource. Typically, you will first create the integration and define column mappings using the "Add Integration" flow in Veza.
CSV data must base64 encoded into the JSON body of the request.
The populated template can be compressed and encoded, for significantly reduced payload size.
Specify the compression_type. Currently supported: GZIP.
If compression is selected, Veza will expect the payload json_data as a compressed, base64-encoded string.
To compress using shell commands:
Size is typically not an issue when updating custom datasources. However, you may want to compress large payloads. The maximum body size is 100MB (compressed or uncompressed).
Veza expects the populated template as a single JSON string, enclosed in the request body json_data field. Any "s and non-ASCII characters must be escaped.
To convert a template to JSON string using Python, the json.dumps() method could be used:
You can optionally add an icon for your custom provider by uploading a PNG or SVG file (less than 64kb) as a base64-encoded string:
Upload a custom icon to display for an OAA provider.
Return the type and string-encoded icon for a custom provider.
Veza expects that spaces in URLS are encoded as "+" (for example?name+eq+"GitHub"&order_by=state). Note that some libraries and clients will encode spaces as "%2B" by default, which will cause errors unless you override this behavior.
Create Custom Provider Datasource
Get Datasource by ID
Delete Custom Provider Datasource
You can also delete OAA datasources from the Veza web interface. On the Integrations page, find the OAA datasource in the list and click the action menu (⋮) to access the Delete option.
Push Custom Provider Datasource
Multipart Push Custom Provider Datasource
Push Custom Provider Datasource CSV
Compression
Escaping unsafe characters
Custom Provider Icons
Create Custom Provider Icon
Get Custom Provider Icon
Delete Custom Provider Icon
Custom Properties
Applying additional metadata to OAA entities
In addition to built-in fields such as last_login_at, OAA supports custom-named properties for users, resources, groups, and other entities in a payload. Custom properties are validated against a set of custom property definitions as part of the JSON payload.
To use custom properties:
Include a definition of all properties as part of the payload push. The definition sets the type for the property.
Set the custom properties for each object.
Built-in properties (such as last_login, created_at, and is_active for local users) enrich Veza graph entities with additional metadata. These built-in properties are described in the template documentation for and .
If a built-in property doesn’t exist for the provider you are modeling, you can define custom properties in the OAA payload. This can enable sophisticated queries on many possible fields (such as encryption_enabled, password_last_used_at). Custom properties have a declared data type and are indexed and filterable, like any built-in property.
For example, you could use the custom string property "state" for an app that can be either "active," "suspended," or "disabled." If there's only one state, you could instead use a boolean ("active": "false").
Custom Properties are defined as part of the custom_property_definition section and require a type. Typing the data allows Veza to provide a better index and search experience. For example, the TIMESTAMP type enables date-relative filters such as "in the last 30 days."
Allowed types are NUMBER, STRING, STRING_LIST, TIMESTAMP, and BOOLEAN.
A type is required and permanent.
Dates must be in , which can include a timezone offset or use UTC (2021-01-01T22:47:31-07:00, 2021-01-01T22:47:31Z).
In the Veza UI, underscores in property names are replaced by spaces, and first letters are capitalized (is_licensed > Is Licensed).
If a custom property name collides with an existing built-in property, Veza will add the "Custom" prefix (ID > Custom Id).
In the Query Builder API, custom properties are prefixed with custom_ in responses and must be prefixed with custom_ when used in filter statements.
Once pushed, properties and types can't be altered. You can re-submit the payload with additional custom property definitions to add new properties.
Property values on entities can be modified by pushing a complete payload with new custom_properties or using operations.
The provider must be deleted and pushed again to remove properties from a definition or change their types.
The original custom property definition is not required in future submissions but should be saved for later reference.
Here are some example custom property definitions for the and templates.
The also supports creating and setting custom properties.
A custom property definition sets possible properties, their types, and the application or resource type they can apply to. The following entities can have custom properties:
Entity
Key
Notes
The following example shows a custom property definition for GitLab:
Properties are set on users and resources in custom_properties:
Entity
Key
Entity Enrichment
Template for setting custom property values on existing entities in the Veza authorization graph
Use this template to set custom property values on existing entities in the Veza authorization graph using the Open Authorization API. Unlike other OAA templates that create new entities, the Entity Enrichment template adds metadata to entities that already exist from other integrations.
Entity enrichment is useful when you have supplemental data about entities that Veza already discovers through native integrations. For example, you might enrich AWS IAM roles with internal compliance metadata, or tag Okta users with cost center information from a custom source.
The Entity Enrichment template sets arbitrary custom properties via API push. This is distinct from , which are UI-configured rules that set a fixed set of built-in Veza classification attributes (identity type, owner, privileged status, and criticality) at extraction time. Use this template when you need to attach custom metadata beyond those built-in attributes. For assigning entity owners (a built-in attribute), see .
The template has two sections:
Enriched entity property definitions - declares the custom properties and their types for each entity type being enriched.
Enriched entities - the list of existing entities to enrich, with values for each declared property.
To use the entity enrichment template, set the template type to entity_enrichment when creating a new data provider:
Field
Type
Description
Each entry declares the custom properties that will be added to a specific entity type, along with their data types. Property types determine how Veza stores and indexes values. For example, TIMESTAMP properties enable relative date filters in queries (such as "last 90 days").
Field
Type
Description
Type
Description
The list of existing entities to enrich with property values. Each entity must appear exactly once with all properties that should be set. Including an entity with no properties clears all enriched property values from that entity. Only entities in the list are updated; other entities are not affected.
Field
Type
Description
To create the OAA provider and push enrichment data:
Create the provider with the entity_enrichment template type:
Create a data source on the provider:
Push the enrichment payload to the data source:
The push endpoint requires the payload as a JSON-encoded string in the
Updates follow the same push workflow. Each push replaces the enrichment data for the entities included in the payload. Entities not included in the push are not affected.
Property values vs. property definitions: You can clear a property value by omitting its key in a subsequent push, or by including the entity with an empty properties object. This clears the stored value but does not remove the property definition from the entity type. Once a property name is defined for an entity type, the definition persists in the graph and cannot be removed.
Provider deletion: Deleting an enrichment provider does not remove enrichment data from the Veza graph. Data pushed through the provider remains associated with the enriched entities after the provider is deleted. Contact Veza support if you need to fully remove enrichment data from the graph.
sso_last_login_at missing on specific users
Identity mismatch
Ensure the user's identities values match the OktaUser property values (check casing and email format)
sso_last_login_at missing on specific users
No Okta SSO activity
The user may not have accessed this application through Okta SSO
sso_last_login_at missing on specific users
No audit log activity for the app
Check Audit Logs for entries where the identity (GPID) accessed the OktaApp matching your okta_app_id. Enrichment only occurs when Veza has recorded SSO activity for that identity and application. This requires Audit Logs enabled on the Okta integration.
app = CustomApplication(name="Demo", application_type="Demo")
# Define a new local user string property `email`
app.property_definitions.define_local_user_property("email", OAAPropertyType.STRING)
local_user = app.add_local_user(name="name", unique_id="user_id")
# set the property by name
local_user.set_property("email", "user@example.com")
Date/time value. Enables relative date filters in Veza queries
STRING_LIST
List of string values
data_source_id
string
Veza data source ID for the entity. For AWS, combine the account ID with the data source type (e.g., 339083562601:awsiam)
properties
dictionary
Map of property names to values. Keys must be defined in the property definitions, and values must match the declared type. Omitting a key that is defined in the property definitions removes that property value from the entity
Methods for working with Custom Data Providers and Sources
This document provides a basic overview of the API requests for creating and updating an OAA data source. These steps and API calls can be adapted for your client or programming language of choice. You can also use the oaaclient Python module to handle Veza authentication, register the data source, and push the populated template.
Overview
While registering sources and pushing authorization metadata with Open Authorization API is relatively straightforward, it is important to understand how Veza organizes custom providers and data sources as endpoints:
The determines the type of entities the provider supports (application, identity_provider, or hris).
Each custom provider can have one or more data sources (such as different instances or domains), generated using .
The populated template can describe additional resources and sub-resources, such as individual databases, repositories, or views.
You can for each custom data source.
All custom data sources are shown on the Configuration > Apps & Data Sources menu, and can be retrieved using .
You should typically name the provider based on the generic application provider (such as GitHub) and the data source after the top-level instance (such as GitHub - Organization). See the for more information about parsing and identifying entities using metadata from the source application.
Your requests will need to include a Veza API Key. For OAA APIs, using a is recommended. Provide it as the bearer auth token in the header of each request, for example:
Follow best practices for managing API keys: Do not save credentials in connector code. Consider using a secrets manager to securely store API keys and make them available at run time.
To add a custom application, you will need to:
Create a new custom provider and data source.
push the entity and authorization data in a JSON payload.
Use to register a new top-level custom provider. The custom_template determines what kind of entities you can push to the provider.
Custom Application provider
This is a common configuration with broad support for modeling applications with local identities, resources, and authorization:
Custom Application with SCIM lifecycle management
If your application exposes SCIM 2.0 endpoints, it can support automated provisioning and deprovisioning through :
Custom Application with REST lifecycle management
For applications that expose custom REST APIs (but not SCIM) for user provisioning. Veza sends REST requests to the application's endpoints through the Insight Point, which must have network access to the target application:
Custom Identity Provider
This template is for modeling custom or unsupported identity providers as a source of users and groups:
Identities and groups in the custom provider can mapped to local accounts in other systems, and assigned as entity owners. Custom IdPs can also be used a source of identity for Lifecycle Management policies.
HRIS Provider
This template is intended to model HR information systems. Set provisioning to true to use the HRIS as a system of record for Lifecycle Management policies:
Provider creation response
All provider creation requests return the Provider ID, which you will need to create and manage data sources:
Provider creation fields
Field
Type
Required
Description
Using the Python SDK
The oaaclient SDK provides create_provider() with an options parameter for advanced fields:
Each provider needs at least one data source. Create one with
The response will include the data source ID:
Datasources should be unique to the data collected by an OAA integration instance. For example, if an application has a "prod" and "dev" instance, creating a datasource for each will enable independent updates to each environment.
Name the data source uniquely based on the application instance to discover. Try to include the hostname or organization name in the data source. For example, don't use "GitHub" use "GitHub - Acme Inc" or "Portal - prod.corp.com"
Note that a provider id is required in both the request path and body.
Once the data source and provider are active, publish the payload with . The request body must include the Provider ID and Data Source ID.
json_data must contain the populated OAA template as a single JSON string (escaping any unsafe characters such as ").
Specifying the Provider ID and Data Source ID, perform the same used for the initial push.
To update an existing data source, use the operations and operations to get the provider and data source IDs.
Application Outline
This document provides a high-level overview and examples for getting started with a new OAA connector to integrate Veza with SaaS applications, infrastructure systems, custom-built applications, and other systems. These examples use Python and the oaaclient SDK.
When developing a connector, the source systems and customer needs can require changes to code flow for different deployment scenarios. The overall goals, best practices, and flow will apply for most integrations:
Code goals
The sample code was written with the following goals in mind:
Connector should be easy to run from automation platforms and the command line.
Parameters are passed through environment variables as well as command line flags. This makes the code easier to package into containers or serverless stacks and control through outside configuration. Connectors by nature require secrets such as the Veza API key. Managing these through variables affords additional options for secrets management.
Connectors do not require state:
Connectors do not require any persistent data between runs.
There is no special invocation for the first run or subsequent runs.
The connector handles all of the logic for provider and data source creation internally, as needed, or by discovering existing ones.
Connector code is importable:
The flexibility to import connector code into another piece of Python code enables a setup wrapper to handle job management tasks such as:
Secrets management
The exact flow of the connector can change to meet specific requirements, but the general steps are as follows:
Process and validate configuration parameters. Ensure you have supplied all necessary values such as host names, user names, and API keys.
Call the main run function with all the required and optional parameters.
Initialize the oaaclient connection to the Veza tenant. Initializing the client verifies that the Veza URL and API key are valid before starting any application discovery.
Update the Provider Name, App Type, and Application Name based on the source system. These values will typically be set to the product name. The data source name must be unique - check that an appropriate distinguishing value such as hostname is included in the data source name. For more information on naming, see
Define any needed in the __init__ method. Properties must be defined on the CustomApplication entities before setting them.
The code below can serve as a template and the comments explain the reasoning beyond the patterns.
C# OAA Application Connector
This document provides a high-level overview of and examples for getting started with a new OAA connector to integrate Veza with SaaS applications, infrastructure systems, custom-built applications, and other systems. These examples use C# and the Veza.OAA SDK.
When developing a connector, source system specifics and individual customer requirements will require alterations to code flow. However, the overall goals, best practices, and development flow are common to most integrations.
The example code was written with the following goals in mind:
Connector should be easy to run from automation platforms and the Command Prompt.
Data Source name should be unique to the discovered environment. This can be achieved by including a hostname or instance ID in the data source name: discoverable by the code and consistent between runs. This ensures that two instances of the same connector do not interfere with each other if discovering separate instances of the application. When such a property cannot be determined, a command line parameter is an option.
Output logging
Other configurations required by the environment
A separate run function implements connector end-to-end logic. This can be imported and invoked by providing the necessary parameters. The main function that runs when invoked from the command line should only process command line inputs and environment variables for setup.
Create an instance of the oaaclient.templates.CustomApplication to populate with the application information.
Connect to the system and perform discovery of required entities:
The discovery order for users, groups, roles, and so on can be changed based on relationships and interface.
Populate the CustomApplication instance with the identity, roles and permissions, resources, and authorization information.
Check if Provider and Data Source exist on Veza. Create them if they do not exist.
Push the application to the Data Source. The SDK creates the JSON payload from the CustomApplication instance.
Process any returned warnings or errors.
Exit.
Implement the discovery steps for the
discover()
function to collect Users, Groups, Roles, and any resources for the application. As the entities are discovered, add them to the
CustomApplication
object using the appropriate
.
Run the connector to validate the output in Veza.
Automate the connector to run on a regular schedule.
Parameters are passed through environment variables as well as command line flags.
Connector does not require maintenance of state:
Connector does not require any persistent data between invocations.
There is no special invocation for the first execution.
The connector handles all provider and data source management logic.
Data source name is unique to the discovered environment.
The exact flow of an OAA connector can change to meet specific requirements, but the general steps are as follows:
Process and validate configuration parameters. Ensure that all required values are present and valid.
Initialize the API client connection to the Veza tenant. Doing so early in the application flow validates the URL and API key before continuing discovery.
Create an instance of the Veza.OAA.Application.CustomApplication class to populate with application metadata.
Connect to the system and perform discovery of required entities.
In your custom integrations, discovery order for users, groups, roles, and other entities can adapt to suit application requirements.
Populate the CustomApplication instance with the identity, role, permission, resource, and authorization information collected.
Check if the Provider and Data Source exist on Veza. Create them if they do not exist.
Push the application to the Data Source on Veza. The SDK creates the required JSON payload from the CustomApplication instance.
Process any returned warnings or errors.
Exit.
To use this example as a starting point for your application integration, follow these steps:
Update the name, applicationType, and description of the CustomApplication object based on the source system for integration with Veza.
Define any custom_properties needed. Properties must be defined on the CustomApplication object before their values are set on any entities.
Implement the discovery steps in the Discover() function to collect user, group, role, resource, and permission data for the application. As entities are collected, add them to the CustomApplication object.
Run the connector to validate the output in Veza.
The following code provides a template and examples for creating a new application integration using the Veza.OAA SDK.
Code goals
High-level code flow
Customizing the example
Example: custom application
oaa-app.py
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import logging
import os
import sys
import requests
from requests.exceptions import HTTPError, RequestException
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomApplication, OAAPermission, OAAPropertyType, LocalUser
import oaaclient.utils as oaautils
"""
Logging in connectors is very important. Establishing a local logging function here
allows the connector log even if its imported into another block of code
"""
logging.basicConfig(
format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
log = logging.getLogger(__name__)
"""
The main logic for connecting to the destination application.
Authorization data collection and OAA template population should be structured into a class.
The class can store the authentication tokens making connections through an API or SDK easier.
The class should also instantiate the OAA CustomApplication or CustomIdP class
to manage populating all the identity, resource and authorization data.
"""
class OAAConnector():
APP_TYPE="SampleApp"
def __init__(self, auth_token: str) -> None:
self.auth_token = auth_token
# Set the application name and type. The type will generally be the vendor or product.
# The App Name can be the same, or contain additional context like the instance name.
app_name = "My App - West"
self.app = CustomApplication(app_name, application_type=self.APP_TYPE)
# declaring custom properties as part of the `__init__` keeps them together
self.app.property_definitions.define_local_user_property("email", OAAPropertyType.STRING)
self.app.property_definitions.define_local_user_property("has_mfa", OAAPropertyType.BOOLEAN)
"""
A `discover` method that starts the discovery cycle.
The discovery cycle should be invoked separately from the init.
More complex connectors may have additional setup steps between init and discovery
"""
def discover(self) -> None:
"""Discovery method"""
log.info(
"Start App discovery") # Start and stop log messages provide progress as discovery proceeds
self._discover_users()
self._discover_roles()
log.info("Finished App discovery")
return
"""
Smaller functions to perform portions of the discovery like users, groups, roles
should be private `_` functions to imply that they should not be run alone,
unless care is taken to ensure no dependencies.
For example, discovery of roles may assume that users are already discovered.
"""
def _discover_users(self) -> None:
log.info("Start user discovery")
# perform user discovery, for example process each user returned from an API call
for user in self._api_get("/Users"):
local_user = self.app.add_local_user(id=user["id"], name=user["name"])
local_user.is_active = user["active"]
local_user.set_property("has_mfa", user["mfa_enabled"])
log.info("Finished user discovery")
return
def _discover_roles(self) -> None:
log.info("Start role discovery")
# perform user discovery
log.info("Finished role discovery")
return
"""
Any required methods to interface with the application should be defined
as part of the class. Not all connectors need these methods, as they may use
other SDKs to interface with the application.
"""
def _api_get(self, path: str) -> dict:
# implement logic to make API call, process results, handle errors, retries ect.
# Could be done with a vendor SDK, SQL, or any method supported by the application
return {}
"""
A run function that is separate from `main` makes it easy to import the connector
into another piece of Python code. This may be useful to call the connector from
code that retrieves secrets or manages the job in other ways.
All necessary parameters should be taken in through the `run` function
"""
def run(veza_url: str, veza_api_key: str, app_key: str, **config_args) -> None:
# Process any configuration arguments
if config_args.get("debug"):
log.setLevel(logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.INFO)
log.info("Enabling debug logging")
else:
log.setLevel(logging.INFO)
save_json = config_args.get("save_json", False)
if not isinstance(save_json, bool):
raise TypeError("save_json argument must be boolean")
# Connect to the Veza instance before discovery to validate that the credentials are valid
try:
conn = OAAClient(url = veza_url, api_key = veza_api_key)
except OAAClientError as error:
log.error(f"Unable to connect to Veza {veza_url}")
log.error(error.message)
# run function should raise any exception so that they can be handled by the parent code, never exit
raise error
# Initialize the connector class and run discovery
try:
app = OAAConnector(auth_token=app_key)
app.discover()
except RequestException as e:
# process possible exceptions from the app discovery
log.error("Error during discovery")
log.error(f"{e} - {e.response.status_code} {e.response.text}")
raise e
# After discovery is complete, set up the Provider and Data Source to push the data to
# Provider name should be consistent with the vendor and application
provider_name = "My App"
provider = conn.get_provider(provider_name)
if provider:
log.info("found existing provider")
else:
log.info(f"creating provider {provider_name}")
provider = conn.create_provider(provider_name, "application", base64_icon=APP_SVG_B64)
log.info(f"provider: {provider['name']} ({provider['id']})")
# Data Source name should be unique to the instance of the app that is discovered but consistent.
# For example the hostname of the application or deployment name. Do not use something that will change.
data_source_name = f"App - {app.unique_identifier}"
try:
log.info("uploading application data")
response = conn.push_application(provider_name,
data_source_name = data_source_name,
application_object = app.app,
save_json = save_json
)
# An OAA Push can succeed with warnings, you can log out the warnings
if response.get("warnings", None):
log.warning("Push succeeded with warnings:")
for e in response["warnings"]:
log.warning(e)
log.info("success")
except OAAClientError as error:
# if there is an issue with the OAA payload the error details should contain useful information to help resolve the problem
log.error(f"{error.error}: {error.message} ({error.status_code})")
if hasattr(error, "details"):
for detail in error.details:
log.error(detail)
raise error
return
"""
Setting an application icon helps visually identify the app in the Veza UI.
A Base64 encoding of an SVG or PNG in the app code is an option.
You can also import an icon from a file with `oaaclient.utils.encode_icon_file`.
"""
APP_SVG_B64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFRE
IFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgd2lkdGg9IjQwMCIgaGVpZ2h0
PSI0MDAiIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KICA8cGF0aCBmaWxsPSJyZWQiIHN0cm9r
ZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIyLjUiIGQ9Ik0xNjggMTY4SDMyVjMyaDEzNnoiLz4NCjwvc3ZnPg0K
"""
"""
The main entry point should only deal with processing parameters and invoking
the run function. No OAA or application discovery should happen during the main
function. All required parameters should be configurable through the OS
environment. It should be possible to run the connector from the command line
with no arguments.
"""
def main():
"""
process command line and OS environment variables, then call `run`
"""
parser = argparse.ArgumentParser(description = "OAA Connector")
# using the `default=os.getenv()` pattern makes it easier to get parameters from command line or OS environment
parser.add_argument("--veza-url", default=os.getenv("VEZA_URL"), help="the URL of the Veza instance")
parser.add_argument("--debug", action="store_true", help="Set the log level to debug")
parser.add_argument("--save-json", action="store_true", help="Save OAA JSON payload to file")
args = parser.parse_args()
# Secrets should only be passed in through ENV
veza_api_key = os.getenv("VEZA_API_KEY")
veza_url = args.veza_url
save_json = args.save_json
if not veza_api_key:
oaautils.log_arg_error(log, None, "VEZA_API_KEY")
if not veza_url:
oaautils.log_arg_error(log, "--veza-url", "VEZA_URL")
# ensure required variables are provided
if None in [veza_api_key, veza_url]:
log.error(f"missing one or more required parameters")
sys.exit(1)
try:
run( veza_url=veza_url, veza_api_key=veza_api_key, save_json=save_json, debug=args.debug)
except (OAAClientError, RequestException):
log.error("Exiting with error")
sys.exit(1)
if __name__ == "__main__":
# replace the log with the root logger if running as main
log = logging.getLogger()
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
main()
example_app.cs
using RestSharp;
using RestSharp.Authenticators;
using Veza.OAA;
using Veza.OAA.Application;
using Veza.OAA.Client;
using NLog;
namespace Example.Integrations
{
/// <summary>
/// Example application group object
/// </summary>
public class AppGroup {
public string Name { get; set; }
public string Type { get; set; }
public string CreatedAt { get; set; }
public List<string> Users { get; set; }
}
/// <summary>
/// Example application resource object
/// </summary>
public class AppResource {
public string Name { get; set; }
public int SiteId { get; set; }
public string ResourceType { get; set; }
}
/// <summary>
/// Example application role object
/// </summary>
public class AppRole {
public string Name { get; set; }
public int SystemId { get; set; }
public string CreatedAt { get; set; }
public List<string> Users { get; set; }
public List<string> Resources { get; set; }
}
public class ExampleApp
{
// Optional NLog logger; can be replaced with any standard logging interface
private static Logger logger = LogManager.GetCurrentClassLogger();
// The base64-encoded logo for the application (displayed on the Veza UI)
public string LogoBase64;
// The name of the provider for the application
public string ProviderName;
// The custom application object for the example application
// This object is used to build the application payload for Veza
public CustomApplication CustomApp { get; set; }
// The example application client for the example application API (not shown in this example)
private ExampleAppClient AppClient { get; set; }
# region "Construction"
public ExampleApp()
{
// Instantiate the example application
CustomApp = new CustomApplication(
name: "Example Application 1",
applicationType: "Example App",
description: "Example application for Veza integration"
);
// Define an "uncategorized" permission for the example application
// This can be used to group permissions that do not fit into another category,
// or if the application API does not provide permission information
CustomApp.AddCustomPermission(
name: "Uncategorized",
permissions: new List<Permission> { Permission.Uncategorized }
);
// define custom properties for the example application
DefineCustomProperties();
// Set the application icon for the Veza UI
// This should be a base64-encoded SVG or PNG image
LogoBase64 = "abc123...def987654"
}
/// <summary>
/// Define custom properties for the example application.
/// This method is called by the constructor to define any custom properties
/// that the example application entities may have.
/// </summary>
private void DefineCustomProperties()
{
CustomApp.DefinedProperties[typeof(User)].
DefineProperty("locked_out", typeof(bool);
CustomApp.DefinedProperties[typeof(Group)].
DefineProperty("type", typeof(string));
CustomApp.DefinedProperties[typeof(Role)].
DefineProperty("system_id", typeof(int));
CustomApp.DefineResourceProperty("site_id", typeof(int)), "widget");
}
# endregion
# region "Discovery"
// Individual methods for discovering users, groups, roles, and resources.
// Should be scoped as private to ensure that they are called only by the Discover method
// and not directly by the client application.
/// <summary>
/// Discover users for the example application.
/// This method is called by the Discover method to discover users for the example application.
/// </summary>
private void DiscoverUsers()
{
Logger.Info("Discovering users for the example application");
// Get users from the example application client.
// In this example, the GetUsers method returns a list of dictionaries of user data.
List<Dictionary<string, string>> users = AppClient.GetUsers();
// Iterate over the users response and add them to the application payload
foreach (Dictionary<string, string> u in users)
{
// Create a new user object and add it to the application payload
User user = CustomApp.AddUser(name: u["username"]);
user.AddIdentity(u["email"]);
user.IsActive = u["active"];
user.CreatedAt = u["created_at"];
}
Logger.Info("User discovery complete");
}
/// <summary>
/// Discover groups for the example application.
/// This method is called by the Discover method to discover groups for the example application.
/// </summary>
private void DiscoverGroups()
{
Logger.Info("Discovering groups for the example application");
// Get groups from the example application client
// in this example, the GetGroups method returns a list of AppGroup objects
List<AppGroup> groups = AppClient.GetGroups();
// Iterate over the groups response and add them to the application payload
foreach (AppGroup g in groups)
{
// Create a new group object and add it to the application payload
Group group = CustomApp.AddGroup(name: g.Name);
group.CreatedAt = g.CreatedAt;
group.SetProperty(name: "type", value: g.Type);
// Iterate users in the group and add them to the group
foreach (string user in g.Users)
{
CustomApp.Users[user].AddGroup(g.Name);
}
}
Logger.Info("Group discovery complete");
}
/// <summary>
/// Discover resources for the example application.
/// This method is called by the Discover method to discover resources for the example application.
/// </summary>
private void DiscoverResources()
{
Logger.Info("Discovering resources for the example application");
// Get resources from the example application
// In this example, the GetResources method returns a list of AppResource objects
List<AppResource> resources = AppClient.GetResources();
foreach (AppResource r in resources)
{
// Create a resource object and add it to the application payload
Resource resource = CustomApp.AddResource(name: r.Name, resourceType: r.ResourceType);
// Set the `site_id` property for the resource if the resource is a "widget"
// Cstom resource properties are defined per-resource type, so non-"widget" resources will not have this property
if (r.ResourceType == "widget")
{
resource.SetProperty(name: "site_id", value: r.SiteId);
}
}
Logger.Info("Resource discovery complete");
}
/// <summary>
/// Discover roles for the example application.
/// This method is called by the Discover method to discover roles for the example application.
/// </summary>
private void DiscoverRoles()
{
Logger.Info("Discovering roles for the example application");
// get roles from the example application
// in this example, the GetRoles method returns a list of AppRole objects
List<AppRole> roles = AppClient.GetRoles();
foreach (Role role in roles)
{
// create a new role object and add it to the application payload
Role role = CustomApp.AddRole(name: role.Name);
role.CreatedAt = role.CreatedAt;
role.SetProperty(name: "system_id", value: role.SystemId);
// iterate users in the role and add them to the role
// set the applyToApplication flag to true to apply the role to the entire application
foreach (string user in role.Users)
{
CustomApp.Users[user].AddRole(name: role.Name, applyToApplication: true);
}
Application.AddRole(role);
}
Logger.Info("Role discovery complete");
}
# endregion
# region "Execution"
/// <summary>
/// Discover the example application.
/// This method is called by the Run method to discover the example application.
/// It serves as a place to instantiate a client for the example application API
/// and then call each of the discovery methods required to build the application payload.
/// </summary>
/// <param name="exampleApiKey">The API key for the example application API</param>
/// <param name="exampleUrl">The URL for the example application API</param>
/// <returns></returns>
public void Discover(string exampleApiKey, string exampleUrl)
{
// instantiate an API client for the example application
AppClient = new ExampleAppClient(exampleApiKey, exampleUrl);
Logger.Info("Beginning example application discovery");
// discover the example application components
DiscoverUsers();
DiscoverGroups();
DiscoverResources();
DiscoverRoles();
Logger.Info("Example application discovery complete");
}
/// <summary>
/// Handle integration execution.
/// This is separated from the Main method to more easily adapt to changes
/// to application execution (e.g. from Command Prompt, as part of another application, etc.)
/// </summary>
/// <param name="exampleApiKey">The API key for the Example application API</param>
/// <param name="exampleUrl">The URL for the Example application API</param>
/// <param name="vezaApiKey">The API key for the Veza tenant</param>
/// <param name="vezaUrl">The URL for the Veza tenant</param>
/// <returns></returns>
public async Task Run(
string exampleApiKey,
string exampleUrl,
string vezaApiKey,
string vezaUrl
)
{
Logger.Info("Starting example application discovery");
// Instantiate a connection to the Veza API.
// The client will attempt to reach the Veza API and throw an exception if it fails.
// This is to ensure that the Veza API is reachable before attempting to discover and push data.
try
{
OAAClient oaaClient = new(vezaApiKey, vezaUrl);
}
catch (ClientException e)
{
Logger.Error("Failed to connect to Veza API: {0}", e.Message);
return;
}
// Discover the example application
Discover(exampleApiKey, exampleUrl);
// Get or create the Veza provider for the payload
Logger.Debug("Checking Veza for an existing provider for the example application");
Sdk.Client.ApiClient.VezaApiResponse providerResponse = await oaaClient.GetProvider(ProviderName);
// Create the provider if none exists
if (providerResponse is null)
{
Logger.Info("No Veza provider exists; creating provider");
await oaaClient.CreateProvider(ProviderName, "application", base64_icon: LogoBase64);
}
// Push OAA payload to Veza
Logger.Info("Pushing example application metadata to Veza");
RestResponse<Sdk.Client.ApiClient.VezaApiResponse> pushResponse = await oaaClient.PushApplication(ProviderName, Environment.MachineName, CustomApp, save_json: true);
if (pushResponse.IsSuccessful)
{
Logger.Info("Example application discovery complete");
} else
{
Logger.Error($"Push response code: {pushResponse.StatusCode}");
Logger.Error($"Push response content: {pushResponse.Content}");
}
}
# endregion
}
}
hris
HR systems with employees, managers, and organizational groups
Yes
Template type: application, identity_provider, or hris.
external_lifecycle_management_type
string
No
Enable lifecycle management: SCIM (standard SCIM 2.0 protocol) or SEND_REST_PAYLOAD (custom REST calls via Insight Point). Only for application template.
provisioning
boolean
No
Set to true to use as system of record for Lifecycle Management. Primarily for hris template.
curl -X GET "https://$VEZA_URL/api/v1/providers/custom" \
-H "authorization: Bearer $API_KEY"
Unlike SCIM mode, SEND_REST_PAYLOAD does not require an OAA connector definition. REST endpoints, HTTP methods, authentication, and payloads are configured in the Lifecycle Management policy. The Insight Point associated with the data source executes the REST calls.
Name the provider generically after the application or SaaS provider. Use the same provider for all data sources for that application.
If you are creating providers dynamically, your OAA integration should check if the provider and data source exist before creating a new one.
The examples on this page can be used as a starting point for building new connectors for custom applications. You should also refer to the current list of Veza-supported connectors for real-world examples, and to check if an integration already exists for your use case.
To run the code, you will need to export environment variables for the Veza URL, user and API keys, for example:
The most common OAA use case is modeling local identities, data sources, and permissions within an application containing sensitive information such as a database, ticket desk, or SCM platform. This sample app uses the CustomApplication class to create an OAA payload for a typical application that includes users, groups, roles and resources.
Customers that implement a custom Identity Provider (or one that doesn't have a native Veza integration) can use the OAA Custom IdP template to describe federated users and groups. This sample app generates a custom payload containing users, groups, and identity metadata, using the CustomIdPProvider class.
The example also demonstrates OAA support for AWS role entitlements, for scenarios where users can assume AWS roles in ways that can't be discovered by Veza's native AWS integration.
Sample app for importing Custom Identity Provider users from a CSV file.
This example can be used as a simple starting point for an OAA data source importer. Demonstrates use of CustomIdPProvider to create IdP users and assign properties using an input file with with the column headings:
Veza API key for authentication.
Generate keys in Administration > API Keys.
Body
get
Retrieve all custom (OAA) providers configured in the tenant. Custom providers represent integrations built using the Open Authorization API (OAA), including both Veza-managed connectors and customer-built integrations. Use the filter parameter to narrow results by name, state, or custom_template (e.g., filter=name eq "My App"). Set page_size to control results per page (default varies), and use page_token from the response to retrieve subsequent pages.
Authorizations
AuthorizationstringRequired
Veza API key for authentication.
Generate keys in Administration > API Keys.
Query parameters
filterstringOptional
order_bystringOptional
page_sizeinteger · int32Optional
The maximum number of results to be returned. Fewer results may be returned even when more pages exist.
page_tokenstringOptional
The token specifying the specific page of results to retrieve.
get
Authorizations
AuthorizationstringRequired
Veza API key for authentication.
Generate keys in Administration > API Keys.
Path parameters
idstringRequired
Responses
200
OK
application/json
idstringOptional
Unique identifier for the provider instance.
external_idstringOptional
External identifier for the provider, typically set by the integration that created it.
namestringOptional
Display name of the provider.
custom_templatestringOptional
The OAA template type used to create this provider (e.g., "application", "idp").
custom_templatesstring[]Optional
List of OAA template types associated with this provider instance (e.g., "application", "idp", "hris").
stateinteger · enumOptional
Current provider state.
application_typesstring[]Optional
Application type classifications for this provider.
resource_typesstring[]OptionalDeprecated
Deprecated. Resource type classifications. Use application_types, idp_types, hris_types, or file_system_types instead.
idp_typesstring[]Optional
Identity provider type classifications (if this provider represents an IdP).
file_system_typesstring[]Optional
File system type classifications (if this provider represents a file system).
hris_typesstring[]Optional
HRIS system type classifications (if this provider represents an HR system).
principal_typesstring[]Optional
Principal (identity) type classifications for this provider.
secret_store_typesstring[]Optional
schema_definition_jsonstring · bytesOptional
provisioningbooleanOptional
Whether provisioning (write-back) operations are enabled for this provider.
push_typeinteger · enumOptional
rbac_idstringOptional
internal_app_namestringOptional
configuration_jsonstringOptional
JSON string containing the provider's connection configuration parameters.
data_plane_idstringOptional
Identifier of the data plane that runs this provider's extraction. Empty for cloud-hosted extraction.
lifecycle_management_stateinteger · enumOptional
Current lifecycle management state for this provider (enum). Indicates whether provisioning and deprovisioning workflows are active.
team_idstringOptional
Identifier of the team that owns this provider instance.
template_typestringOptional
column_namestringOptional
destination_typestringOptional
destination_propertystringOptional
namestringOptional
typeinteger · enumOptional
lcm_unique_identifierbooleanOptional
as_listbooleanOptional
templatestringOptional
property_typeinteger · enumOptional
is_requiredbooleanOptional
application_namestringOptional
application_typestringOptional
identitystring[]Optional
resource_typestringOptional
okta_app_idstringOptional
list_delimiterstringOptional
idp_typestringOptional
domainstringOptional
hris_namestringOptional
hris_typestringOptional
hris_urlstringOptional
destination_datasource_typestringOptional
destination_datasource_oaa_app_typestringOptional
typeinteger · enumOptional
modeinteger · enumOptional
transformationsinteger · enum[]Optional
custom_valuestringOptional
source_propertyinteger · enumOptional
destination_propertyinteger · enumOptional
custom_source_propertystringOptional
custom_destination_propertystringOptional
source_idstringOptional
destination_idstringOptional
typestringOptional
oaa_app_typestringOptional
property_match_operatorinteger · enumOptional
use_emailbooleanOptional
hris_provisioning_sourcebooleanOptional
cmdb_instance_namestringOptional
cmdb_instance_typestringOptional
owner_id_column_namestringOptional
asset_id_column_namestringOptional
asset_type_column_namestringOptional
owner_node_typestringOptional
owner_id_propertystringOptional
asset_type_valuestringOptional
asset_node_typestringOptional
asset_property_namestringOptional
idstringRead-onlyOptional
secret_idstringOptional
typeinteger · enumOptional
mappingstringOptional
vault_idstringOptional
idstringRead-onlyOptional
namestringOptional
Must be unique within an insight point
vault_providerstringOptional
Provider type: "azure_key_vault", "aws_secrets_manager", etc.
insight_point_idstringOptional
Owning insight point ID, or "internal" for control plane vaults
deletedbooleanOptional
Soft-deleted flag for external vaults; restored by re-registering (internal vaults are hard-deleted)
#!env python3"""Copyright 2022 Veza Technologies Inc.
Sample Identity Provider
sample-idp.py
#!env python3"""Copyright 2022 Veza Technologies Inc.
Sample IdP from CSV input
IdPImportCSV.py
#!env python3
"""Example of using `oaaclient` to import users from a CSV file.
Reads user properties from the input file, populates an OAA payload,
and creates a new OAA identity provider containing the imported users.
Expected CSV headers are `identity,name,full_name,is_active,is_guest,manager_id`
Can be updated to match custom column headings or apply custom properties.
Example:
```
export VEZA_URL=<Veza URL>
export VEZA_API_KEY=<Veza API key>
./idp-importer-csv.py --provider MyIdpProvider --datasource MyDatasource ./my-users.csv
```
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
"""
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomIdPProvider
import click
import csv
import logging
import os
import sys
logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.INFO)
log = logging.getLogger()
def load_users(idp: CustomIdPProvider, source: str) -> None:
"""Populate the idp with user from the source csv file"""
log.info(f"Loading users from {source}")
with open(source) as f:
for r in csv.DictReader(f):
# get the identity, name, full_name and email
try:
identity = r["identity"]
name = r["name"]
full_name = r["full_name"]
email = r["email"]
except KeyError as e:
log.error(f"Incorrect CSV column headers, missing column {e}")
sys.exit(1)
# create a new IDP user
new_user = idp.add_user(name=name, full_name=full_name, email=email, identity=identity)
# set the user to active and guest or not, look for strings like true/false or yes/no
if r.get("active"):
active_string = r["active"].lower()
if active_string in ["true", "yes"]:
new_user.is_active = True
elif active_string in ["false", "no"]:
new_user.is_active = False
if r.get("is_guest"):
guest_string = r["is_guest"].lower()
if guest_string in ["true", "yes"]:
new_user.is_guest = True
elif guest_string in ["false", "no"]:
new_user.is_guest = False
# if the manager id column is filled in, set the new users manager
if r.get("manager_id"):
new_user.manager_id = r.get("manager_id")
return
@click.command()
@click.option("--provider", required=True)
@click.option("--datasource", required=True)
@click.option("--save-json", is_flag=True)
@click.argument("file", required=True)
def main(provider, datasource, save_json, file):
# load the Veza URL and API key from the environment
veza_url = os.getenv("VEZA_URL")
veza_api_key = os.getenv("VEZA_API_KEY")
if not (veza_url or veza_api_key):
log.error("Must set VEZA_URL and VEZA_API_KEY")
sys.exit(1)
try:
log.info("Testing Veza credentials")
veza_con = OAAClient(url=veza_url, api_key=veza_api_key)
except OAAClientError as e:
log.error("Unable to connect to Veza API")
log.error(e)
sys.exit(1)
# create a new provider if the provider doesn't already exist
if not veza_con.get_provider(provider):
log.info(f"Creating new provider {provider}")
veza_con.create_provider(provider, "identity_provider")
# Configure the Custom IdP
idp = CustomIdPProvider("Custom IdP", idp_type="custom_idp", domain="example.com", description=None)
# load the user from
load_users(idp, file)
try:
# push the IdP to Veza, log and errors or warnings
log.info("Sending to Veza")
response = veza_con.push_application(provider, datasource, idp, save_json=save_json)
if response.get("warnings", None):
log.warning("Push succeeded with warnings")
for w in response['warnings']:
log.warning(w)
log.info("Success")
except OAAClientError as e:
log.error(f"Error during push {e.message} {e.status_code}")
if e.details:
log.error(e.details)
sys.exit(1)
return
if __name__ == "__main__":
main()
OAA Template for Human Resources Information Systems
Overview
Use this Open Authorization API template to publish employee metadata for Human Resources Information Systems (HRIS) platforms, typically used by organizations as a single source of truth for employee information.
Unlike an Identity Provider, HR platforms typically do not provide access to other systems. Employee profiles within an HRIS platform are instead used to store important details such as employment status, who individuals report to, department, and country. Veza can use this metadata to:
Trigger Lifecycle Management events when there is a change in the integrated HRIS data source.
Correlate employees in the HRIS system with identities in your identity provider (IdP).
Enrich Access Reviews with details about linked HRIS employees for users under review.
The template supports:
A top-level System entity representing the HRIS tenant, organization, or account.
Employee entities representing current and inactive workers
Group entities representing teams, departments, cost centers, or other units to which users are assigned.
To enable this payload format, specify the hris custom template when with the API.
The HRIS template supports . After specifying a custom property definition in the payload, you can assign additional attributes to entities. These enable attribute filters for searches and access reviews in Veza, and enrich results with entity metadata unique to the source system or your organization.
Veza maps HRIS employees to identities from integrated Identity Providers (IdPs) such as Okta by matching the idp_id, email, or id value in the HRIS payload with the IdP entity's Name, Principal Name, or Identity. The matching process checks these fields in the following sequence:
idp_id
email
id
If the idp_id is unset, Veza uses the email field for matching. If the email field is also absent, the id is used. Veza issues a warning if no matching entity is found.
The account/tenant/etc. that contains the HR information.
Property
Attribute Name
Type
Required
Unique
Description
Used to represent any person who has been employed by a company.
Property
Attribute Name
Type
Required
Unique
Description
Used to represent any subset of employees, such as PayGroup or Team. Employees can be in multiple Groups.
Property
Attribute Name
Type
Required
Unique
Description
Use of this source code is governed by the MIT
license that can be found in the LICENSE file or at
https://opensource.org/licenses/MIT.
Example of using the `CustomApplication` class to model a typical application where users and groups are assigned
permissions to the application or resources.
If you want to run the code you will need to export environment variables for the Veza URL, user and API keys.
```
export OAA_TOKEN="xxxxxxx"
export VEZA_URL="https://myveza.vezacloud.com"
./sample-app.py
```
"""
from oaaclient.client import OAAClient, OAAClientError
from oaaclient.templates import CustomApplication, OAAPermission
import os
import sys
defmain():
# OAA requires an API token, which you can generate from your Veza user profile
# Export the API token, and Veza URL as environment variables
# Making them available to your connector in this way keeps credentials out of the source code
veza_api_key = os.getenv('VEZA_API_KEY')
veza_url = os.getenv('VEZA_URL')
ifNonein(veza_url, veza_api_key):
print("Unable to local all environment variables")
sys.exit(1)
# Instantiates a client connection. The client will confirm the credentials and Veza URL are valid
# Checking this early helps prevents connection failures in the final stage
List of destination IdP provider types to connect this system to (e.g. okta, azure_ad).
Identity Mapping Configuration
identity_mapping_configuration
Object
N
N
Configuration for mapping employees to identities in external data sources.
The employee's number that appears in the third-party integration.
Company
company
String
N
N
The company (or subsidiary) the employee works for.
First Name
first_name
String
N
N
The employee's first name.
Last Name
last_name
String
N
N
The employee's last name.
Preferred Name
preferred_name
String
N
N
The employee's preferred first name.
Display Full Name
display_full_name
String
N
N
The employee's full name, to use for display purposes. If a preferred first name is available, the full name will include the preferred first name.
Canonical Name
canonical_name
String
N
N
The employee's canonical name.
Username
username
String
N
N
The employee's username that appears in the integration UI.
Email
email
String
N
Y
The employee's work email.
IDP ID
idp_id
String
N
N
The ID for this employee on the destination IDP provider used to automatically connect to it, if not supplied email is used.
Personal Email
personal_email
String
N
N
The employee's personal email.
Home Location
home_location
String
N
N
The employee's home location.
Work Location
work_location
String
N
N
The employee's work location.
Cost Center
cost_center
EntityRef
N
N
Reference to the group representing the cost center the employee is in (e.g. {"id": "cost-center-001"}).
Department
department
EntityRef
N
N
Reference to the group representing the department the employee is in (e.g. {"id": "engineering"}).
Managers
managers
EntityRef list
N
N
References to the employee's managers (e.g. [{"id": "987654"}]).
Groups
groups
EntityRef list
N
N
References to the groups this employee is in (e.g. [{"id": "all_employees"}]).
Employment Status
employment_status
String
N
N
The employment status of the employee. Possible values include - ACTIVE, PENDING, INACTIVE.
Is Active
is_active
Boolean
N
N
If the employee is active or not.
Start Date
start_date
Timestamp
N
N
The date that the employee started working. If an employee was rehired, the most recent start date will be returned.
Termination Date
termination_date
Timestamp
N
N
The employee's termination date.
Job Title
job_title
String
N
N
The title of the employee.
Employment Types
employment_types
String list
N
N
The employee's type of employment. Possible values include - FULL_TIME, PART_TIME, INTERN, CONTRACTOR, FREELANCE.
Primary Time Zone
primary_time_zone
String
N
N
The time zone which the employee primarily lives.
The type of group, possible values include - TEAM, DEPARTMENT, COST_CENTER, BUSINESS_UNIT, GROUP. This is intended as to not have each type as their own nodes.
Parent
parent
EntityRef
N
N
Reference to the parent group (e.g. {"id": "parent-group-id"}).
Template for modeling a lightweight identity source with users, groups, and tenants
Use this template to model a source of identities (users, groups, and tenants) using the . Principals represent identity sources that connect to other OAA template types on the same provider, enabling Veza to map users and groups to the applications and resources they access.
The Custom Principal template differs from the in scope: a Principal is a lightweight identity source meant to feed users and groups into Custom Application or other templates on the same provider. Custom IdP models a full identity provider with domains and federated identity features.
The template has three primary entities:
Tenant - the top-level container for the principal instance. Each submission has exactly one tenant.
Users - the individual identities in the principal system. Users can belong to groups and have custom properties like is_active, email, and timestamps.
Groups - collections of users. Groups support hierarchical nesting through parent group references.
To use the principal template, set custom_templates to a list that includes principal when creating the provider. Because a principal is almost always used alongside an application, include both templates:
Then create a data source for the principal on that provider, specifying the principal template:
Veza's Atlassian Cloud connector uses the Custom Principal template to model the organization-level identity directory in Atlassian Cloud. The principal feeds users and groups into the Jira Cloud and Confluence Cloud application connectors on the same provider, linking identities to the resources they access.
This approach separates identity management (who exists, what products they can access) from application-level authorization (what permissions they have in Jira projects or Confluence spaces). The principal captures the organization directory, while separate Custom Application submissions model Jira and Confluence.
Key patterns from this integration:
user_type distinguishes managed users (in the organization's domain) from external collaborators, enabling access reviews to flag external access.
product_access as a STRING_LIST tracks which Atlassian products each user can access (Jira, Confluence, Bitbucket), providing visibility into license usage.
access_billable flags whether the user counts toward the organization's Atlassian license seat count.
Groups map to product access rather than organizational structure — groups like jira-software-users and confluence-users reflect Atlassian's product-based access model.
The principal connects to application templates on the same provider. Users and groups defined here appear as identities in Jira Cloud and Confluence Cloud Custom Application submissions, linking organization membership to application-level permissions.
Field
Type
Description
name
string
Name of the principal provider instance
principal_type
string
Type descriptor for the principal provider (e.g., corporate_directory). Applied as a searchable property
Each principal submission contains exactly one tenant, representing the top-level container for the identity source.
Field
Type
Description
name
string
Display name for the tenant
id
string
Unique identifier for the tenant
Users represent individual identities in the principal system. Each user can be linked to external identities and assigned to groups.
Field
Type
Description
name
string
Display name for the user
id
string
Unique identifier for the user. Defaults to name if not provided
Groups represent collections of users. Groups can have external identities and support hierarchical nesting through parent group references.
Field
Type
Description
name
string
Display name for the group
id
string
Unique identifier for the group. Defaults to name if not provided
Custom properties allow you to attach additional metadata to principal entities. Define properties in the custom_property_definition object, then set values on individual entities.
Scope
Description
tenant_properties
Custom properties for the tenant entity
user_properties
Custom properties for user entities
group_properties
Custom properties for group entities
Property values must match their declared type. Supported types are described in Custom Properties.
After the initial metadata push (which must contain the full payload), you can modify, add, or remove the tenant, users, and groups without resubmitting other entities. An incremental update is enabled by setting "incremental_change": true in the push payload, and specifying the update operation for each entity to change.
To create the OAA provider and push data:
Create the provider with both the principal and application template types:
This example demonstrates a corporate directory with users assigned to groups, custom properties, and hierarchical group nesting.
Real-World Example: Atlassian Cloud Admin
Atlassian Cloud Admin Payload
This payload models an Atlassian Cloud organization with managed and external users, product-access groups, and custom properties tracking account metadata.
Top-Level Payload
Tenant
Tenant Properties
Users
User Properties
Groups
Group Properties
Custom Property Definitions
Incremental Updates
Creating and Updating a Custom Principal
Client
Classes for calling Veza APIs and managing OAA providers and data sources.
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
Global Variables
OAACLIENT_VERSION
PROVIDER_ICON_MAX_SIZE
Entry point for oaaclient-report-builder command
Reads a JSON file and passes it to the oaaclient.utils.build_report method
Error raised by OAAClient.
Raised for issues connecting to the OAA API and when the API returns an error.
Args:
error (str): short string for error message
message (str): detailed error message
status_code (int, optional): status code for HTTP related errors. Defaults to None.
details (list, optional): list of additional details for error. Defaults to None.
Error returned from API Call
Error with API Connection
Class for OAA API Connection and Management.
Utilities for OAA-related operations with Veza API calls. Manages custom providers and data sources, and can push OAA payloads from JSON or template objects.
Connection url and API key can be automatically loaded from OS environment values if set. To utilize environment variables initialize OAAClient without providing a URL or API key value and set the VEZA_URL and VEZA_API_KEY OS environment variables.
Args:
url (str, optional): URL for Veza instance.
api_key (str, optional): Veza API key.
username (str, optional): Not used (legacy). Defaults to None.
token (str, optional): Legacy parameter name for API key. Defaults to None.
Attributes:
url (str): URL of the Veza instance to connect to
api_key (str): Veza API key
enable_compression (bool): Enable or disable compression of the OAA payload during push, defaults to enabled (True)
Raises:
OAAClientError: For errors connecting to API and if API returns errors
Add a Query to a Report
Adds a Query to an existing Report by ID
Args:
report_id (str): Report UUID to add Query to
query_id (str): Query UUID to add
Returns:
dict: API Response
Perform REST API DELETE operation.
Args:
api_path (str): API Path API path relative to Veza URL
Raises:
OAAResponseError: API returned an error
OAAConnectionError: Connection error during HTTP operation
Returns:
dict: API response from call
Perform a Veza API GET operation.
Makes the GET API call to the given path and processes the API response. Returns the value or values result returned from the API.
For API endpoints that return a list like /api/v1/providers/custom function will return a list of entities or an empty list if the API returns no results.
For API endpoints that are a specific ID such as /api/v1/providers/custom/<uuid> function will return the dictionary result of the JSON returned by the API.
Args:
api_path (str): API path relative to Veza URL (example /api/v1/providers).
Raises:
OAAResponseError: API returned an error
OAAConnectionError: Connection error during HTTP operation
Returns:
list|dict: Returns list or dict based on API destination
Perform REST API PATCH operation.
Args:
api_path (str): API Path API path relative to Veza URL
Raises:
OAAResponseError: API returned an error
OAAConnectionError: Connection error during HTTP operation
Returns:
dict: API response from call
Perform a Veza API POST operation.
Call POST on the supplied Veza instance API path, submitting a data payload.
Returns value or values response from API result. Paginated responses are automatically processed to collect all responses a single list.
Args:
api_path (str): API path relative to Veza URL example /api/v1/providers
data (dict): dictionary object included as JSON in body of POST operation
OAAConnectionError: Connection error during HTTP operation
Returns:
dict: API response as dictionary
Create a new Data Source for the given Provider ID.
Args:
name (str): Name for new Data Source
provider_id (str): Unique identifier for the Provider
options: (dict, optional): Additional arguments to be included with data source create call to Veza. Defaults to None.
Raises:
ValueError: Data source name contains invalid characters
Returns:
dict: dictionary of new Data Source
Deprecated Legacy function for backward-compatibility.
Create a new Provider.
Creates a new Provider with the given name. An error will be raised for naming conflicts.
Args:
name (str): new Provider name
custom_template (str): the OAA template to use for the Provider ("application" or "identity_provider")
base64_icon (str, optional): Base64 encoded string of icon to set for Provider. Defaults to "".
options: (dict, optional): Additional arguments to be included with provider create call to Veza. Defaults to None.
Raises:
ValueError: Provider name contains invalid characters
Returns:
dict: dictionary representing the created Provider
Create a new Assessment Query
For details on how to define an Assessment Query see the Veza docs.
Args:
query (dict): Query definition
Returns:
dict: API response including ID of created Query
Create a new Report
For details on how to define a new Report see the Veza docs.
Args:
report (dict): Report definition
Returns:
dict: API response including ID of created Report
Delete an existing Data Source by ID.
Removes a Data Source and all entity data.
Args:
data_source_id (str): ID of Data Source to delete
provider_id (str): ID of Data Source Provider
Returns:
dict: API response
Delete an existing provider by ID.
Deleting a provider removes all datasources and historical data. Fully deleting the provider is a background operation that will complete after API response is returned.
Args:
provider_id (str): ID of provider to delete
Returns:
dict: API response
Delete an Assessment Query by ID
Args:
id (str): UUID of Query to delete
force (bool): Force deletion of query that may be part of a report. Defaults to False
Returns:
dict: API response from delete
Delete Report by ID
Args:
id (str): UUID of Report to delete
Returns:
dict: API response
Get Provider's Data Source by name.
Find a Data Source from a specific provider based on the name of the Data Source
Args:
name (str): Data Source name
provider_id (str): Provider unique ID
Returns:
dict: Data Source as dict or None
Get Data Sources for Provider by ID.
Get the list of existing Data Sources, filtered by Provider UUID.
Args:
provider_id (str): ID of Provider
Returns:
list[dict]: List of Data Sources as dictionaries
Get Provider by name.
Args:
name (str): name of Provider
Returns:
dict: dictionary representing Provider or None
Get Provider by UUID identifier.
Args:
provider_id (str): Unique global identifier for provider
Returns:
dict: dictionary representation of Provider or None
Return list of Providers.
Returns:
list[dict]: Returns a list of existing Providers as dictionaries
Get all saved Assessment Queries
Veza can filter out queries that include inactive entity types (e.g. Okta Users on a system without Okta configured). To only retrieve queries that include active entity types set include_inactive_queries to False.
Args:
include_inactive_queries (bool): Set False to exclude inactive queries from result. Defaults to True.
Returns:
list: List of assessment Queries as dictionaries
Get Assessment Query by ID
Args:
id (str): UUID identifier for Query
Returns:
dict: Query definition
Get Report by ID
Veza can filter out queries from reports that only contain entity types that are not configured (e.g. Okta Users on a system without Okta configured). To only return queries configured on the report that match entity types configured on the system set include_inactive_queries to False
Args:
id (str): UUID of Report to get
include_inactive_queries (bool): Set True to include inactive queries. Default True.
Returns:
dict: Report definition
Get all Reports
Gets Reports created on the system. To get all reports include_inactive_reports and include_inactive_queries must be set to True.
Args:
include_inactive_reports (bool, Optional): Set to True to include reports that contain no active providers, defaults to True.
include_inactive_queries (bool, Optional): Set to True to include reports that contain only inactive queries, defaults to True.
Returns:
list[dict]: List of Reports as dictionary objects
Push an OAA Application Object (such as CustomApplication).
Extracts the OAA JSON payload from the supplied OAA class (e.g. CustomApplication, CustomIdPProvider, etc) and push to the supplied Data Source.
The Provider with provider_name must be a valid existing Provider or create_provider must be set to True. A new data source will be created automatically by default if it does not already exist.
For logging, and debugging, the optional save_json flag writes the payload to a local file (before push). Output file name is formatted with a timestamp: {data source name}-{%Y%m%d-%H%M%S}.json
Args:
provider_name (str): Name of an existing Provider.
data_source_name (str): Name for Data Source (will be created if it doesn't exist).
application_object (Class): OAA object to extract the payload from
save_json (bool, optional): Save the JSON payload to a local file before push. Defaults to False.
create_provider (bool, optional): Create a new Provider if Provider does not already exists. Defaults to False.
options (dict, optional): Additional dictionary of key/values to be included in push API call. Defaults to None.
Raises:
OAAClientError: If any API call returns an error (including errors processing the OAA payload).
Returns:
dict: API response from push, including any warnings that are returned.
Push an OAA payload dictionary to Veza.
Publishes the supplied metadata dictionary representing an OAA payload to the specified provider and data source. The function will create a new data source if it does not already exist, but requires the Provider be created ahead of time.
Args:
provider_name (str): Name of existing Provider
data_source_name (str): Name for Data Source, will be created if doesn't exist.
metadata (dict): Dictionary of OAA payload to push.
save_json (bool, optional): Save the OAA JSON payload to a local file before push. Defaults to False.
options (dict, optional): Additional dictionary of key/values to be included in push API call. Defaults to None.
Raises:
OAAClientError: If any API call returns an error including errors processing the OAA payload.
Returns:
dict: API response to the push request (including any warnings).
Update an existing custom provider icon from base64 encoded string.
To load an icon from file, use utils.encode_icon_file to get the base64 encoding of the file first
Args:
provider_id (str): unique ID of existing provider
base64_icon (str): base64 encoded string of new icon
Raises:
ValueError: If icon size exceeds maximum allowed size
Update an existing report
Args:
report_id (str): UUID of Report to updated
report (dict): Updated Report definition
Returns:
dict: API response
Updates the User-Agent string passed with all API calls
Generates a User-Agent with the oaaclient version, Python version and platform information.
The optional extra string will be appended if provided.
Args:
extra (str, optional): Additional information to append to User-Agent string. Defaults to "".
Super class for urllib3.util.retry
Super class to allow modifying the default max backoff time from 120 seconds to our own value
Template for modeling secret storage systems with vaults, entries, and permissions
Secret Store is an Early Access feature. Contact your Veza account team to enable it for your organization.
Use this template to model secret and credential management systems using the Open Authorization API. The Secret Store template captures the authorization relationships for custom or self-hosted credential management systems that are not covered by a native Veza integration.
The template models a hierarchical structure:
Secret Store - the top-level entity representing the secret management system instance
Permissions - define actions that identities can perform (e.g., Read, Write, Decrypt)
Vaults - logical containers for secrets within the store
Entries - individual secrets or credentials within a vault
Identities - optional identity mappings linking the entry to external identities
Identity-to-Permission Bindings - map identities to permissions on specific vaults
A can define additional properties for the secret store, permissions, vaults, and entries.
To use the secret store template, set the template type to secret_store when creating a new data provider:
Organizations with custom or self-hosted privileged access management (PAM) systems can use the Secret Store template to model their credential vaults, entries, and access permissions. This example shows how to map a typical PAM structure to the Secret Store template.
This example demonstrates key patterns for working with the template:
Vaults group credentials by scope. Permissions are granted at the vault level. Grouping credentials by team or system (databases, cloud keys) is the natural unit of access control.
allow_identity_assume indicates whether this permission grants the ability to retrieve and use a credential's actual value.
rotation_policy and requires_approval
Field
Type
Description
The secret store object is the top-level container for permissions, vaults, and identity mappings.
Field
Type
Description
Permissions define the actions that identities can perform on the secret store and its vaults. Permissions are referenced by name in identity-to-permission bindings.
Field
Type
Description
Vaults are logical containers for secrets within the store. Each vault has a type and can contain multiple entries.
Field
Type
Description
Entries represent individual secrets or credentials within a vault. Entries optionally include that link the credential to external identities in the authorization graph.
Field
Type
Description
Identity mappings on vault entries link a credential to external identities in the authorization graph. When the payload is parsed, Veza creates graph edges between the vault entry and the referenced identities. See for more information.
Field
Type
Description
Identity-to-permission mappings define which identities have which permissions on which vaults. Each mapping links an identity to one or more permission assignments.
Field
Type
Description
Each permission assignment binds a set of permissions to a set of vaults for the parent identity.
Field
Type
Description
Custom properties allow you to attach additional metadata to secret store entities. Define properties in the custom_property_definition object, then set values on individual entities.
Scope
Description
Property values must match their declared type. Supported types are described in .
After the initial metadata push (which must contain the full payload), you can modify, add, or remove the secret store, permissions, vaults, entries, and identity assignments without resubmitting other entities. An is enabled by setting "incremental_change": true in the push payload, and specifying the update operation for each entity to change.
To create the OAA provider and push data:
Create the provider with the secret_store template type:
Create a data source on the provider:
Push the payload to the data source:
The push endpoint requires the payload as a JSON-encoded string in the json_data
Updates follow the same push workflow. Veza processes the full payload and updates the Authorization Graph accordingly.
** are custom properties that capture PAM-specific policies useful for access reviews and compliance reporting.
secret_store
object
The object containing all entities
identity_mapping_configuration
object
Optional configuration for mapping local identities to users from external data sources
incremental_change
boolean
When true, enables (optional)
description
string
Description shown in Veza entity details (optional)
tags
array
Specify tags with a key and optional value
custom_properties
dictionary
validated against the custom_property_definition
operation
string
Operation type for (optional)
permissions
array
Array of objects
secret_store_vaults
array
Array of objects
identity_to_permissions
array
Array of mappings
resource
string
Resource path or pattern this permission applies to (optional)
allow_identity_assume
boolean
Whether this permission allows identity assumption (optional)
tags
array
Specify tags with a key and optional value
custom_properties
dictionary
operation
string
Operation type for (optional)
vault_type
string
Type descriptor for the vault (e.g., kv, transit, pki). Required
description
string
Description shown in Veza entity details (optional)
tags
array
Specify tags with a key and optional value
custom_properties
dictionary
validated against the custom_property_definition
operation
string
Operation type for (optional)
entries
array
Array of objects
description
string
Description shown in Veza entity details (optional)
This payload models a custom PAM system with two credential vaults, permission definitions, and identity-to-permission mappings reflecting typical DBA and platform engineer access patterns.
A can define additional properties, used to add supplemental metadata to entities in the payload.
Veza will handle federated identities just as those in supported IdPs such as Okta or Entra ID, enabling search and access review for OAA entities alongside the rest of your data catalog.
The metadata payload describes the Identity Provider domain, users, and groups to add to the Veza Access Graph:
For cases where federated IdP entities are granted AWS permissions via IAM roles, the template supports defining assumable roles per-user. Binding a custom IdP user or group to an AWS role or group ARN enables Veza to parse and display the resource-level actions permitted within AWS.
Custom IdP users and groups can be assigned permissions in other OAA applications by setting the principal type to idp in identity_to_permissions in the payload.
For use cases where a custom IdP is federated with another identity provider user identities can be linked between the two. Authorizations granted to the user will also be granted the source identity. The link is created by providing the unique identity ID and provider type as part of the user entry.
For provider_type the following values are accepted:
New in Veza release 2022.2.1
To assign an IdP user or group as the manager of any resource Veza has discovered, list the node type and node id in the entities_owned field, for example:
When parsing the payload, resources in the data catalog will be updated with a SYSTEM_resource_managers tag to enable entitlement reviews. The owner(s) will be suggested as reviewers for Veza Workflows that target an individual named resource with the correct tag.
Users and groups can be mapped to the identity of another user they report to. When configured, the manager will be suggested as a review for Workflow certifications where the assigned reporter is the single query target "named entity."
are the recommended method for adding additional metadata to custom identities and resources.
The custom_property_definition object supports separate property namespaces for each entity type:
Field
Description
Additionally, can be applied to the IdP domain, users, and groups:
Use incremental updates to remove tags: Resubmitting a payload with different tags will apply any new tags, but not remove existing ones. To remove a tag already applied to an entity, you will need to use the remove_tag operation.
After the initial metadata push (which must contain the full payload), you can modify, add, or remove the domain, users, and groups without resubmitting other entities. An is enabled by setting "incremental_change": true in the json_data push payload, and specifying the update operation for each entity to change.
The identity provider object models one instance of the custom IdP:
Field
Type
Description
One domain is supported for each custom IdP. Users and groups are mapped to the IdP domain, and connected in Veza Search:
Field
Type
Description
Each IdP user object contains the display name, login email, and identity, along with other identity-related properties:
Field
Type
Description
Add a group by name in the groups section of the template to enable mapping IdP users to those groups:
Field
Type
Description
IdP entities can be granted permissions on custom applications in the identity_to_permissions section of the .
Use the apps section to define any applications used to manage access within the identity provider. Apps can be associated with users and groups to model application assignments across your organization.
Field
Type
Description
The apps payload does not accept an owners field. To assign owners to CustomIDPApp entities, see .
Users and Groups can be assigned to an application by setting the app_assignments in the user or group.
Field
Type
Description
The steps to add a custom IdP are the same as for any other OAA provider: you will need to register the new provider and data source, and then push the domain, user, and group descriptions in a JSON payload.
To create a new custom provider using the identity_provider template, POST the name and template type to /providers/custom:
The response will return the custom IdP ID, which you will need when pushing the metadata payload:
Note that the provider id is required in both the path and body of the request. The response will include the new data source ID.
The payload file must contain the provider and data source ID, and the authorization metadata as a single string, for example:
The identity_mapping_configuration parameter defines rules for connecting users in a custom IdP to users from other data sources in the Veza graph.
This is useful when:
The connected data source does not natively support returning information about external identities
A correlation between IdP identities and local users can be assumed based on values like username, email, or another property value.
The identity_mapping_configuration is a top-level property of the Custom IDP submission, and is optional. The mapping configuration can include multiple mappings to connect IDP users to users from different data source types,
each based on its own mappings.
You can update just the identity mappings without resubmitting the entire provider payload by using an incremental update. This is useful when you need to modify only the mapping configuration while leaving other provider data unchanged.
Example curl command to apply the incremental identity mapping update:
Field
Type
Description
Field
Type
Description
Supported transformations:
IGNORE_SPECIAL: Ignore special characters (_, -, .) when matching identities
IGNORE_DOMAIN: Match identities after removing domain portions (e.g., "@example.com")
Field
Type
Description
OAA
custom
Google Workspace
google_workspace
Okta
okta
One Login
one_login
app_properties
Custom property definitions for IdP app entities.
app_assignment_properties
Custom property definitions for app assignment entities.
idp_type
string
Type descriptor for IdP, can be unique or share across multiple IdP (for example ldap, IPA)
idp_description
string
Any notes to add as entity details (optional)
domains
Domain model
users
Dictionary of CustomIdPUser class instances
groups
Dictionary of CustomIdPGroup class instances
incremental_change
boolean
When true, enables operations (optional).
identity_mapping_configuration
Configuration for mapping identities between IdP User and other User types from external data sources
dynamic_properties
Dynamic Properties
Up to 5 attributes to apply to the domain (deprecated, use instead)
tags
list
Any tags to create and apply to the domain.
operation
enum
For , the operation to use.
identity
string
Optional unique identifier for user
groups
string list
Assign groups memberships by group identity (optional)
full_name
string
Full name to display in Veza
department
string
Department to apply as a searchable property (optional).
is_active
boolean
If available, will be applied to the entity as a searchable property (optional).
is_guest
boolean
If available, will be applied to the entity as a searchable property (optional).
assumed_role_arns
array
AWS IAM roles that can be assumed by the IdP user, in the format {"identity": ["arn:aws:iam::123456789012:role/S3Access"]} (optional).
tags
list
Any tags to create and apply to the user.
dynamic_properties
Dynamic Properties
Up to 5 attributes to apply to the user (deprecated, use instead)
custom_properties
Each element of the push payload can have property_values, validated against the custom_property_definition.
manager_id
string
If the same as another user's identity, that user will be recommended for reviews. Entity details for the user will be updated on push to include the manager as a searchable property.
entities_owned
array
If another resource is specified by entity type and entity id, a Veza tag will be created on the resource to indicate the owner.
operation
enum
For , the operation to use (optional).
source_identity
Optionally link IdP user to user from another IdP for federation use cases.
full_name
string
Optional display name for group
groups
string list
other custom IdP groups this group is a member of
is_security_group
boolean
Sets the is security group searchable property for the entity in Veza (optional).
tags
Veza Tags list
Any to create and apply to the group.
custom_properties
Each element of the push payload can have property_values, validated against the custom_property_definition.
dynamic_properties
Dynamic Properties
Up to 5 attributes to apply to the domain. (deprecated, use instead)
operation
enum
For , the operation to use (optional).
assumed_role_arns
array
AWS IAM roles the group can assume, in the format {"identity": ["arn:aws:iam::123456789012:role/S3Access"]} (optional).
source_identity
Optionally link the IdP group to a group from another IdP for federation use cases (optional).
entities_owned
array
Resources to assign this group as manager of (optional).
app_assignments
array
App assignments for this group (optional). See .
description
string
Description for the App (optional).
assumed_role_arns
array
AWS IAM roles the app can assume, in the format {"identity": ["arn:aws:iam::123456789012:role/S3Access"]} (optional).
custom_properties
Each element of the payload can have property_values, validated against the custom_property_definition.
tags
Veza Tags list
Any to create and apply to the group.
operation
enum
For , the operation to use (optional).
app_id
string
Unique ID of the App to assign the identity to.
custom_properties
Each element of the payload can have property_values, validated against the custom_property_definition.
property_matchers
IdentityMappingPropertyMatchersSubmission
List of properties to match on
transformations
list enum
Optional transformations to perform on the property values, available values: ignore_special, ignore_domain
custom_source_property
string
When using property or custom_propert the property name to match on
custom_destination_property
string
When using property or custom_propert the property name to match on
Veza Type for the destination data source, GITHUB_USERS, SQL_SERVER, CUSTOM_APPLICATION
destination_datasource_oaa_app_type
string
Optional specifically for mapping to OAA Custom Application to provide a specific App Type
source_property
enum
IDP User property to match on, unique_id, email, property or custom_property
destination_property
enum
Destination User property to match on, unique_id, email, property or custom_property
Sample Template and Features
Simple Custom Identity Provider
{"name":"My IdP
Modeling Assumable Amazon Web Services Roles
Source Identity Assignments
Resource Manager Assignments
Manager Assignments
Custom Properties and Tags
Incremental Updates
Custom Identity Provider definition
IdP Domain
IdP Users
IdP Groups
IdP Apps
Creating and Updating a Custom Identity Provider
Register a custom identity provider
Push a data source for the custom identity provider
Push metadata for the data source
Identity Mapping Configuration
Incremental Identity Mapping Updates
Example: Incremental Identity Mapping Update
Set "incremental_change": true and use "operation": "modify" in the identity_mapping_configuration to update mapping rules without affecting other aspects of the provider.
Template for pushing custom data source entities and authorization
Overview
The Custom Application Template can be used to model most applications and services. It can describe many common entity types (such as users, groups, and resources), and should be the starting point for most custom connectors.
The template has three primary elements, covered in detail in this document:
Applications - describes one or more application instances for the custom data source. An application may consist of any of the following entities:
Local Users - defines the users of the application. The local user entity can be used to store the properties of the user specific to the application (such as last_login_at) and can be linked to a source identity like Okta or AzureAD.
Local Groups - defines a group of users, permissions to the application or resources can be assigned to a group.
Local Roles - defines a collection of permissions. A role can be used to link an identity (local user, group, or IdP) to an application or resource. An identity assigned to a role will be assigned all permissions from that role.
Local Access Credentials - defines API keys, tokens, certificates, or other non-human authentication methods used by applications or services.
Resources - for more fine grain authorization tracking resources can be used to represent components of the application that have their own authorization. Users and groups can be assigned permission or roles to resources.
Sub Resources - resources can additionally have sub-resources for additional levels of depth.
Permissions - define the applications specific permissions and map to Veza canonical permissions.
Identity to Permissions - Assign local and federated users and groups to permissions or roles to the application and resources.
Additionally, a may describe user-configured key:pair values that can be applied to entities in the payload.
To use the generic app template, set the template type to application when creating a new data provider:
If your custom application exposes SCIM 2.0 compliant endpoints, you can enable automated provisioning and deprovisioning through Veza Lifecycle Management and Access Requests by setting the external_lifecycle_management_type parameter to SCIM:
This enables Veza to automate user provisioning, deprovisioning, and group membership management for your custom application. For detailed configuration and supported operations, see .
and can be applied to most objects in the OAA payload: the application and its local_users, local_groups, local_roles and resources/sub_resources.
Define custom properties
In the rest of the payload, for each object that should have additional properties, add a custom_properties array containing the property keys and values:
Use incremental updates to remove tags: Resubmitting a payload with different tags will apply any new tags, but not remove existing ones. To remove a tag already applied to an entity, you will need to use the remove_tag operation.
Validation and Troubleshooting
The API response will provide information for invalid data submission. You can check Veza events for updates on parsing status. Errors won't typically occur during parsing, as the metadata is validated upon push. To ensure a valid payload, you should:
Confirm all string fields are are valid UTF-8 strings no larger than 256 bytes.
Check that all required fields are present. Tags and properties are optional. You can null empty groups, roles, and other "empty" but required keys.
A 200 OK response may include warnings when matching IDP identities can't be found
The OAA payload must contain at least one top-level application. To model data systems with multiple components (such as different servers or repositories), applications can have resources and sub-resources.
You can also specify more than one application in the OAA payload, each with its own identities, permissions, roles, and resources.
The application_typeis applied to all application resources and identities, and can be used as a filterable property in Veza search.
Field
Type
Description
Optional fields: some values in the schema are optional. When submitting a payload without a required field, an error message will help identify the issue. The following guidelines apply:
Any type of data in a JSON payload can be null (not set).
Unused optional arrays and objects should be empty {} or [].
Unused optional strings, numbers, and booleans should be null.
OAA apps need to contain at least one identity, which could be a local_group, local_role, or an IdP identity. Role assignments are made in the section.
Each application can contain one or more resources that users can access. Resources can have additional searchable properties and may contain additional sub-resources.
Sub-resources describe additional layers of the application principals can have authorization to, and support the same properties as resources, including additionally nested sub-resources.
An application can have any number of nested sub resources.
Field
Type
Description
* A specific resource type must have only resources with an id, or only resources without an id. When used identity_to_permissions assignments are made by the id value and name functions as a display name.
In the system being modeled, application resources and sub-resources (such as virtual machines or Looker views) have access to other entities in the Veza Access Graph.
If an application resource or sub-resource is able to assume the permissions of a local user, IAM role, or Enterprise application, you can specify the connections to another graph entity node_type and id:
The following node types are currently available:
SnowflakeUser
GoogleCloudServiceAccount
AwsIamRole
Applications can have local users and groups for identities. For users and groups that correlate to an external Identity Provider (for example accounts automatically provisioned by the IdP), you can map the principal to the IdP entity name or login email in identities.
Contains any users whose profiles and authentication are handled and stored by the custom application. Local users include their group assignments and any federated identities that should be mapped to the local user:
Field
Type
Description
If the application has any groups, describe each one in the local_groups array.
Group assignments for entities are defined in identity_to_permissions.
Field
Type
Description
*Must match a discovered Okta or Azure entity Name, PrincipalName, or Identity
Local roles define collections of local permissions that can be assigned to multiple resources. In the applications section, roles are named and mapped to permissions. Role assignments are defined in identity_to_permissions.
Field
Type
Description
Access credentials represent API keys, tokens, certificates, or other non-human authentication methods used by applications or services.
Field
Type
Description
permissions
Bind local permissions to the corresponding Veza canonical permission(s). Each native application permission should be included as an object, mapped to the corresponding data/non-data actions it allows.
Canonical permission types are:
DataRead
DataWrite
MetadataRead
Field
Type
Description
To better model systems where roles can contain different permissions to different types of resources, permissions can apply to individual resource_types.
When the payload is parsed, individual permissions are created for each type of resource the permission applies to.
Without resource_types specified, the permission will function normally. When directly connecting principals and resources, resource_type is ignored.
Contains an object for each local and IdP identity, and the individual permissions to applications and resources.
You can bind permissions to federated users and groups by providing the principal’s IDP login email or group name as the identity, and setting the identity_type to idp.
Permissions and role assignments can apply to the entire application or scoped to specific resources.
Field
Type
Description
Each identity can be either a local_user, local_role, local_group, or local_access_creds name, or the identifier of an IdP user, group, or role (email address or group name).
identity_type
application_permissions
Binds the identity (IdP entity, local user, or local group) to local permission, by application and resources.
Field
Type
Description
role_assignments
Local roles are assigned to identities in the role_assignments array. Roles can apply to the entire application or only to specific (sub) resources.
Field
Type
Description
The identity_to_permissions array defines how identities are authorized to applications and resources. Each entry maps an identity to its application permissions and/or role assignments. See the section above for field details.
description
string
Any additional notes to show in the entity details, limit 256 characters
custom_properties
dictionary
contain property_values validated against the custom_property_definition
tags
array
Specify tags with a key and optional value (optional)
owners
array
See
local_users
array
Contains zero or more local users (see ).
local_groups
array
Contains zero or more (collections of users).
local_roles
array
Defines permissions for any within the application.
local_access_creds
array
Contains any for the application.
local_agents
array
Contains any AI agent entities for the application.
local_models
array
Contains any AI model entities for the application.
resources
array
Contains any and sub-resources.
okta_app_id
string
(Optional, early access) The Okta Application ID for this application. When set, Veza enriches local users with sso_last_login_at timestamps from Okta SSO activity. Requires the INTEG_OAA_SSO_LAST_LOGIN feature flag. See .
Strings and string lists intended to have constant values (enums) such as identity_type may have a default value when not set.
resource_type
string
Searchable label for the resource type. The application entity details in Veza will show the contained resource types as properties.
description
string
Shown in Veza entity details, max 255 characters.
custom_properties
dictionary
See .
sub_resources
array
Used for additional resource layers, nested data sources, services, and so on.
connections
Optional list of resource connections to external entities discovered by Veza
tags
array
Specify tags with a key and optional value (optional)
owners
array
See
AzureADEnterpriseApplication
TrinoUser
email
string
User email address (optional). Separate from identities, this is a display/metadata field on the user entity.
identities
identities array
Maps the user to a federated identity by login email or group name. Use when your IdP provisions local accounts, or if the local user can be assumed by an external group. Must match a discovered Okta, Google Workspace, or Azure AD entity Name, PrincipalName, or Identity.
groups
groups array
List of any memberships as strings. Must exist in local groups.
access_creds
array
List of local_access_creds IDs associated with this user (optional).
is_active
boolean
If activity state is available from the provider, use this field to make the value available as a searchable property (optional).
user_type
string
Distinguishes between human and service_account user types (optional). Useful for identifying non-human accounts in access reviews.
principal_id
string
The ID for this user in a linked principal template, used for automatic connection. If not supplied, the user id is used (optional).
created_at
RFC3339 string
User creation date (optional), for example 1996-12-19T16:39:57-08:00.
last_login_at
RFC3339 string
(optional)
password_last_changed_at
RFC3339 string
(optional)
deactivated_at
RFC3339 string
(optional)
access_creds
array
List of access credential id values associated with this user (optional). Links the user to their API keys, tokens, or other credentials defined in local_access_creds.
custom_properties
dictionary
See .
tags
array
Specify tags with a key and optional value (optional).
owners
array
See
identities
array
If IdP users are members of the local group, or if the local group directly maps to an IdP group, list them here.*
groups
array
List of local groups this group is a member of (for applications that support adding groups to other groups).
access_creds
array
List of local_access_creds IDs associated with this group (optional).
created_at
RFC3339 string
Group creation date (optional).
custom_properties
dictionary
See .
tags
array
Specify tags with a key and optional value (optional).
owners
array
See .
permissions
array
Permissions associated with the role. Must exist in permissions.
roles
array
List of sub-role names for nested role hierarchies (optional). An identity assigned to this role inherits all permissions from its sub-roles.
custom_properties
dictionary
See .
tags
array
Specify tags with a key and optional value (optional).
owners
array
See .
created_at
RFC3339 string
When the credential was created (optional)
expires_at
RFC3339 string
When the credential expires (optional)
last_used_at
RFC3339 string
Last time the credential was used (optional)
can_expire
boolean
Whether the credential can expire
is_active
boolean
Whether the credential is currently active
custom_properties
dictionary
See
tags
array
See
owners
array
See
MetadataWrite
NonData
DataCreate
DataDelete
MetadataCreate
MetadataDelete
Uncategorized
apply_to_sub_resources
bool
To more accurately model applications where permissions should apply to any children of a resource, set TRUE to define the permission as inheritable. This eliminates the need to include the permission at each sub level.
resource_types
array
Optional list of resource type strings. When specified, separate permission nodes are created per resource type. See below.
For each identity (matching a local user, group, or IdP identity), state the identity type and add the assigned permissions/roles:
application_permissions
array
List each local permission available to the identity (must be a valid permission name from the previous section).
role_assignments
array
Any roles assigned to the identity, and the resources they apply to (role/resource must exist in applications).
must be one of:
idp
(default),
local_user
,
local_group
,
local_role
, or
local_access_creds
.
apply_to_application
boolean
Set to true to model environments where permissions apply to the top-level application as well as its resources.
permission
string
Maps to a permission name from the second section. Must exist in permissions
apply_to_application
boolean
Set to true to model environments where the role applies to the top-level application and all its resources.
resources
array
List of resources and sub-resources where the role applies. Must exist in applications
assignment_properties
dictionary
Custom properties on the role assignment itself (optional). Must be defined in role_assignment_properties within custom_property_definition. Useful for tracking assignment-specific metadata such as assignment date or expiration.
Classes for constructing an OAA JSON payload (Custom "Application" or "IdP").
Copyright 2022 Veza Technologies Inc.
Use of this source code is governed by the MIT license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
Global Variables
PROPERTY_NAME_REGEX
functionappend_helper
append_helper(base, addition)
Helper function to simplify appending.
Handles multiple cases:
base is None: starts a list
addition is list: extends base with list
addition is anything else: append element to list
Args:
base (List or None): base list to append to, can be None
addition (*): What to append to the list
Returns:
list: will always return a list
Returns a list of unique strings from input list case insensitive
Returns the unique list of strings from input list in a case insensitive manner. For duplicate strings with different cast (e.g. "STRING" and "string") the case of the first occurrence is returned.
Args:
input (list): list of strings
Returns:
list: list of unique strings
General exception used for violations of the template schema.
Canonical permissions used by Veza Authorization Framework.
Used to describe the raw data or metadata permissions granted by CustomPermission
Types of identities for permission mapping.
Base class for CustomProvider.
Base class for CustomApplication.
Class for modeling application authorization using the OAA Application template.
CustomApplication class consists of identities, resources and permissions and produces the OAA JSON payload for the custom application template.
Class uses dictionaries to track most entities that can be referenced after creation. Dictionaries keys are case insensitive of the entity identifier (name or id). This applies to local_users, local_groups, local_roles, idp_identities, resources and custom_permissions.
Args:
name (str): Name of custom application
application_type (str): Searchable property, can be unique or shared across multiple applications
description (str, optional): Description for application. Defaults to None.
Attributes:
application_type (str): Searchable application type
custom_permissions (dict[OAAPermission]): Dictionary of class instances
description (str): Description for application
Legacy method for backwards compatibility.
.. deprecated:
Create an Access Credential
Access creds can be used to represent alternative access methods such as API keys or application integrations.
Access creds can be assigned roles and permissions similar to local users. Access credentials can exist independently for use cases such as administratively created integrations or can be assigned to a local user for use cases like personal access tokens.
Args:
unique_id (str): unique identifier for access cred
name (str): name for access cred
Raises:
OAATemplateException: Access credential with unique ID already exists
Returns:
AccessCred: New access cred
Create a new custom permission.
Creates a new CustomPermission object for the application that can be used to authorize identities to the application, resources/sub-resource or as part of a role.
Args:
name (str): Name of the permission
permissions (list[OAAPermission]): Canonical permissions the custom permission represents
apply_to_sub_resources
Returns: CustomPermission
Create an IdP principal identity.
IdP users and groups can be authorized directly to applications and resources by associating custom application permissions and roles with an IdP identity's name or email.
Args:
name (str): IdP unique identifier for user or group.
Returns: IdPIdentity
Create a new local group.
Groups can be associated to resources via permissions or roles. All users in the local group are granted the group's authorization.
Local groups will be identified by name by default, if unique_id is provided it will be used as the identifier instead
Local groups can be referenced after creation using .local_groups dictionary attribute. Dictionary is case insensitive keyed by unique_id or name if not using unique_id.
Args:
name (str): Display name for group
identities (list): List of IdP identities to associate group with.
unique_id
Returns: LocalGroup
Create a new local role.
A local role represents a collection of permissions.
Identities (local user, group, idp user) can be assigned a role to the application or resource, granting the role's permissions.
Local roles will be identified by name by default, if unique_id is provided it will be used as the identifier instead.
Args:
name (str): Display name for role
permissions (list): List of Custom Permission names to include in role. CustomPermission must be created separately.
Returns: LocalRole
Create a new local user for application.
Local users can be assigned to groups and associated with resources via permissions or roles. Groups and identities can be provided at creation or added later. See Identity and LocalUser class for operations.
Local users will be identified by name by default, if unique_id is provided it will be used as the identifier instead.
Local users can be referenced after creation using the .local_users dictionary attribute. Dictionary is case insensitivekeyed by unique_id or name if not using unique_id.
Use unique_id when name is not guaranteed to be unique. All permission, group and role assignments will be referenced by unique_id.
Args:
name (str): Display name for user
identities (list): List of identities as strings (usually email) for local user. Used to map local user to discovered IdP identities.
groups
Returns: LocalUser
Create a new resource under the application.
Resource type is used to group and filter application resources. It should be consistent for all common resources of an application.
Returns new resource object.
Resource is identified by name by default unless unique_id is provided. name must be unique if not using unique_id.
Resources can be referenced after creation using the .resources dictionary attribute. Dictionary is keyed by unique_id or name if not using unique_id. Use unique_id when name is not guaranteed to be unique.
Args:
name (str): Name of resources
resource_type (str): Type for resource
description (str, optional): Description of resources. Defaults to None.
Returns: CustomResource
Add a tag to the Application
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Return the 'applications' section of the payload as serializable dictionary.
Add a custom permission to the application.
.. deprecated: ``` See CustomApplication.add_custom_permission()
Collect authorizations for all identities into a single list.
Get the OAA payload.
Returns the complete OAA template payload for application as serializable dictionary
Returns:
dict: OAA payload as dictionary
Return the 'permissions' section of the payload as serializable dictionary.
Set a custom property value for the application.
Property name must be defined for CustomApplication before calling set_property. See example below and ApplicationPropertyDefinitions.define_application_property for more information on defining properties.
Args:
property_name (str): Name of property to set value for, property names must be defined as part of the application property_definitions
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none
Raises:
OAATemplateException: If property name is not defined
Should be used for representing components of the application to which authorization is granted. Each resource has a name and a type. The type can be used for grouping and filtering.
Arguments:
name (str): display name for resource, must be unique to parent application or resource unless using unique_id
resource_type (str): type for resource
description
Attributes:
name (str): display name for resource, must be unique to parent application or resource
unique_id (str): resource's unique identifier if provided.
resource_type
No longer supported, access should be added through identity (local_user, local_group, idp)
Add an external connection to the resource.
Used to add a relationship to another entity discovered by Veza such as a service account or AWS IAM role.
Args:
id (str): Unique identifier for connection entity
node_type (str): Veza type for connecting node
Create a new sub-resource under current resource
Args:
name (str): display name for resource
resource_type (str): type for resource
description (str, optional): String description. Defaults to None.
Returns: CustomResource
Add a new tag to resource.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set the value for a custom property on a resource or sub-resource.
Property name must be defined for resource type before calling set_property(). See example below and ApplicationPropertyDefinitions.define_resource_property for more information on defining properties.
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none
Raises:
OAATemplateException: If property_name is not defined
Base class for deriving all identity types (should not be used directly).
Args:
name (str): name of identity
identity_type (OAAIdentityType): Veza Identity Type (local_user, local_group, idp)
unique_id (str, optional): ID of entity for reference by ID
Attributes:
name (str): name of identity
identity_type (OAAIdentityType): Veza Identity Type (local_user, local_group, idp)
application_permissions (list[CustomPermission]): List of permissions identity has directly to custom application
Add a permission to an identity.
Permission can apply to either the application or application resource/sub-resources
Args:
permissions ([str]): List of strings representing the permission names
resource (CustomResource, optional): Custom resource, if None permission is applied to application. Defaults to None.
apply_to_application
Add a role to an identity.
Role to authorize identity to either the application or application resource/sub-resource based on role's permissions.
Role assignment properties can be set with the assignment_properties dictionary parameter with property names as the keys. Role assignment properties types must be defined on the application prior to setting.
Args:
role (str): Name of role as string
resources (List[CustomResource], optional): Custom resource, if None role is applied to application. Defaults to None.
apply_to_application (bool, optional): Apply permission to application when True, False will replace existing value, None will leave previous setting if any
Add a new tag to identity.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Get a JSON serializable dictionary of all the identity's permissions and roles.
Formats the identity's permissions and roles for the Custom Application template payload
Returns:
dict: JSON serializable dictionary of all the identity's permissions and roles
Set a custom defined property to a specific value on an identity.
Property name must be defined for identity type before calling set_property(). See example below for LocalUser and ApplicationPropertyDefinitions.define_local_user_property for more information on defining properties. Property must be defined for the correct Identity type (LocalUser or LocalGroup, IdPIdentity does not support custom properties).
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
Raises:
OAATemplateException: If property with property_name is not defined.
LocalUser identity, derived from Identity base class.
Used to model an application user. Can be associated with an external IdP user, or represent a local account.
Args:
name (str): name of identity
identities (list): list of strings for IdP identity association
groups
Attributes:
name (str): name of identity
id (str): ID of entity for ID based reference
email (string): Users email address
Add access cred to user (access cred must be created separately)
Args:
access_cred (str): unique identifier of access cred
Add user to local group (group must be created separately).
Args:
group (str): identifier of local group
Add multiple identities to a local user from a list.
Args:
identities (list[str]): list of identities to add to user
Add an identity to user.
Identity should match the email address or another principal identifier for an IdP user (Okta, Azure, ect). Veza will create a connection from the application local user to IdP identity.
Args:
identity (str): email or identifier for IdP user
Add a permission to an identity.
Permission can apply to either the application or application resource/sub-resources
Args:
permissions ([str]): List of strings representing the permission names
resource (CustomResource, optional): Custom resource, if None permission is applied to application. Defaults to None.
apply_to_application
Add a role to an identity.
Role to authorize identity to either the application or application resource/sub-resource based on role's permissions.
Role assignment properties can be set with the assignment_properties dictionary parameter with property names as the keys. Role assignment properties types must be defined on the application prior to setting.
Args:
role (str): Name of role as string
resources (List[CustomResource], optional): Custom resource, if None role is applied to application. Defaults to None.
apply_to_application
Add a new tag to identity.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Get a JSON serializable dictionary of all the identity's permissions and roles.
Formats the identity's permissions and roles for the Custom Application template payload
Returns:
dict: JSON serializable dictionary of all the identity's permissions and roles
Set a custom defined property to a specific value on an identity.
Property name must be defined for identity type before calling set_property(). See example below for LocalUser and ApplicationPropertyDefinitions.define_local_user_property for more information on defining properties. Property must be defined for the correct Identity type (LocalUser or LocalGroup, IdPIdentity does not support custom properties).
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
Raises:
OAATemplateException: If property with property_name is not defined.
Derived from Identity base class. Used to represent groups of local users for application.
Args:
name (str): name of group
identities (list): list of strings for IdP identity association
unique_id
Attributes:
name (str): name of identity
identities (list): list of strings for IdP identity association
groups
Add a nested group to local group (group must be created separately).
Args:
group (str): identifier of local group
Add an identity to group.
The email address or another valid identifier should match that of an IdP principal (Okta, Azure, ect). Veza will create a connection from the application local group to IdP identity.
Args:
identity (str): primary IdP identifier for group to associate
Add a permission to an identity.
Permission can apply to either the application or application resource/sub-resources
Args:
permissions ([str]): List of strings representing the permission names
resource (CustomResource, optional): Custom resource, if None permission is applied to application. Defaults to None.
apply_to_application
Add a role to an identity.
Role to authorize identity to either the application or application resource/sub-resource based on role's permissions.
Role assignment properties can be set with the assignment_properties dictionary parameter with property names as the keys. Role assignment properties types must be defined on the application prior to setting.
Args:
role (str): Name of role as string
resources (List[CustomResource], optional): Custom resource, if None role is applied to application. Defaults to None.
apply_to_application (bool, optional): Apply permission to application when True, False will replace existing value, None will leave previous setting if any
Add a new tag to identity.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Get a JSON serializable dictionary of all the identity's permissions and roles.
Formats the identity's permissions and roles for the Custom Application template payload
Returns:
dict: JSON serializable dictionary of all the identity's permissions and roles
Set a custom defined property to a specific value on an identity.
Property name must be defined for identity type before calling set_property(). See example below for LocalUser and ApplicationPropertyDefinitions.define_local_user_property for more information on defining properties. Property must be defined for the correct Identity type (LocalUser or LocalGroup, IdPIdentity does not support custom properties).
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
Raises:
OAATemplateException: If property with property_name is not defined.
Used to associate IdP identities (users or groups) directly to resource where concept of local users/groups doesn't apply to application.
Args:
name (str): Primary IdP identifier for identity (email, group name, etc)
Attributes:
name (str): name of identity
identity_type (OAAIdentityType): Veza Identity Type, (idp)
application_permissions (list[CustomPermission]): permissions identity has directly to custom application
Add a permission to an identity.
Permission can apply to either the application or application resource/sub-resources
Args:
permissions ([str]): List of strings representing the permission names
resource (CustomResource, optional): Custom resource, if None permission is applied to application. Defaults to None.
apply_to_application
Add a role to an identity.
Role to authorize identity to either the application or application resource/sub-resource based on role's permissions.
Role assignment properties can be set with the assignment_properties dictionary parameter with property names as the keys. Role assignment properties types must be defined on the application prior to setting.
Args:
role (str): Name of role as string
resources (List[CustomResource], optional): Custom resource, if None role is applied to application. Defaults to None.
apply_to_application (bool, optional): Apply permission to application when True, False will replace existing value, None will leave previous setting if any
Add a new tag to identity.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Get a JSON serializable dictionary of all the identity's permissions and roles.
Formats the identity's permissions and roles for the Custom Application template payload
Returns:
dict: JSON serializable dictionary of all the identity's permissions and roles
Set custom IdP property (no functionality).
IdP identities do not support custom properties since the identity is discovered through the provider (Okta, Azure, etc)
Access Credential derived from Identity base class.
Access Creds can be used to represent non-user based methods that grant access such as API keys or integrations.
AccessCreds can be assigned roles or permissions to an application or resource. An AccessCred can stand-alone or be associated to a local user.
Args:
unique_id (str): Unique identifier for access cred
name (str): Name for access cred, does not need to be unique
Attributes:
unique_id (str): Unique identifier for access cred
name (str): Name for access cred, does not need to be unique
is_active (bool): Indicate if credential is active, defaults to True
Add a permission to an identity.
Permission can apply to either the application or application resource/sub-resources
Args:
permissions ([str]): List of strings representing the permission names
resource (CustomResource, optional): Custom resource, if None permission is applied to application. Defaults to None.
apply_to_application (bool): Apply permission to application when True, defaults to False
Add a role to an identity.
Role to authorize identity to either the application or application resource/sub-resource based on role's permissions.
Role assignment properties can be set with the assignment_properties dictionary parameter with property names as the keys. Role assignment properties types must be defined on the application prior to setting.
Args:
role (str): Name of role as string
resources (List[CustomResource], optional): Custom resource, if None role is applied to application. Defaults to None.
apply_to_application (bool, optional): Apply permission to application when True, False will replace existing value, None will leave previous setting if any
Add a new tag to identity.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Get a JSON serializable dictionary of all the identity's permissions and roles.
Formats the identity's permissions and roles for the Custom Application template payload
Returns:
dict: JSON serializable dictionary of all the identity's permissions and roles
Set a custom defined property to a specific value on an access credential.
Property name must be defined for access credentials before calling set_property(). See example below and ApplicationPropertyDefinitions.define_access_cred_property for more information on defining properties.
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none
Raises:
OAATemplateException: If property with property_name is not defined.
Local Roles are a collection of permissions (as CustomPermission). Roles can be used to associate a local user, group or IdP identity to an application, resource or sub-resource.
Permissions can either be assigned at creation and/or added later.
If the CustomPermission definition includes resource types in the resource_types list, the permission will only be assigned to resources/sub-resources that match that type as part of an assignment.
Args:
name (str): name of local role
permissions (list[CustomPermission], optional): List of custom permission names (strings) to associate with the role. Defaults to empty list.
unique_id (string, optional): Unique identifier for role for identification by ID
Attributes:
name (str): name of local role
unique_id (str): Unique identifier for role for identification by ID
permissions (list[CustomPermission]): list of custom permission names (strings) to associate with the role
Add a permission to the role.
Args:
permissions (list): List of permission names (strings) to add to role
Add a nested sub-role to the role (nested role must be created separately)
Args:
role (str): identifier of the local role to nest inside this role
Add a new tag to role.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set the value for custom property on a local role.
Property name must be defined for local roles before calling set_property(). See example below and ApplicationPropertyDefinitions.define_local_role_property for more information on defining properties.
Args:
property_name (str): Name of property to set value for
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none
Raises:
OAATemplateException: If property name is not defined.
Convert role to dictionary for inclusion in JSON payload.
Returns:
dict: serializable dictionary of role
CustomPermission class for defining CustomApplication permissions.
Custom permissions represent the named permissions for the application in its terms (e.g. "Admin" or "PUSH") and define the Veza canonical mapping (e.g. DataRead, MetadataRead, DataWrite).
A permission can either be applied directly to an application or resource or assigned as part of a role.
Optionally, when permissions are used as part of a role, if the resource_types list is populated the permission will only be applied to resources who's type is in the resource_types
Args:
name (str): Display name for permission
permissions (list): List of OAAPermission enums that represent the canonical permissions
apply_to_sub_resources (bool, optional): If true, when permission is applied to the application or resource, identity also has permission to all children of application/resource. Defaults to
Attributes:
name (str): Display name for permission
permissions (list[OAAPermission]): List of OAAPermission enums that represent the canonical permissions
apply_to_sub_resources (bool): If true, when permission is applied to the application or resource, identity also has permission to all children of application/resource.
Add a resource type to the resource_types list.
Extends the list of resource types permission applies to when used in role assignment.
Args:
resource_type (str): The resource type string value
Returns dictionary representation for payload.
Supported types for custom properties on OAA entities such as application, resource, and identity.
Model for defining custom properties for application and its entities (users, groups, roles, resources).
Property definitions define the names for additional entity properties and the expected type.
Args:
application_type (str): type of custom application property definitions apply to
Attributes:
application_properties (dict): property definitions for application
local_user_properties (dict): property definitions for local users
local_group_properties (dict): property definitions for local groups
Define an access cred property.
Args:
name (str): name for property
property_type (OAAPropertyType): type for property
Define an application property.
Args:
name (str): name for property
property_type (OAAPropertyType): type for property
Define a local group property.
Args:
name (str): name for property
property_type (OAAPropertyType): type for property
Define a local role property.
Args:
name (str): name for property
property_type (OAAPropertyType): type for property
Define a local user property.
Args:
name (str): name for property
property_type (OAAPropertyType): type for property
Define a property for a resource by type of resource.
Args:
resource_type (str): type of resource property definition is for
name (str): property name
property_type (OAAPropertyType): type for property
Return property definitions as dictionary ready for OAA payload
Check property name for valid characters
Raises an exception if the name string does not match required pattern. Name must start with a character and can only contain letters and _ character.
Args:
name (str): name of property to validate
Raises:
OAATemplateException: Name is not a string
OAATemplateException: Name contains invalid characters or does not start with a letter
Validate that a property name has been defined for given resource type.
Args:
property_name (str): name of property to validate
entity_type (str): type of entity custom property is for (application, local_user, local_group, local_role, resource)
resource_type (str): (optional) type for validating resource property names, only applicable to entity_type resource
Raises:
OAATemplateException: If property name has not been previously defined for entity
IdP entity types.
Veza supported IdP provider types.
CustomIdPProvider class for modeling Identity Providers (IdP) using OAA Custom Identity Provider Template.
CustomIdPProvider class consists of IdP domain information, user, group and external associations for identities like AWS Roles.
Classes uses dictionaries to track most components, dictionaries are all keyed by string of the entity name
Args:
name (str): Name of IdP
idp_type (str): Type descriptor for IdP, can be unique or share across multiple IdP e.g. ldap, IPA
domain (str): IdP domain name
Attributes:
name (str): Name of custom IdP
idp_type (str): Type for IdP
description (str): Description for IdP
summary
Args:
id (str): description
name (str): description
Raises:
Returns:
CustomIdPApp: description
Add group to IdP.
Arguments:
name (str): primary ID for group
full_name (str): optional display name for group
identity (str): optional unique identifier for group, if None name is used as identity
Add user to IdP
if no identity is set name will be used as identity
Arguments:
name (str): primary ID for user
full_name (str): optional full name for display
email (str): optional email for user
Returns: CustomIdPUser
Return formatted payload as dictionary for JSON conversion and upload
Domain model for Custom IdP provider.
Args:
name (str): domain name
Attributes:
name (str): domain name
Add a new tag to IdP Domain.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set custom property value for domain.
Property name must be defined for domain before calling set_property(). See example below and IdPPropertyDefinitions.define_domain_property for more information.
Args:
property_name (str): Name of property
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
id (str): ID of App assignment, must be unique for user
name (str): Name of assignment
app_id (str): App ID, must exist in list of Apps for IDP
Raises:
OAATemplateException: Duplicate assignment ID
OAATemplateException: Unknown assignment property name
Add AWS Roles to list of roles user can assume by ARN.
Args:
arns (list): list of role ARNs as strings that the user is allowed to assume
Add user to group(s) by group name
Args:
group_identities (list): list of strings for group identities to add user to
Add a new tag to IdP User.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set custom property value for user.
Property name must be defined for users before calling set_property(). See example below and IdPPropertyDefinitions.define_user_property for more information.
Args:
property_name (str): Name of property
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
source_identity will connect CustomIdP user to a Veza graph IdP user.
provider_type limits scope for finding matching IdP identities
search all providers with IdPProviderType.ANY.
Args:
identity (str): Unique Identity of the source identity
provider_type (IdPProviderType): Type for provider to match source identity from
Function to prepare user entity for payload
Group model for CustomIdPProvider.
Args:
name (str): name of group
full_name (str): optional full name for group
identity (str): optional identifier for group if name is not reference identifier
Parameters:
name (str): name of group
full_name (str): optional full name for group
identity (str): optional identifier for group, if None name is used as identity
Create App assignment for group
Args:
id (str): ID of App assignment, must be unique for group
name (str): Name of assignment
app_id (str): App ID, must exist in list of Apps for IDP
Raises:
OAATemplateException: Duplicate assignment ID
OAATemplateException: Unknown assignment property name
Add AWS Roles to list of roles group members can assume by ARN.
Args:
arns (list): list of role ARNs as strings that the group members are allowed to assume
Add group to group(s) by group name
Adds current group to another parent group by the group identifier
Args:
group_identities (list): list of strings for group identities to add group to
Add a new tag to IdP Group.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set custom property value for group.
Property name must be defined for groups before calling set_property(). See example below and IdPPropertyDefinitions.define_group_property for more information.
Args:
property_name (str): Name of property
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
property_definitions (IdPPropertyDefinitions, optional): Custom property definitions, required to set custom properties. Defaults to None.
Attributes:
id (str): ID for App, must be unique
name (str): Name for App
description (str): Description property for App
Add AWS Roles to list of roles App can assume by ARN. Any Users or Groups assigned to the App are represented as being able to assume the roles.
Args:
arns (list): list of role ARNs as strings that the user is allowed to assume
Add a new tag to IdP User.
Args:
key (str): Key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for Tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only. Defaults to "".
Set custom property value for app.
Property name must be defined for app before calling set_property(). See example below and IdPPropertyDefinitions.define_app_property for more information.
Args:
property_name (str): Name of property
property_value (Any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
Model for defining custom properties for CustomIdPProvider and its entities (users, groups, domain).
Property definitions define the names for additional entity properties and the expected type.
Attributes:
domain_properties (dict): property definitions for IdP Domain
user_properties (dict): property definitions for IdP users
group_properties (dict): property definitions for IdP groups
Define an app assignment custom property
Args:
name (str): name of property
property_type (OAAPropertyType): type for property
Define an app custom property
Args:
name (str): name of property
property_type (OAAPropertyType): type for property
Define a domain custom property.
Args:
name (str): name of property
property_type (OAAPropertyType): type for property
Define a group custom property.
Args:
name (str): name of property
property_type (OAAPropertyType): type for property
Define a user custom property.
Args:
name (str): name of property
property_type (OAAPropertyType): type for property
Returns custom IdP property definitions.
Validate that a property name has been defined for a given IdP entity.
Raises exception if property name has not been previously defined for entity
Args:
property_name (str): name of property to validate
entity_type (str): type of entity custom property is for (domain, users, groups)
Raises:
OAATemplateException: If property name is not defined
Veza Tag data model.
Args:
key (str): key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str, optional): Value for tag, will appear in Veza as key:value. Must be letters, numbers, whitespace and the special characters @,._- only.
Attributes:
key (str): key for tag, aka name. Must be present and must be letters, numbers or _ (underscore) only.
value (str): Value for tag, will appear in Veza as key:value. Must be letters, numbers and the special characters @,._ only.
Class for modeling Human Resource Information Systems (HRIS) Template
HRIS template consists of base information about the HRIS instance, Employees and Groups.
Employees and Groups are tracked in case insensitive dictionaries that can be used to reference entities after creation.
Args:
name (str): Name for HRIS Instance
hris_type (str): Type for HRIS. Typically the vendor or product name.
url (str): Instance URL for HRIS.
Attributes:
employees (dict[string]): Dictionary of HRISEmployee instances keyed by Employee ID
groups (dict[string]): Dictionary of HRISGroup instances keyed by Group ID
Add a new Employee
Function creates a new HRISEmployee instance and adds it to the HRISProvider.employees keyed by the unique_id
Args:
unique_id (str): Unique Identifier for Employee
name (str): Display name for employee
employee_number (str): The employee's number that appears in the third-party integration.
Raises:
OAATemplateException: Employee with ID already exists
Returns:
HRISEmployee: Entity for new employee
Add a new Group
Used to represent any subset of employees, such as PayGroup or Team. Employees can be in multiple Groups. Groups can also be members of other groups to create hierarchy.
Some properties of HRISEmployee such as department must reference an existing HRISGroup by its ID.
Args:
unique_id (str): Unique ID for group
name (str): Display name
group_type (str): Type for group such as "Team", "Department", "Cost Center"
Returns:
HRISGroup: Entity for new group
Get the OAA payload.
Returns the complete OAA template payload for HRIS as serializable dictionary
Returns:
dict: OAA payload as dictionary
HRISSystem information
Representation for HRISSystem information. The system information is used to represent additional details for the HRIS Instance.
Args:
name (str): Name for system Instance
url (str, optional): URL for instance . Defaults to "". TODO: Is this right?
Link HRIS to External IdP of given type
Sets the IdP types (Okta, AzureAD, ect) for Veza to link employee identities too.
Args:
provider_type (IdPProviderType): Type of IdP for source identities
Raises:
ValueError: provider_type must be IdPProviderType enum
Returns:
list[IdPProviderType]: List of configured IdP types
HRIS Employee Entity
Represents an employee record in the HRIS system. Each employee must have a unique ID to identify it in the payload. This ID is also used to reference one employee to the other for manager hierarchy.
Init variables are all required and must not be empty such as ""
Args:
unique_id (str): Unique Identifier for Employee
name (str): Name for employee record.
employee_number (str): The employee's number that appears in the third-party integration.
Parameters:
company (str): The company (or subsidiary) the employee works for.
preferred_name (str): The employee's preferred first name.
display_full_name (str): The employee's full name, to use for display purposes.
Raises:
ValueError: Any of the required arguments are empty.
Add employee to group
Adds employee to a group by the group ID. Group must also be defined for HRISInstance with HRISProvider.add_group()
Args:
group_id (str): Unique ID of HRISGroup to add employee too
Add manager to Employee
Adds a manager to the employee by the manager's HRISEmployee instance unique ID. Manger employee record must also exist.
Args:
manager_id (str): Unique ID for manager HRISEmployee instance
Set Employee custom property value
Property name must be defined for employee before calling set_property
Args:
property_name (str): Name of property
property_value (any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
Output employee to dictionary for payload.
HRIS Group
Represents any group of employees in the HRIS system. HRISGroups can be used to represent teams, departments, cost centers or any organizational unit. Each group has a type to make searching and grouping easier.
Group's Unique ID must be unique across all group types.
Args:
unique_id (str): Unique ID for group
name (str): Display name
group_type (str): Type for group such as "Team", "Department", "Cost Center"
Set HRIS Group custom property value
Property name must be defined for group before calling set_property
Args:
property_name (str): Name of property
property_value (any): Value for property, type should match OAAPropertyType for property definition
ignore_none (bool, optional): Do not set property if value is None. Defaults to False.. Defaults to False.
Raises:
OAATemplateException: If property with property_name is not defined.
Dictionary output for inclusion in payload
Check property name for valid characters
Raises an exception if the name string does not match required pattern. Name must start with a character and can only contain letters and _ character.
Args:
name (str): name of property to validate
Raises:
OAATemplateException: Name is not a string
OAATemplateException: Name contains invalid characters or does not start with a letter
identity_to_permissions (dict): Mapping of authorizations for identities to resources
idp_identities (dict[IdPIdentity]): Contains federated identities without a corresponding local account
local_groups (dict[LocalGroup]): Contains application groups (collections of users)
local_roles (dict[LocalRole]): Contains application roles (collections of permissions)
local_users (dict[LocalUser]): Contains users local to the application and their properties
name (str): Name of custom application
properties (dict): key value pairs of property values, property keys must be defined as part of the property_definitions
property_definitions (ApplicationPropertyDefinitions): Custom property names and types for the application
resources (dict[CustomResource]): Contains data resources and subresources within the application
(bool, optional): If true, when permission is applied to the application or resource, identity also has permission to all children of application/resource. Defaults to False.
resource_types (list, optional): List of resource types as strings that the permission relates to. Defaults to empty list.
(str, optional): Unique identifier for group for reference by ID
Local roles can be referenced after creation if needed through .local_roles case insensitive dictionary attribute.
When a permission that has resource_types is added to a role, it will only apply to resources with a matching resource_type
unique_id (str, optional): Unique identifier for role for reference by ID
(list[LocalGroup]): List of group names (as string) to add user to
unique_id (str, optional): Unique identifier for user for reference by ID
unique_id (str, optional): Unique identifier for resource. defaults to None.
(bool, optional): Do not set property if value is None. Defaults to False.
(str): description for resource
application_name (str): name of parent application
resource_key (str, optional): for sub-resources the full unique identifier required for identity_to_permissions section. Defaults to name or unique_id if not provided.
property_definitions (ApplicationPropertyDefinitions, optional): Property definitions structure for the resource
unique_id (str, optional): Optional unique identifier for the resource. Defaults to None.
(str): type for resource
application_name (str): name of parent application
resource_key (str): for sub-resources represents the sub-resource's parent path
sub_resources (dict): dictionary of sub-resources keyed by name
properties (dict): dictionary of properties set for resource
tags (list[Tag]): list of tags
unique_id (str, optional): Unique identifier for new subresource, Defaults to name.
(bool, optional): Do not set property if value is None. Defaults to False.
resource_permissions (dict): Dictionary of custom permissions associated with resources and sub-resources. Key is permission, value is list of resource keys
application_roles (LocalRole): List of roles identity has directly to custom application
resource_roles (dict): Dictionary of local_roles for resources and sub-resources. Key is roles, value is list of resource keys
properties (dict): Dictionary of properties for identity, allowed values will vary by identity type
tags (list[Tag]): List of tags
(bool): Apply permission to application when True, defaults to False
assignment_properties (dict, optional): Custom properties for the role assignment. Defaults to no properties.
ignore_none
(bool, optional): Do not set property if value is None. Defaults to False.
(list[LocalGroup]): list of group names as strings to add user too
unique_id (string, optional): For reference by ID
identities (list): list of strings for IdP identity association
groups (list[LocalGroup]): list of group names as strings to add user too
identity_type (OAAIdentityType): Veza Identity Type (local_user)
application_permissions (list[CustomPermission]): Permissions identity has directly to custom application
resource_permissions (dict): Dictionary of custom permissions associated with resources and sub-resources. Key is permission, value is list of resource keys
application_roles (list[LocalRole]): Custom application roles assigned directly to the identity
resource_roles (dict): Dictionary of local_roles for resources and sub-resources. Key is roles, value is list of resource keys
properties (dict): Dictionary of properties for identity, allowed values will vary by identity type
tags (list[Tag]): List of tags
is_active (bool): Defaults to None for unset
created_at (str): RFC3339 time stamp for user creation
last_login_at (str): RFC3339 time stamp for last login
deactivated_at (str): RFC3339 for user deactivate time
password_last_changed_at (str): RFC3339 time stamp for last password change
user_type (LocalUserType): Set the local user account type
(bool): Apply permission to application when True, defaults to False
(bool, optional): Apply permission to application when True, False will replace existing value, None will leave previous setting if any
assignment_properties (dict, optional): Custom properties for the role assignment. Defaults to no properties.
ignore_none
(bool, optional): Do not set property if value is None. Defaults to False.
(string, optional): Unique identifier for group
(list[LocalGroup]): list of group names as strings that group is member of for nested groups
identity_type (OAAIdentityType): Veza Identity Type, local_group
application_permissions (list[CustomPermission]): permissions identity has directly to custom application
resource_permissions (dict): Dictionary of custom permissions associated with resources and sub-resources. Key is permission, value is list of resource keys
application_roles (list[LocalRole]): list of roles identity has directly to custom application
resource_roles (dict): Dictionary of local_roles for resources and sub-resources. Key is roles, value is list of resource keys
properties (dict): Dictionary of properties for identity, allowed values will vary by identity type
tags (list[Tag]): List of tags
created_at (str): RFC3339 time stamp for group creation time
(bool): Apply permission to application when True, defaults to False
assignment_properties (dict, optional): Custom properties for the role assignment. Defaults to no properties.
ignore_none
(bool, optional): Do not set property if value is None. Defaults to False.
resource_permissions (dict): Dictionary of custom permissions associated with resources and sub-resources. Key is permission, value is list of resource keys
application_roles (list[LocalRole]): roles identity has directly to custom application
resource_roles (dict): Dictionary of local_roles for resources and sub-resources. Key is roles, value is list of resource keys
properties (dict): Dictionary of properties for identity, allowed values will vary by identity type
tags (list[Tag]): List of tags
(bool): Apply permission to application when True, defaults to False
assignment_properties (dict, optional): Custom properties for the role assignment. Defaults to no properties.
created_at (str): Time access cred was created at as RFC3339 timestampe, defaults to empty
expires_at (str): Time access cred was created at as RFC3339 timestampe, defaults to empty
last_used_at (str): Time access cred was created at as RFC3339 timestampe, defaults to empty
can_expire (bool): Boolean to indicate if credential type can exipre, defaults to unset
assignment_properties (dict, optional): Custom properties for the role assignment. Defaults to no properties.
(bool, optional): Do not set property if value is None. Defaults to False.
roles (list[LocalRole]): list of roles nested inside the role
tags (list[Tag]): list of Tags instances
(bool, optional): Do not set property if value is None. Defaults to False.
list when the role is applied to a resource.
False
.
resource_types (list, optional): List of resource types as strings that the permission relates to. Defaults to empty list.
resource_types (list): List of resource types as strings that the permission relates to.
local_role_properties (dict): property definitions for local roles
resources (dict): property definitions for resources keyed by resource type
description (str, optional): Description for IdP. Defaults to None.
domain (CustomIdPDomain): Domain model, created with domain name at init
users (dict[CustomIdPUser]): Dictionary of CustomIdPUser class instances
groups (dict[CustomIdPGroup]): Dictionary of CustomIdPGroup class instances
property_definitions (IdPPropertyDefinitions): Custom Property definitions for IdP instance
identity (str): optional unique identifier for user, if None name is used as identity
identity (str): unique identifier for user (may be same as username or email, or another unique ID like employee number)
identity (str): unique identifier for user (may be same as username or email, or another unique ID like employee number)
department (str): department name for user
is_active (bool): if user is active, defaults to None
is_guest (bool): if user is a guest type user, defaults to None
manager_id (str, optional): CustomIdPUser.identity of manager, defaults to None
assignment_properties (Optional[dict], optional): Optional custom properties to set. Property names must be defined first. Defaults to None.
is_security_group (bool): Property for group, defaults to None (unset)
assignment_properties (Optional[dict], optional): Optional custom properties to set. Property names must be defined first. Defaults to None.
first_name (str): Employee first name
last_name (str): Employee last name (family name)
is_active (bool): Boolean for employee active status
employment_status (str): String representation of employee status, e.g. "ACTIVE", "TERMINATE", "PENDING"
first_name (str): Employee first name
last_name (str): Employee last name (family name)
is_active (bool): Boolean for employee active status
employment_status (str): String representation of employee status, e.g. "ACTIVE", "TERMINATE", "PENDING"
canonical_name (str): The employee's canonical name.
username (str): The employee's username that appears in the integration UI.
email (str): The employee's work email.
idpid (str): The ID for this employee on the destination IDP provider used to automatically connect to it, if not supplied email is used.
personal_email (str): The employee's personal email.
home_location (str): The employee's home location.
work_location (str): The employee's work location.
cost_center (str): The cost center ID (Group ID) that the employee is in.
department (str): The department ID (Group ID) that the employee is in.
managers (str): The employee IDs of the employee's managers.
groups (str): The IDs of groups this user is in
start_date (str): The date that the employee started working. RFC3339 timestamp.
termination_date (str): The employee's termination date. RFC3339 timestamp.
job_title (str): The title of the employee.
employment_typ (str): The employee's type of employment. For example: FULL_TIME, PART_TIME, INTERN, CONTRACTOR, FREELANCE.
primary_time_zone (str): The time zone which the employee primarily lives.