#Official Authzee SDKs
Authzee official SDKs offer the same general API's and architecture. This makes it easier to switch languages by standardizing SDK patterns, and still leave room for language specific functionality and syntax.
They offer a flexible and scalable general purpose interface, but they are opinionated in their APIs.
If this doesn't fit your use case you are free to create your own! Try to stay compliant with the Authzee spec for the sake of portability.
NOTE - This document is not a specification but a list of recommendations. It may change and will not effect the specification or specification version of Authzee.
#Available SDKs
SDKs are considered:
- Authzee Compliant - Follows the Authzee specification.
- Maintained - Actively maintained.
- SDK Standard - Follows the Authzee SDK standard. It's not a bad thing if the library does not follow the standard. You can expect a different interface than the official SDKs.
- Official - Branded as the official Authzee SDK for a language. Again, not a bad thing if the library isn't official.
| Language | Code Repo | Package Repo | Authzee Compliant | Maintained | SDK Standard | Official | Notes |
|---|---|---|---|---|---|---|---|
| python | btemplep/authzee-py | authzee - pypi.org | ✅ | ✅ | ✅ | ✅ |
#Table of Contents
- Example
- SDK Standards
- SDK Full Example
- Standard JMESPath Extensions
- INNER JOIN - Join 2 arrays in a fashion similar to an SQL INNER JOIN.
- LEFT JOIN - Join 2 arrays in a fashion similar to an SQL LEFT JOIN.
- OUTER JOIN - Join 2 arrays in a fashion similar to an SQL OUTER JOIN.
- Is Identity Present - Check if the given identity type is in the request and at least one instance was given.
- regex Find - Run a regex pattern on a string or array of strings to find the first match.
- regex Find All - Run a regex pattern on a string or array of strings to find all matches.
- regex Groups - Run a regex pattern on a string or array of strings to find the first match, and extract the groups.
- regex Groups All - Run a regex pattern on a string or array of strings to find all matches, and extract the groups.
- String Lower - Convert string to lower case.
- String Upper - Convert string to upper case.
#Example
from authzee import Authzee, InProcessCompute, InProcessStorage, jmespath_execute, paginator
storage = {}
authz = Authzee(
execute=jmespath_execute,
compute_type=InProcessCompute,
compute_kwargs={},
storage_type=InProcessStorage,
storage_kwargs={
"storage_ptr": storage
},
config={
"authzee": {
"raise_errors": True
}
}
)
authz.construct()
# authz.destroy()
authz.start()
# authz.shutdown()
context_def = {
"context_type": "Team",
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"Team"
],
"properties": {
"Team": {
"type": "string"
}
}
}
}
authz.put_context_def(context_def)
# authz.delete_context_def(context_def["context_type"])
identity_def = {
"identity_type": "User",
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"username",
"email",
"department"
],
"properties": {
"username": {
"type": "string"
},
"email": {
"type": "string"
},
"department": {
"type": "string"
}
}
}
}
authz.put_identity_def(identity_def)
# authz.delete_identity_def(identity_def["identity_type"])
authz.put_resource_def(
{
"resource_type": "Balloon",
"actions": [
"Balloon:Inflate",
"Balloon:Deflate",
"Balloon:ListBalloons"
],
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"color",
"size",
"psi",
"is_inflated"
],
"properties": {
"color": {
"type": "string",
"enum": [
"green",
"purple"
]
},
"size": {
"type": "number",
"minimum": 0
},
"psi": {
"type": "number",
"minimum": 0,
"description": "Pounds per square inch of inflated air."
},
"is_inflated": {
"type": "boolean"
}
}
}
}
)
# authz.delete_resource_def("Balloon")
for page in paginator(authz.list_context_defs):
for context_def in page.context_defs:
print(context_def)
for page in paginator(authz.list_identity_defs):
for identity_def in page.identity_defs:
print(identity_def)
for page in paginator(authz.list_resource_defs):
for resource_def in page.resource_defs:
print(resource_def)
grant = authz.enact(
{
"name": "Balloon Sales and maintenance Inflate",
"description": "Allow people in the Balloon Sales and Maintenance departments to inflate balloons.",
"tags": {
"SomeKey": "SomeVal"
},
"effect": "allow",
"actions": [
"Balloon:Inflate"
],
"query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
"equality": True,
"data": {
"allowed_departments": [
"Maintenance",
"Balloon Sales"
]
}
}
)
# authz.repeal(grant["grant_uuid"], purge=False)
for page in paginator(authz.list_grants, effect="allow"):
for g in page.grants:
print(g)
for page in paginator(authz.list_grant_refs):
for ref in page.grant_refs:
print(ref)
request = {
"identities": {
"User": [
{
"username": "tester",
"email": "tester@example.com",
"department": "Balloon Sales"
}
]
},
"action": "Balloon:Inflate",
"resource_type": "Balloon",
"resource": {
"color": "green",
"size": 2.7,
"psi": 7.2,
"is_inflated": True
},
"context_type": "Team",
"context": {
"Team": "My Team"
}
}
authorize_result = authz.authorize(request)
print(authorize_result)
# {
# "is_authorized": True,
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales and maintenance Inflate",
# "description": "Allow people in the Balloon Sales and Maintenance departments to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
# "error": None
# }
audit_result = authz.audit(
request,
effect="allow",
action="Balloon:Inflate",
page_ref=None
)
print(audit_result)
# {
# "results": [
# {
# "is_applicable": True,
# "query_result": True,
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales and maintenance Inflate",
# "description": "Allow people in the Balloon Sales and Maintenance departments to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "failure": None
# }
# ],
# "error": None,
# "next_page_ref": None
# }
batch_request = {
"identities": {
"User": [
{
"username": "tester",
"email": "tester@example.com",
"department": "Balloon Sales"
}
]
},
"action": "Balloon:Inflate",
"resource_type": "Balloon",
"resource": {
"color": "green",
"size": 2.7,
"psi": 7.2,
"is_inflated": True
},
"context_type": "Team",
"context": {
"Team": "My Team"
},
"batch": [
{},
{
"identities": {
"User": [
{
"username": "tester2",
"email": "tester2@example.com",
"department": "Balloon Popper"
}
]
}
}
]
}
batch_authorize_result = authz.batch_authorize(batch_request)
print(batch_authorize_result)
# {
# "batch": [
# {
# "is_authorized": True,
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales and maintenance Inflate",
# "description": "Allow people in the Balloon Sales and Maintenance departments to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
# "error": None
# },
# {
# "is_authorized": False,
# "grant": None,
# "message": "No grants are applicable to the request. Therefore, the request is implicitly denied and is not authorized.",
# "error": None
# }
# ],
# "error": None
# }
batch_audit_result = authz.batch_audit(
batch_request,
effect="allow",
action="Balloon:Inflate",
page_ref=None
)
print(batch_audit_result)
# {
# "results": [
# {
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales and maintenance Inflate",
# "description": "Allow people in the Balloon Sales and Maintenance departments to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "batch": [
# {
# "is_applicable": True,
# "query_result": True,
# "failure": None
# },
# {
# "is_applicable": False,
# "query_result": False,
# "failure": None
# }
# ]
# }
# ],
# "error": None,
# "next_page_ref": None
# }
#SDK Standards
The following sections outline Authzee SDK standards. All examples are given in python or JSON with python naming conventions, but the SDKs should change this based on the convention of the language.
The suggested architecture for the high level API of SDKs is to have a primary class, Authzee, and create instances from it. This class provides the only public API to the Authzee SDKs.
Under this object, the JSON query search function is static. The Authzee object is created with a compute module and a storage module. The compute module will be used to provide the compute resources for running operations, and the storage module will be used to store and retrieve grants and other compute state objects.
NOTE - The Standard describes the minimum expectations of what an Authzee SDK should meet. SDKs are welcome to have more functionality!!!
- Language Translations
- Low Level API
- Authzee Class
- Compute Modules
- Storage Modules
- Module Locality
- Storage Latches
- Handling Errors
- Standard Types
#Language Translations
These docs will use python as the example language. For languages that don't support Classes and methods, translate as well as you can:
- Classes -> opaque struct definitions
- Class instances or objects -> struct instances
- Methods -> struct methods or functions that act on a struct
Function/method parameter are expected to be able to grow for all methods/functions and for class/struct instantiation. For languages that don't support all of these features like C and Rust:
- Authzee structs should be opaque and only created with a function
- All methods should accept the Authzee struct pointer, required params, and an opaque struct for optional and future arguments.
In the examples, the most simple python types and data structures are given for clarity. SDKs are free to change simple types like str to UUID. They can also change complex types like dicts to structs, classes, data classes etc. As long as they support adding fields without breaking the existing API.
#Low Level API
Authzee SDKs should offer both a high and low level APIs.
The majority of this document will focus on the high level APIs that are more easily consumed.
The low level APIs should also exist, and directly follow the specification/reference for Authzee. This is to give a core point of logic for the higher level APIs, and the ability to use a Authzee specification-like interface directly.
It should include these variables to import:
authzee_specification_version- The latest version of the Authzee specification supported.context_definition_schema- Context Definition Schemaidentity_definition_schema- Identity Definition Schemaresource_definition_schema- Resource Definition Schemagrant_schema- Grant Schemageneric_error_schema- Generic Error Schemageneral_result_schema- General Result Schemarequest_schema- Authzee Request Schemaquery_execute_result_schema- Return value schema for the query execute functionevaluate_one_result_schema- Return value schema for theevaluate_onefunctionaudit_result_schema- Return value schema for theauditoperation/functionauthorize_result_schema- Return value schema for theauthorizeoperation/functionbatch_request_schema- Authzee Batch Request Schemavalidate_request_result_schema- Return value schema for thevalidate_requestfunctionvalidate_batch_request_result_schema- Return value schema for thevalidate_batch_requestfunctionbatch_audit_result_schema- Return value schema for thebatch_auditoperation/functionbatch_authorize_result_schema- Return value schema for thebatch_authorizeoperation/function
It should include these functions from the authzee reference:
def validate_context_defs(context_defs: List[Dict[str, AnyJSON]]) -> Dict[str, AnyJSON]:
def validate_identity_defs(identity_defs: List[Dict[str, AnyJSON]]) -> Dict[str, AnyJSON]:
def validate_resource_defs(resource_defs: List[Dict[str, AnyJSON]]) -> Dict[str, AnyJSON]:
def validate_grants(
grants: List[Dict[str, AnyJSON]]
) -> Dict[str, AnyJSON]:
def validate_request(
request: Dict[str, AnyJSON],
context_defs: List[Dict[str, AnyJSON]],
identity_defs:List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]]
) -> Dict[str, AnyJSON]:
def validate_batch_request(
batch_request: Dict[str, AnyJSON],
context_defs: List[Dict[str, AnyJSON]],
identity_defs:List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]]
) -> Dict[str, AnyJSON]:
def evaluate_one(
request: Dict[str, AnyJSON],
grant: Dict[str, AnyJSON],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
The evaluate_one function is for evaluating a request against one grant.
def audit(
request: Dict[str, AnyJSON],
grants: List[Dict[str, AnyJSON]],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, List[Dict[str, AnyJSON]]]:
NOTE -
auditandauthorizefunctions do not run the validation steps before the core operation.
def authorize(
request: Dict[str, AnyJSON],
grants: List[Dict[str, AnyJSON]],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
NOTE - Workflow functions perform all steps that need to be done for an operation. They will return different result depending on if there are failures. The are included as a way to easily test low level functionality and are just a simplification of the spec.
def audit_workflow(
context_defs: List[Dict[str, AnyJSON]],
identity_defs: List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]],
grants: List[Dict[str, AnyJSON]],
request: Dict[str, AnyJSON],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
def authorize_workflow(
context_defs: List[Dict[str, AnyJSON]],
identity_defs: List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]],
grants: List[Dict[str, AnyJSON]],
request: Dict[str, AnyJSON],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
def batch_audit(
batch_request: Dict[str, AnyJSON],
grants: List[Dict[str, AnyJSON]],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, List[Dict[str, AnyJSON]]]:
NOTE -
batch_auditandbatch_authorizefunctions do not run the validation steps before the core operation.
def batch_authorize(
batch_request: Dict[str, AnyJSON],
grants: List[Dict[str, AnyJSON]],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, List[Dict[str, AnyJSON]]]:
def batch_audit_workflow(
context_defs: List[Dict[str, AnyJSON]],
identity_defs: List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]],
grants: List[Dict[str, AnyJSON]],
batch_request: Dict[str, AnyJSON],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
def batch_authorize_workflow(
context_defs: List[Dict[str, AnyJSON]],
identity_defs: List[Dict[str, AnyJSON]],
resource_defs: List[Dict[str, AnyJSON]],
grants: List[Dict[str, AnyJSON]],
batch_request: Dict[str, AnyJSON],
execute: Callable[[str, AnyJSON], AnyJSON]
) -> Dict[str, AnyJSON]:
#Authzee Class
The Authzee class is the primary public API for the SDK. It wraps compute and storage modules and provides all authorization operations.
The Authzee class should take these arguments when created:
- JSON query execute function
- Compute Module type and arguments
- keyword args where available, or else ordered arguments
- Storage Module type and arguments
- keyword args where available, or else ordered arguments
- Compute storage kwargs (optional) - override storage kwargs that the compute module will use. Only include kwargs you want to override.
- Authzee Config override or null to take defaults.
If the language supports async, there should also be an AuthzeeAsync variant. AuthzeeAsync has the same constructor signature and methods as Authzee, but all methods are async.
#Authzee Config
Config is organized per-method — each root key corresponds to a method name and holds that method's specific setting. The authzee root key is for general Authzee instance settings.
Authzee instances have a default set of configs.
The configs can be changes by passing them when creating an instance.
Every method on the Authzee class (and AuthzeeAsync) accepts a config parameter. This allows overriding configuration at the call-level without changing the instance-level configuration.
#Config Precedence
Configuration is resolved through 3 levels (least to most precedence):
- Default config values — The built-in defaults shown below.
- Instance-level config — Passed via the
configparameter atAuthzeeconstruction. Only provided keys override the defaults. - Method-call config override — Passed via the
configparameter on any method call. Only provided keys override the resolved instance config.
Only the keys you provide at a higher-precedence level override the values from the lower level. Everything else keeps its resolved value.
#AuthzeeConfig Full Example - All Defaults
{
"authzee": {
"raise_errors": True
},
"start": {
"compute_start": {
"storage": {}
},
"storage_start": {}
},
"shutdown": {
"compute_shutdown": {
"storage": {}
},
"storage_shutdown": {}
},
"construct": {
"compute_construct": {},
"storage_construct": {}
},
"destroy": {
"compute_destroy": {},
"storage_destroy": {}
},
"validate_context_def": {},
"list_context_defs": {
"page_size": 100,
"use_cache": False
},
"get_context_def": {
"use_cache": False
},
"put_context_def": {},
"delete_context_def": {},
"validate_identity_def": {},
"list_identity_defs": {
"page_size": 100,
"use_cache": False
},
"get_identity_def": {
"use_cache": False
},
"put_identity_def": {},
"delete_identity_def": {},
"validate_resource_def": {},
"list_resource_defs": {
"page_size": 100,
"use_cache": False
},
"get_resource_def": {
"use_cache": False
},
"put_resource_def": {},
"delete_resource_def": {},
"validate_grant": {},
"list_grants": {
"page_size": 100,
"use_cache": False
},
"get_grant": {
"use_cache": False
},
"enact": {},
"repeal": {},
"list_grant_refs": {
"page_size": 10,
"use_cache": False
},
"cleanup_latches": {},
"validate_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"validate_batch_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"audit": {
"validate_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"list_grants": {
"page_size": 100,
"use_cache": True
}
},
"batch_audit": {
"validate_batch_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"list_grants": {
"page_size": 100,
"use_cache": True
}
},
"authorize": {
"validate_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"list_grants": {
"page_size": 100,
"use_cache": True
},
"parallel_paging": True,
"list_grant_refs": {
"page_size": 10,
"use_cache": True
}
},
"batch_authorize": {
"validate_batch_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"validate_request": {
"get_context_def": {
"use_cache": True
},
"use_list_context_defs": True,
"list_context_defs": {
"page_size": 100,
"use_cache": True
},
"get_identity_def": {
"use_cache": True
},
"use_list_identity_defs": True,
"list_identity_defs": {
"page_size": 100,
"use_cache": True
},
"get_resource_def": {
"use_cache": True
},
"use_list_resource_defs": True,
"list_resource_defs": {
"page_size": 100,
"use_cache": True
}
},
"list_grants": {
"page_size": 100,
"use_cache": True
},
"parallel_paging": True,
"list_grant_refs": {
"page_size": 10,
"use_cache": True
}
}
}
These are the methods for the Authzee class. For the AuthzeeAsync class, they should all be async.
class Authzee:
def __init__(
self,
execute: Callable[[str, Any], Any],
compute_type: Type[ComputeModule],
compute_kwargs: Dict[str, Any],
storage_type: Type[StorageModule],
storage_kwargs: Dict[str, Any],
config: AuthzeeConfigOverride | None = None
):
pass
def start(self, config: AuthzeeConfigOverride | None = None) -> GenericResult:
"""Start up Authzee app.
- Initialize runtime resources
- Needs to run before any methods or vars are accessed.
- Run the same method for compute and storage modules.
- After this method is complete these public instance vars or getters must be available:
- locality - Authzee [Module Locality](#module-locality) to tell the limit of where other Authzee instances can be created.
- has_parallel_paging - if the instance of Authzee supports processing grant pages in parallel according to the compute and storage combination.
"""
pass
def shutdown(self, config: AuthzeeConfigOverride | None = None) -> GenericResult:
"""Shutdown the authzee app. Cleans up runtime resources.
"""
pass
def construct(self, config: AuthzeeConfigOverride | None = None) -> GenericResult:
"""Construct backend resources for compute and storage
One time setup.
"""
pass
def destroy(self, config: AuthzeeConfigOverride | None = None) -> GenericResult:
"""Destroy down backend resources.
destructive - may lose all storage and compute etc.
"""
pass
def list_context_defs(
self,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> ContextDefsPage:
"""Get a page of context definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
def validate_context_def(
self,
context_def: ContextDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Validate a context definition.
"""
pass
def get_context_def(
self,
context_type: str,
config: AuthzeeConfigOverride | None = None
) -> ContextDefResult:
"""Get a context definition by type.
If the context_type does not match a stored context definition, the result will have `context_def` set to null and `error` set to a non-null error object.
"""
pass
def put_context_def(
self,
context_def: ContextDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Add a new Context Definition or update an existing one.
"""
def delete_context_def(
self,
context_type: str,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Delete a context definition by type.
"""
pass
def validate_identity_def(
self,
identity_def: IdentityDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Validate an identity definition.
"""
pass
def list_identity_defs(
self,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> IdentityDefsPage:
"""Get a page of identity definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
def get_identity_def(
self,
identity_type: str,
config: AuthzeeConfigOverride | None = None
) -> IdentityDefResult:
"""Get an identity definition by type.
If the identity_type does not match a stored identity definition, the result will have `identity_def` set to null and `error` set to a non-null error object.
"""
pass
def put_identity_def(
self,
identity_def: IdentityDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Add a new Identity Definition or update an existing one
"""
pass
def delete_identity_def(
self,
identity_type: str,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Delete an identity definition by type.
"""
pass
def validate_resource_def(
self,
resource_def: ResourceDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Validate a resource definition.
"""
pass
def list_resource_defs(
self,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> ResourceDefsPage:
"""Get a page of resource definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
def get_resource_def(
self,
resource_type: str,
config: AuthzeeConfigOverride | None = None
) -> ResourceDefResult:
"""Get a resource definition by type.
If the resource_type does not match a stored resource definition, the result will have `resource_def` set to null and `error` set to a non-null error object.
"""
pass
def put_resource_def(
self,
resource_def: ResourceDef,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Add a new Resource Definition or update an existing one.
"""
pass
def delete_resource_def(
self,
resource_type: str,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Delete a resource definition by type.
"""
pass
def validate_grant(
self,
grant: Grant,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Validate a grant.
"""
pass
def enact(
self,
grant: Grant,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Add a new grant.
**NOTE** - For scalability, grants should only be created and destroyed. Storage modules may do their best to check if a grant UUID exists, but may not always be correct. Only ever put in new UUIDs, not ones known to exist.
"""
pass
def repeal(
self,
grant_uuid: UUID,
purge: bool = False,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Delete a grant.
`purge` will scan all grant partitions. Slower but can be used to clean up corrupted grants.
"""
pass
def get_grant(
self,
grant_uuid: UUID,
config: AuthzeeConfigOverride | None = None
) -> GrantResult:
"""Get a grant by UUID.
If the grant_uuid does not match a stored grant, the result will have `grant` set to null and `error` set to a non-null error object.
"""
pass
def list_grants(
self,
effect: str | None,
action: str | None,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> GrantsPage:
"""Retrieve a page of grants.
Pass the returned page reference to get the next page until a null page reference is returned.
effect - Filter by grant effect. Accepts "allow", "deny", or null.
Null means no filtering by effect. When non-null, only grants whose
effect field matches the filter value are included.
action - Filter by resource action. Accepts a resource action string or null.
Null means no filtering by action. When non-null, only grants whose
actions field contains the filter value are included.
"""
pass
def list_grant_refs(
self,
effect: str | None,
action: str | None,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> PageRefsPage:
"""Retrieve a page of grant page references for parallel pagination.
Pass the returned page reference to get the next page until a null page reference is returned.
For some storage modules this may not be possible, check the `parallel_paging` value.
effect - Filter by grant effect. Accepts "allow", "deny", or null.
Null means no filtering by effect. When non-null, only grants whose
effect field matches the filter value are included.
action - Filter by resource action. Accepts a resource action string or null.
Null means no filtering by action. When non-null, only grants whose
actions field contains the filter value are included.
"""
pass
def cleanup_latches(
self,
before: Datetime,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Delete all latches before the specified datetime.
- operations should clean up their own latches, but in case of a failure this can be used to clean up zombie latches.
"""
pass
def validate_request(
self,
request: AuthzeeRequest,
config: AuthzeeConfigOverride | None = None
) -> GenericResult:
"""Validate a request.
Return value matches `validate_request_result_schema`.
"""
pass
def audit(
self,
request: AuthzeeRequest,
effect: str | None,
action: str | None,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> AuditResultPage:
"""Run the Audit Operation for a page of results.
Pass the returned page reference to get the next page until a null page reference is returned.
effect - Filter by grant effect. Accepts "allow", "deny", or null.
Null means no filtering by effect. When non-null, only grants whose
effect field matches the filter value are included in the audit.
action - Filter by resource action. Accepts a resource action string or null.
Null means no filtering by action. When non-null, only grants whose
actions field contains the filter value are included in the audit.
"""
pass
def authorize(
self,
request: AuthzeeRequest,
config: AuthzeeConfigOverride | None = None
) -> AuthorizeResult:
"""Run the Authorize Operation.
"""
pass
def validate_batch_request(
self,
batch_request: AuthzeeBatchRequest,
config: AuthzeeConfigOverride | None = None
) -> ValidateBatchRequestResult:
"""Validate a batch request.
Return value matches `validate_batch_request_result_schema`.
"""
pass
def batch_audit(
self,
batch_request: AuthzeeBatchRequest,
effect: str | None,
action: str | None,
page_ref: str | None,
config: AuthzeeConfigOverride | None = None
) -> BatchAuditResultPage:
"""Run the Batch Audit Operation for a page of results.
Pass the returned page reference to get the next page until a null page reference is returned.
effect - Filter by grant effect. Accepts "allow", "deny", or null.
Null means no filtering by effect. When non-null, only grants whose
effect field matches the filter value are included in the audit.
action - Filter by resource action. Accepts a resource action string or null.
Null means no filtering by action. When non-null, only grants whose
actions field contains the filter value are included in the audit.
"""
pass
def batch_authorize(
self,
batch_request: AuthzeeBatchRequest,
config: AuthzeeConfigOverride | None = None
) -> BatchAuthorizeResult:
"""Run the Batch Authorize Operation.
"""
pass
#Paginator
The paginator() utility function provides automatic pagination through all pages from any page-returning method. It replaces the old auto-paginating list_* iterator methods.
def paginator(page_method, **kwargs):
"""Iterate through all pages from a page-returning method.
Yields each page result.
Terminates when next_page_ref is None or error is not None.
"""
...
For AuthzeeAsync, use paginator_async():
async def paginator_async(page_method, **kwargs):
"""Async version of paginator for use with AuthzeeAsync.
Yields each page result via an async generator.
Terminates when next_page_ref is None or error is not None.
"""
...
#Usage Examples
# Paginate through all context definitions
for page in paginator(authz.list_context_defs):
for context_def in page.context_defs:
print(context_def)
# Paginate through grants filtered by effect
for page in paginator(authz.list_grants, effect="allow", action=None):
for grant in page.grants:
print(grant)
# Paginate through grant refs
for page in paginator(authz.list_grant_refs, effect=None, action="Balloon:Inflate"):
for ref in page.page_refs:
print(ref)
#Compute Modules
Compute modules provide a standard API for running operation on compute. Compute Modules should not be used directly but through the Authzee class. They have direct access to the storage module and use it to retrieve grants. They may also use the storage module to create and retrieve latches that help with compute state. Especially for compute that is spread across multiple systems.
NOTE - If the language supports async, then the compute module functions are expected to be async. Even if the underlying functionality is not async, this is to simplify the API between the
Authzeeapp and the compute modules. As well as avoid having to create a sync and async version of each compute module.
Compute Modules should take any module specific arguments when created.
Compute modules objects should implement these methods. Every method accepts its dedicated config class as a required parameter. The config class name follows the pattern Compute{MethodName}Config for lifecycle methods (e.g., ComputeStartConfig for start) and {MethodName}Config for operation methods (e.g., AuditConfig for audit). The Authzee class is responsible for resolving the full config and passing the appropriate method-specific config object to the compute module.
class ComputeModule:
async def start(
self,
execute: Callable[[str, Any], Any],
storage_type: Type[StorageModule],
storage_kwargs: Dict[str, Any],
config: ComputeStartConfig
) -> GenericResult:
"""Start up compute module.
- run before use
- After this method is complete these public instance vars or getters must be available and stable:
- locality - Compute [Module Locality](#module-locality)
- has_parallel_paging - if the compute module supports processing grants with parallel paging
"""
pass
async def shutdown(self, config: ComputeShutdownConfig) -> GenericResult:
"""Shutdown Compute module.
- clean up runtime resources
"""
pass
async def construct(self, config: ComputeConstructConfig) -> GenericResult:
"""Construct backend resources for compute.
- one time setup
"""
pass
async def destroy(self, config: ComputeDestroyConfig) -> GenericResult:
"""Tear down backend resources.
- destructive - may lose all long lasting compute resources
"""
pass
async def validate_context_def(
self,
context_def: ContextDef,
config: ValidateContextDefConfig
) -> GenericResult:
pass
async def validate_identity_def(
self,
identity_def: IdentityDef,
config: ValidateIdentityDefConfig
) -> GenericResult:
pass
async def validate_resource_def(
self,
resource_def: ResourceDef,
config: ValidateResourceDefConfig
) -> GenericResult:
pass
async def validate_grant(
self,
grant: Grant,
config: ValidateGrantConfig
) -> GenericResult:
pass
async def validate_request(
self,
request: AuthzeeRequest,
config: ValidateRequestConfig
) -> GenericResult:
"""Validate a request.
Return value matches `validate_request_result_schema`.
"""
pass
async def validate_batch_request(
self,
batch_request: AuthzeeBatchRequest,
config: ValidateBatchRequestConfig
) -> ValidateBatchRequestResult:
"""Validate a batch request.
Return value matches `validate_batch_request_result_schema`.
"""
pass
async def audit(
self,
request: AuthzeeRequest,
page_ref: str | None,
config: AuditConfig
) -> AuditResultPage:
"""Run the Audit Operation for a page of results.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def authorize(
self,
request: AuthzeeRequest,
config: AuthorizeConfig
) -> AuthorizeResult:
"""Run the Authorize Operation.
"""
pass
async def batch_audit(
self,
batch_request: AuthzeeBatchRequest,
page_ref: str | None,
config: BatchAuditConfig
) -> BatchAuditResultPage:
"""Run the Batch Audit Operation for a page of results.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def batch_authorize(
self,
batch_request: AuthzeeBatchRequest,
config: BatchAuthorizeConfig
) -> BatchAuthorizeResult:
"""Run the Batch Authorize Operation.
"""
pass
#Storage Modules
Storage modules provide a standard API for storing and retrieving grants and Storage Latches.
NOTE - If the language supports async, then the storage module functions are expected to be async. Even if the underlying functionality is not async, this is to simplify the API between the pieces.
Storage Modules should take any module specific arguments when created.
Storage modules should implement these methods. Every method accepts its dedicated config class as a required parameter. The config class name follows the pattern Storage{MethodName}Config for lifecycle methods (e.g., StorageStartConfig for start) and {MethodName}Config for operation methods (e.g., ListGrantsConfig for list_grants). The Authzee class is responsible for resolving the full config and passing the appropriate method-specific config object to the storage module.
class StorageModule:
def __init__(self):
pass
async def start(self, config: StorageStartConfig) -> GenericResult:
"""Start up storage module.
- run before use
- After this method is complete these public instance vars or getters must be available:
- locality - Storage [Module Locality](#module-locality)
- has_parallel_paging - if the storage module supports parallel paging (returning a page of grant page references).
"""
pass
async def shutdown(self, config: StorageShutdownConfig) -> GenericResult:
"""Shutdown storage module.
- clean up runtime resources
"""
pass
async def construct(self, config: StorageConstructConfig) -> GenericResult:
"""Construct backend resources for storage.
- one time setup
"""
pass
async def destroy(self, config: StorageDestroyConfig) -> GenericResult:
"""Tear down backend resources.
- destructive - may lose all long lasting storage resources
"""
pass
async def list_context_defs(
self,
page_ref: str | None,
config: ListContextDefsConfig
) -> ContextDefsPage:
"""Get a page of context definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def get_context_def(
self,
context_type: str,
config: GetContextDefConfig
) -> ContextDefResult:
"""Get a context definition by type.
"""
pass
async def put_context_def(
self,
context_def: ContextDef,
config: PutContextDefConfig
) -> GenericResult:
"""Add a new Context Definition or update an existing one.
"""
pass
async def delete_context_def(
self,
context_type: str,
config: DeleteContextDefConfig
) -> GenericResult:
"""Delete a context definition by type.
"""
pass
async def list_identity_defs(
self,
page_ref: str | None,
config: ListIdentityDefsConfig
) -> IdentityDefsPage:
"""Get a page of identity definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def get_identity_def(
self,
identity_type: str,
config: GetIdentityDefConfig
) -> IdentityDefResult:
"""Get an identity definition by type.
"""
pass
async def put_identity_def(
self,
identity_def: IdentityDef,
config: PutIdentityDefConfig
) -> GenericResult:
"""Add a new Identity Definition or update an existing one.
"""
pass
async def delete_identity_def(
self,
identity_type: str,
config: DeleteIdentityDefConfig
) -> GenericResult:
"""Delete an identity definition by type.
"""
pass
async def list_resource_defs(
self,
page_ref: str | None,
config: ListResourceDefsConfig
) -> ResourceDefsPage:
"""Get a page of resource definitions.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def get_resource_def(
self,
resource_type: str,
config: GetResourceDefConfig
) -> ResourceDefResult:
"""Get a resource definition by type.
"""
pass
async def put_resource_def(
self,
resource_def: ResourceDef,
config: PutResourceDefConfig
) -> GenericResult:
"""Add a new Resource Definition or update an existing one.
"""
pass
async def delete_resource_def(
self,
resource_type: str,
config: DeleteResourceDefConfig
) -> GenericResult:
"""Delete a resource definition by type.
"""
pass
async def enact(
self,
grant: Grant,
config: EnactConfig
) -> GenericResult:
"""Add a new grant.
"""
pass
async def repeal(
self,
grant_uuid: str,
purge: bool,
config: RepealConfig
) -> GenericResult:
"""Delete a grant.
"""
pass
async def get_grant(
self,
grant_uuid: str,
config: GetGrantConfig
) -> GrantResult:
"""Get a grant by UUID.
"""
pass
async def list_grants(
self,
effect: str | None,
action: str | None,
page_ref: str | None,
config: ListGrantsConfig
) -> GrantsPage:
"""Retrieve a page of grants.
Pass the returned page reference to get the next page until a null page reference is returned.
"""
pass
async def list_grant_refs(
self,
effect: str | None,
action: str | None,
page_ref: str | None,
config: ListGrantRefsConfig
) -> PageRefsPage:
"""Retrieve a page of grant page references for parallel pagination.
Pass the returned page reference to get the next page until a null page reference is returned.
For some storage modules this may not be possible.
Check the `parallel_paging` attribute on the storage module after `start()` is complete.
"""
pass
async def create_latch(self, config: CreateLatchConfig) -> StorageLatchResult:
"""Create a new [storage latch](#storage-latches).
"""
pass
async def get_latch(
self,
storage_latch_uuid: str,
config: GetLatchConfig
) -> StorageLatchResult:
"""Get a [storage latch](#storage-latches) by UUID.
"""
pass
async def set_latch(
self,
storage_latch_uuid: str,
config: SetLatchConfig
) -> StorageLatchResult:
"""Set a [storage latch](#storage-latches) by UUID.
"""
pass
async def delete_latch(
self,
storage_latch_uuid: str,
config: DeleteLatchConfig
) -> GenericResult:
"""Delete a [storage latch](#storage-latches) by UUID.
"""
pass
async def cleanup_latches(
self,
before: datetime.datetime,
config: CleanupLatchesConfig
) -> GenericResult:
"""Delete all latches before the specified datetime.
- operations should clean up their own latches, but in case of a failure this can be used to clean up zombie latches.
"""
pass
NOTE - When listing grants there are 2 filters:
effectandaction. Storage modules should partition grants on these 2 fields if they can.
#Module Locality
Module Locality is a way to describe "where" a compute module, storage module, or Authzee instance could be located in relation to one another. This will determine the compute localities that are compatible with specific storage localities. It will also limit how Authzee instances can be created.
- process - The module is localized to the same process as the Authzee app.
- Compute resources are shared with the same process as the Authzee app.
- Storage is localized to the same process and is not shared with any other instances of the Authzee app (other processes).
- Authzee instances must exist within the same process.
- system - The module is localized to the same system as the Authzee app.
- Compute resources are shared with the same system as the Authzee app.
- Storage is localized to the same system and is shared with other Authzee app instances on the system.
- Authzee instances must exist within the same system.
- network - The module is localized to network connectivity with the Authzee app.
- Compute resources are shared with systems that are reachable across the same network as the Authzee app.
- Storage is shared with systems that are reachable across the same network as the Authzee app.
- More precisely, the storage and compute is available over the network from all Authzee instances.
Compute localities are only compatible with storage localities that are the same or have a "larger" locality.
The compute locality compatibility matrix with storage localities:
| _____________\Storage Locality Compute Locality\ _______________ |
Process | System | Network |
|---|---|---|---|
| Process | ✅ | ✅ | ✅ |
| System | ❌ | ✅ | ✅ |
| Network | ❌ | ❌ | ✅ |
Authzee Localities are usually the same as the storage locality.
#Handling Errors
The SDK should return normalized results for all operations that include any errors in the results.
If the Language supports exceptions, then the Authzee Class should support the ability to raise errors as exceptions.
Exceptions should provide a message and the full result of the function with all errors.
#Exception Hierarchy
If the language support exception hierarchies it should be as follows:
- root exception for Authzee.
- Authzee Specification Exception
- Definition Specification Error
- Grant Specification Error
- Request Specification Error
- Evaluation Specification Error
- Authzee SDK Exception
- SDKs are free to implement any other exceptions as needed. Try to denote that they are SDK exceptions where possible.
- Authzee Specification Exception
#Standard Types
The input and output objects (data class instances, struct instances) should take a standard form when dealing with the Authzee class. The Authzee class provides the only public API to the SDKs, but the compute and storage classes are expected to provide consistent APIs to make compute and storage classes interchangeable.
The SDKs build on some existing data structures from the spec and use some totally new.
Standard Types:
- AuthzeeConfig
- page_ref
- GenericResult and *Results
- Page Results
- Grant
- AuthzeeRequest
- AuditResultPage
- AuthorizeResult
- AuthzeeBatchRequest
- BatchAuditResultPage
- BatchAuthorizeResult
#AuthzeeConfig
See Authzee Config in the Authzee Class section for the full per-method config structure, AuthzeeConfigOverride, and the 3-level precedence model.
#page_ref
Authzee relies on pagination to make its operations scalable.
page_ref represents a string token to a specific page of resources. To get the first page of a resource the page_ref should have a null value. next_page_ref is present in results to be passed in the following function call to retrieve the next page. When next_page_ref is a null value, the current page is considered the last and should not be passed back to the function.
#GenericResult and *Results
GenericResult simply returns if the function has encountered an error.
Types from Authzee that are prefixed with Result are simply that type nested in an object with fields in GenericResult as well.
Example structure for Grant:
{
"grant": null,
"error": null
}
The results should use these field names:
Grant->grantContextDef->context_defIdentityDef->identity_defResourceDef->resource_def
#GenericResult Example
{
"error": null
}
#GenericResult Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "GenericResult",
"description": "An object representing the a result from an authzee function.",
"type": "object",
"additionalProperties": true,
"required": [
"error"
],
"properties": {
"error": {
"description": "Error information if the operation failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
#Page Results
Authzee supplies several resources that are paginated including: grants, context definitions, identity definitions, resource definitions, and page references.
Each of these has generalized paged results that will contain a field for the list of items, as well next_page_ref and the fields from GenericResult.
GrantsPage Example:
{
"grants": [],
"next_page_ref": "asdfds",
"error": null
}
Mapping of resource pages to field containing items:
GrantsPage->grantsContextDefsPage->context_defsIdentityDefsPage->identity_defsResourceDefsPage->resource_defsPageRefsPage->page_refs
#Grant
Grants should offer more flexibility over the reference implementation, and should be standard across the SDKs.
In the SDK standard, grants are an immutable resource. They can only be enacted(created) or repealed(destroyed). This is a purposeful limitation to enable better scaling of grants.
#Grant Example
{
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"Balloon:Pop",
"Balloon:Inflate"
],
"query": "contains(request.identities.Group[? contains(grant.data.allowed_groups, cn)]",
"equality": true,
"applicable_on_failure": false,
"data": {
"allowed_groups": "MyGroup"
}
}
#Grant Schema
They should provide these additional fields over the Grant Specification, and they should also be available to query during runtime.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Grant",
"description": "A grant is an object representing enacted authorization rules.",
"type": "object",
"additionalProperties": true,
"required": [
"grant_uuid",
"name",
"description",
"tags",
"effect",
"actions",
"data",
"query",
"equality",
"applicable_on_failure"
],
"properties": {
"grant_uuid": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"description": "Short name for the grant"
},
"description": {
"type": "string",
"description": "Longer description for the grant "
},
"tags": {
"type": "object",
"description": "General purpose Key/Value pairs for categorization.",
"patternProperties": {
"^[A-Za-z0-9_]*$": {
"type": "string"
}
}
},
"effect": {
"type": "string",
"enum": [
"allow",
"deny"
],
"description": "Any applicable deny grant will always cause the request to be unauthorized. If there are no applicable deny grants, and there is an applicable allow grant, the request is authorized. If there no applicable allow or deny grants, requests are implicitly denied and is not authorized."
},
"actions": {
"type": "array",
"uniqueItems": true,
"items": {
"title": "Resource Action",
"description": "Unique name for a resource action. The 'ResourceType:ResourceAction' pattern is common, or more general 'Namespace:Action' pattern.",
"type": "string",
"pattern": "^[A-Za-z0-9_.:-]*$",
"minLength": 1,
"maxLength": 512
},
"description": "List of actions this grant applies to or null to match any resource action."
},
"data": {
"type": "object",
"description": "Data that is made available at query time for the grant evaluation. Easy place to store data so it doesn't have to be embedded in the query."
},
"query": {
"type": "string",
"description": "JSON query to run on the authorization data. {\"grant\": <grant>, \"request\": <request>}"
},
"equality": {
"description": "Expected value for the query to return. If the query result matches this value the grant is a considered applicable to the request."
},
"applicable_on_failure": {
"type": "boolean",
"description": "If true, the grant is considered applicable when the query evaluation fails. Useful as a fail-safe for deny grants."
}
}
}
#Storage Latches
Storage latches are flag like objects kept in the storage module. Storage latches can only be created, set, or deleted. They cannot be unset or otherwise mutated.
Compute modules may call on the storage module to create latches to manage the state of operations. When compute is shared over the network this becomes a necessary piece to communicate different operation statuses.
#Storage Latch Example
{
"storage_latch_uuid": "7fa89195-d455-444c-ad53-9f1c66a0fc85",
"is_set": false,
"created_at": "2025-07-20T04:13:17.292144Z"
}
#Storage Latch Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "StorageLatch",
"description": "An object representing a latch held in the storage module.",
"type": "object",
"additionalProperties": true,
"required": [
"storage_latch_uuid",
"is_set",
"created_at"
],
"properties": {
"storage_latch_uuid": {
"type": "string",
"format": "uuid"
},
"is_set": {
"type": "boolean",
"description": "Is the latch set or not"
},
"created_at": {
"type": "string",
"format": "date-time"
}
}
}
#AuthzeeRequest
The standard "Request" object used to initiate an Authzee operation. Should match the Authzee Request Specification.
#AuditResultPage
A page of Audit operation results. Conforms to the Audit Operation Results. Each result item includes the grant that was evaluated. It will also have a next_page_ref field for pagination.
#AuditResultPage Example
{
"results": [
{
"grant": {
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"Balloon:Pop",
"Balloon:Inflate"
],
"query": "contains(request.identities.Group[? contains(grant.data.allowed_groups, cn)]",
"equality": true,
"applicable_on_failure": true,
"data": {
"allowed_groups": "MyGroup"
}
},
"is_applicable": true,
"query_result": null,
"failure": "A JSON Query error has occurred: invalid expression."
}
],
"next_page_ref": "abc123",
"error": {
"error_type": "request",
"message": "Identity type 'Ghost' is not valid."
}
}
#AuditResultPage Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Audit Result Page",
"description": "Page of results for the audit operation.",
"type": "object",
"additionalProperties": true,
"required": [
"results",
"next_page_ref",
"error"
],
"properties": {
"results": {
"type": "array",
"description": "List of grant evaluation results with the grant included.",
"items": {
"type": "object",
"additionalProperties": true,
"required": [
"grant",
"is_applicable",
"query_result",
"failure"
],
"properties": {
"grant": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Grant",
"description": "A grant is an object representing enacted authorization rules.",
"type": "object",
"additionalProperties": true,
"required": [
"grant_uuid",
"name",
"description",
"tags",
"effect",
"actions",
"data",
"query",
"equality",
"applicable_on_failure"
],
"properties": {
"grant_uuid": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"description": "Short name for the grant"
},
"description": {
"type": "string",
"description": "Longer description for the grant"
},
"tags": {
"type": "object",
"description": "General purpose Key/Value pairs for categorization.",
"patternProperties": {
"^[A-Za-z0-9_]*$": {
"type": "string"
}
}
},
"effect": {
"type": "string",
"enum": [
"allow",
"deny"
],
"description": "Any applicable deny grant will always cause the request to be unauthorized. If there are no applicable deny grants, and there is an applicable allow grant, the request is authorized. If there no applicable allow or deny grants, requests are implicitly denied and is not authorized."
},
"actions": {
"type": "array",
"uniqueItems": true,
"items": {
"title": "Resource Action",
"description": "Unique name for a resource action. The 'ResourceType:ResourceAction' pattern is common, or more general 'Namespace:Action' pattern.",
"type": "string",
"pattern": "^[A-Za-z0-9_.:-]*$",
"minLength": 1,
"maxLength": 512
},
"description": "List of actions this grant applies to or null to match any resource action."
},
"data": {
"type": "object",
"description": "Data that is made available at query time for the grant evaluation. Easy place to store data so it doesn't have to be embedded in the query."
},
"query": {
"type": "string",
"description": "JSON query to run on the authorization data. {\"grant\": <grant>, \"request\": <request>}"
},
"equality": {
"description": "Expected value for the query to return. If the query result matches this value the grant is a considered applicable to the request."
},
"applicable_on_failure": {
"type": "boolean",
"description": "If true, the grant is considered applicable when the query evaluation fails. Useful as a fail-safe for deny grants."
}
}
},
"is_applicable": {
"type": "boolean",
"description": "If the grant is applicable to the request or not."
},
"query_result": {
"description": "Result from running the JSON query."
},
"failure": {
"description": "A message describing why the evaluation failed, or null if no failure occurred. Evaluation failures do not cause the operation to fail.",
"type": [
"string",
"null"
]
}
}
}
},
"next_page_ref": {
"type": [
"string",
"null"
],
"description": "Used to retrieve the next page of audit results."
},
"error": {
"description": "Error information if the operation failed, or null if successful.",
"type": [
"object",
"null"
],
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type of error."
},
"message": {
"type": "string",
"description": "Message describing the error."
}
}
}
}
}
#AuthorizeResult
The standard Authorize operation Results are returned with updated fields for grants.
The error field is required on every AuthorizeResult. When error is not null, is_authorized is always false and message indicates an error has occurred. This can happen when a validation error occurs or when an internal SDK error prevents the operation from completing.
#AuthorizeResult Example - Successful Authorization
{
"is_authorized": true,
"grant": {
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"Balloon:Read",
"pop"
],
"query": "contains(request.identities.User[0].role, 'admin')",
"equality": true,
"applicable_on_failure": false,
"data": {}
},
"message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
"error": null
}
#AuthorizeResult Example - Error
When an error occurs during authorization, error is not null and is_authorized is always false.
{
"is_authorized": false,
"grant": null,
"message": "An error has occurred. Therefore, the request is not authorized.",
"error": {
"error_type": "request",
"message": "Identity type 'Ghost' is not valid."
}
}
#Authorize Result Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Authorize Result",
"description": "Result for the authorize operation.",
"type": "object",
"additionalProperties": true,
"required": [
"is_authorized",
"grant",
"message",
"error"
],
"properties": {
"is_authorized": {
"type": "boolean",
"description": "true if the request is authorized. false if it is not authorized."
},
"grant": {
"description": "Grant that was responsible for the authorization decision, if applicable.",
"anyOf": [
{
"type": "null",
"description": "No grant was involved in the authorization decision."
},
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Grant",
"description": "A grant is an object representing enacted authorization rules.",
"type": "object",
"additionalProperties": true,
"required": [
"grant_uuid",
"name",
"description",
"tags",
"effect",
"actions",
"data",
"query",
"equality",
"applicable_on_failure"
],
"properties": {
"grant_uuid": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"description": "Short name for the grant"
},
"description": {
"type": "string",
"description": "Longer description for the grant "
},
"tags": {
"type": "object",
"description": "General purpose Key/Value pairs for categorization.",
"patternProperties": {
"^[A-Za-z0-9_]*$": {
"type": "string"
}
}
},
"effect": {
"type": "string",
"enum": [
"allow",
"deny"
],
"description": "Any applicable deny grant will always cause the request to be unauthorized. If there are no applicable deny grants, and there is an applicable allow grant, the request is authorized. If there no applicable allow or deny grants, requests are implicitly denied and is not authorized."
},
"actions": {
"type": "array",
"uniqueItems": true,
"items": {
"title": "Resource Action",
"description": "Unique name for a resource action. The 'ResourceType:ResourceAction' pattern is common, or more general 'Namespace:Action' pattern.",
"type": "string",
"pattern": "^[A-Za-z0-9_.:-]*$",
"minLength": 1,
"maxLength": 512
},
"description": "List of actions this grant applies to or null to match any resource action."
},
"data": {
"type": "object",
"description": "Data that is made available at query time for the grant evaluation. Easy place to store data so it doesn't have to be embedded in the query."
},
"query": {
"type": "string",
"description": "JSON query to run on the authorization data. {\"grant\": <grant>, \"request\": <request>}"
},
"equality": {
"description": "Expected value for the query to return. If the query result matches this value the grant is a considered applicable to the request."
},
"applicable_on_failure": {
"type": "boolean",
"description": "If true, the grant is considered applicable when the query evaluation fails. Useful as a fail-safe for deny grants."
}
}
}
]
},
"message": {
"type": "string",
"description": "Details about why the request was authorized or not.",
"enum": [
"An error has occurred. Therefore, the request is not authorized.",
"A deny grant is applicable to the request. Therefore, the request is not authorized.",
"An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
"No grants are applicable to the request. Therefore, the request is implicitly denied and is not authorized."
]
},
"error": {
"description": "Error information if the operation failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
#AuthzeeBatchRequest
The standard "Batch Request" object used to initiate an Authzee operation. Should match the Authzee Request Specification.
#BatchAuditResultPage
A page of Batch Audit operation results. Conforms to the Batch Audit Operation Results. The grants array at the top level lists the grants processed for this page. Each batch item's results array corresponds to the grants by index. It will also have a next_page_ref field for pagination.
#BatchAuditResultPage Example
{
"grants": [
{
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"inflate"
],
"query": "contains(request.identities.Role[*].permissions[], 'balloon:inflate') && request.identities.User[0].department == request.resource.owner_department",
"equality": true,
"applicable_on_failure": true,
"data": {}
}
],
"batch": [
{
"results": [
{
"is_applicable": true,
"query_result": null,
"failure": "A JSON Query error has occurred: unknown function 'bad_func'."
}
],
"error": {
"error_type": "request",
"message": "Identity type 'Ghost' is not valid."
}
}
],
"next_page_ref": "def456",
"error": {
"error_type": "definition",
"message": "Context types must be unique. 'event' is present more than once."
}
}
#BatchAuditResultPage Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Batch Audit Result Page",
"description": "Page of results for the Batch Audit Operation.",
"type": "object",
"additionalProperties": true,
"required": [
"grants",
"batch",
"next_page_ref",
"error"
],
"properties": {
"grants": {
"type": "array",
"description": "List of grants that have been processed for the request.",
"items": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Grant",
"description": "A grant is an object representing enacted authorization rules.",
"type": "object",
"additionalProperties": true,
"required": [
"grant_uuid",
"name",
"description",
"tags",
"effect",
"actions",
"data",
"query",
"equality",
"applicable_on_failure"
],
"properties": {
"grant_uuid": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"description": "Short name for the grant"
},
"description": {
"type": "string",
"description": "Longer description for the grant "
},
"tags": {
"type": "object",
"description": "General purpose Key/Value pairs for categorization.",
"patternProperties": {
"^[A-Za-z0-9_]*$": {
"type": "string"
}
}
},
"effect": {
"type": "string",
"enum": [
"allow",
"deny"
],
"description": "Any applicable deny grant will always cause the request to be unauthorized. If there are no applicable deny grants, and there is an applicable allow grant, the request is authorized. If there no applicable allow or deny grants, requests are implicitly denied and is not authorized."
},
"actions": {
"type": "array",
"uniqueItems": true,
"items": {
"title": "Resource Action",
"description": "Unique name for a resource action. The 'ResourceType:ResourceAction' pattern is common, or more general 'Namespace:Action' pattern.",
"type": "string",
"pattern": "^[A-Za-z0-9_.:-]*$",
"minLength": 1,
"maxLength": 512
},
"description": "List of actions this grant applies to or null to match any resource action."
},
"data": {
"type": "object",
"description": "Data that is made available at query time for the grant evaluation. Easy place to store data so it doesn't have to be embedded in the query."
},
"query": {
"type": "string",
"description": "JSON query to run on the authorization data. {\"grant\": <grant>, \"request\": <request>}"
},
"equality": {
"description": "Expected value for the query to return. If the query result matches this value the grant is a considered applicable to the request."
},
"applicable_on_failure": {
"type": "boolean",
"description": "If true, the grant is considered applicable when the query evaluation fails. Useful as a fail-safe for deny grants."
}
}
}
},
"batch": {
"type": "array",
"description": "Array of results from a batch request. Each result corresponds to the batch request item of the same index.",
"items": {
"type": "object",
"description": "Audit batch item result.",
"additionalProperties": true,
"required": [
"results",
"error"
],
"properties": {
"results": {
"type": "array",
"description": "List of grant evaluation results for each respective grant index.",
"items": {
"type": "object",
"additionalProperties": true,
"required": [
"is_applicable",
"query_result",
"failure"
],
"properties": {
"is_applicable": {
"type": "boolean",
"description": "If the grant is applicable to the request or not."
},
"query_result": {
"description": "Result from running the JSON query."
},
"failure": {
"description": "A message describing why the evaluation failed, or null if no failure occurred. Evaluation failures do not cause the operation to fail.",
"type": [
"string",
"null"
]
}
}
}
},
"error": {
"description": "Error information if the batch item failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
},
"error": {
"description": "Error information if the operation failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
#BatchAuthorizeResult
The Authorize operation Results, which conforms to the Authzee specification, where some fields are updated depending on the identity and resource defs.
The error field appears at two levels in a BatchAuthorizeResult:
- Top-level
error: Indicates the batch request itself failed validation (e.g., the batch request object was invalid). When notnull, thebatcharray may be empty or incomplete. - Per-item
error: Each AuthorizeResult withinbatchhas its ownerrorfield. When notnullon a per-item result, that individual authorization encountered an error,is_authorizedisfalse, andmessageindicates the error.
#BatchAuthorizeResult Example - Successful Batch
{
"batch": [
{
"is_authorized": true,
"grant": {
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"Balloon:Read",
"pop"
],
"query": "contains(request.identities.User[0].role, 'admin')",
"equality": true,
"applicable_on_failure": false,
"data": {}
},
"message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
"error": null
},
{
"is_authorized": false,
"grant": null,
"message": "No grants are applicable to the request. Therefore, the request is implicitly denied and is not authorized.",
"error": null
}
],
"error": null
}
#BatchAuthorizeResult Example - Per-Item Error
In this example, the batch itself succeeded but one item in the batch encountered an error.
{
"batch": [
{
"is_authorized": true,
"grant": {
"grant_uuid": "6ce44005-8735-45ac-ae76-38e22e66f615",
"name": "My grant name",
"description": "Longer description here to explain what the grant is for.",
"tags": {
"some_key": "some_val"
},
"effect": "allow",
"actions": [
"Balloon:Read",
"pop"
],
"query": "contains(request.identities.User[0].role, 'admin')",
"equality": true,
"applicable_on_failure": false,
"data": {}
},
"message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
"error": null
},
{
"is_authorized": false,
"grant": null,
"message": "An error has occurred. Therefore, the request is not authorized.",
"error": {
"error_type": "request",
"message": "Identity type 'Ghost' is not valid."
}
}
],
"error": null
}
#BatchAuthorizeResult Example - Batch Validation Failure
When the batch request itself fails validation, the top-level error is not null.
{
"batch": [],
"error": {
"error_type": "request",
"message": "Batch request validation failed: identity type 'InvalidUser' does not match any registered identity definition."
}
}
#BatchAuthorizeResult Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Batch Authorize Result",
"description": "Result for the Batch Authorize Operation.",
"type": "object",
"additionalProperties": true,
"required": [
"batch",
"error"
],
"properties": {
"batch": {
"type": "array",
"description": "Array of results from a batch request. Each result corresponds to the batch request item of the same index.",
"items": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Authorize Result",
"description": "Result for the authorize operation.",
"type": "object",
"additionalProperties": true,
"required": [
"is_authorized",
"grant",
"message",
"error"
],
"properties": {
"is_authorized": {
"type": "boolean",
"description": "true if the request is authorized. false if it is not authorized."
},
"grant": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Grant",
"description": "A grant is an object representing enacted authorization rules.",
"type": "object",
"additionalProperties": true,
"required": [
"grant_uuid",
"name",
"description",
"tags",
"effect",
"actions",
"data",
"query",
"equality",
"applicable_on_failure"
],
"properties": {
"grant_uuid": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"description": "Short name for the grant"
},
"description": {
"type": "string",
"description": "Longer description for the grant "
},
"tags": {
"type": "object",
"description": "General purpose Key/Value pairs for categorization.",
"patternProperties": {
"^[A-Za-z0-9_]*$": {
"type": "string"
}
}
},
"effect": {
"type": "string",
"enum": [
"allow",
"deny"
],
"description": "Any applicable deny grant will always cause the request to be unauthorized. If there are no applicable deny grants, and there is an applicable allow grant, the request is authorized. If there no applicable allow or deny grants, requests are implicitly denied and is not authorized."
},
"actions": {
"type": "array",
"uniqueItems": true,
"items": {
"title": "Resource Action",
"description": "Unique name for a resource action. The 'ResourceType:ResourceAction' pattern is common, or more general 'Namespace:Action' pattern.",
"type": "string",
"pattern": "^[A-Za-z0-9_.:-]*$",
"minLength": 1,
"maxLength": 512
},
"description": "List of actions this grant applies to or null to match any resource action."
},
"data": {
"type": "object",
"description": "Data that is made available at query time for the grant evaluation. Easy place to store data so it doesn't have to be embedded in the query."
},
"query": {
"type": "string",
"description": "JSON query to run on the authorization data. {\"grant\": <grant>, \"request\": <request>}"
},
"equality": {
"description": "Expected value for the query to return. If the query result matches this value the grant is a considered applicable to the request."
},
"applicable_on_failure": {
"type": "boolean",
"description": "If true, the grant is considered applicable when the query evaluation fails. Useful as a fail-safe for deny grants."
}
}
},
"message": {
"type": "string",
"description": "Details about why the request was authorized or not.",
"enum": [
"An error has occurred. Therefore, the request is not authorized.",
"A deny grant is applicable to the request. Therefore, the request is not authorized.",
"An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
"No grants are applicable to the request. Therefore, the request is implicitly denied and is not authorized."
]
},
"error": {
"description": "Error information if the operation failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
},
"error": {
"description": "Error information if the batch operation failed, or null if successful.",
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"required": [
"error_type",
"message"
],
"properties": {
"error_type": {
"type": "string",
"description": "The type/category of the error."
},
"message": {
"type": "string",
"description": "Detailed message about what caused the error."
}
}
}
]
}
}
}
#SDK Full Example
This comprehensive example demonstrates the full lifecycle of using the Authzee SDK with the new API.
from authzee import Authzee, InProcessCompute, InProcessStorage, jmespath_execute, paginator
# Create an Authzee instance with the config param
storage = {}
authz = Authzee(
execute=jmespath_execute,
compute_type=InProcessCompute,
compute_kwargs={},
storage_type=InProcessStorage,
storage_kwargs={
"storage_ptr": storage
},
config={
"authzee": {
"raise_errors": True
},
"list_grants": {
"page_size": 50
}
}
)
# One time creation and setup of resources
authz.construct()
# Initialization and creation of runtime resources
authz.start()
# --- Define context, identity, and resource ---
context_def = {
"context_type": "Team",
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"Team"
],
"properties": {
"Team": {
"type": "string"
}
}
}
}
authz.put_context_def(context_def)
identity_def = {
"identity_type": "User",
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"username",
"email",
"department"
],
"properties": {
"username": {
"type": "string"
},
"email": {
"type": "string"
},
"department": {
"type": "string"
}
}
}
}
authz.put_identity_def(identity_def)
resource_def = {
"resource_type": "Balloon",
"actions": [
"Balloon:Inflate",
"Balloon:Deflate",
"Balloon:ListBalloons"
],
"schema": {
"type": "object",
"additionalProperties": False,
"required": [
"color",
"size",
"psi",
"is_inflated"
],
"properties": {
"color": {
"type": "string",
"enum": [
"green",
"purple"
]
},
"size": {
"type": "number",
"minimum": 0
},
"psi": {
"type": "number",
"minimum": 0
},
"is_inflated": {
"type": "boolean"
}
}
}
}
authz.put_resource_def(resource_def)
# --- Validate definitions ---
context_val_result = authz.validate_context_def(context_def)
print(context_val_result)
# {"error": None}
identity_val_result = authz.validate_identity_def(identity_def)
print(identity_val_result)
# {"error": None}
resource_val_result = authz.validate_resource_def(resource_def)
print(resource_val_result)
# {"error": None}
# --- Enact a grant ---
grant = authz.enact(
{
"name": "Balloon Sales Inflate",
"description": "Allow people in the Balloon Sales department to inflate balloons.",
"tags": {
"department": "sales"
},
"effect": "allow",
"actions": [
"Balloon:Inflate"
],
"query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
"equality": True,
"data": {
"allowed_departments": [
"Maintenance",
"Balloon Sales"
]
}
}
)
# --- Validate a grant ---
grant_val_result = authz.validate_grant(grant)
print(grant_val_result)
# {"error": None}
# --- List definitions using paginator ---
for page in paginator(authz.list_context_defs):
print(page)
# {
# "context_defs": [...],
# "error": None,
# "next_page_ref": None
# }
for page in paginator(authz.list_identity_defs):
print(page)
# {
# "identity_defs": [...],
# "error": None,
# "next_page_ref": None
# }
for page in paginator(authz.list_resource_defs):
print(page)
# {
# "resource_defs": [...],
# "error": None,
# "next_page_ref": None
# }
# --- List grants with effect/action filters using paginator ---
for page in paginator(
authz.list_grants,
effect="allow",
action="Balloon:Inflate"
):
print(page)
# {
# "grants": [...],
# "error": None,
# "next_page_ref": None
# }
# --- Get a specific definition by type ---
context_def_result = authz.get_context_def("Team")
print(context_def_result)
# {
# "context_def": {
# "context_type": "Team",
# "schema": {...}
# },
# "error": None
# }
# --- Validate and authorize a request ---
request = {
"identities": {
"User": [
{
"username": "tester",
"email": "tester@example.com",
"department": "Balloon Sales"
}
]
},
"action": "Balloon:Inflate",
"resource_type": "Balloon",
"resource": {
"color": "green",
"size": 2.7,
"psi": 7.2,
"is_inflated": True
},
"context_type": "Team",
"context": {
"Team": "My Team"
}
}
validate_result = authz.validate_request(request)
print(validate_result)
# {"error": None}
authorize_result = authz.authorize(request)
print(authorize_result)
# {
# "is_authorized": True,
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales Inflate",
# "description": "Allow people in the Balloon Sales department to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "contains(request.identities, 'User') && length(request.identities.User) > `0` && contains(grant.data.allowed_departments, request.identities.User[0].department)",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
# "error": None
# }
# --- Audit with effect/action filters ---
for page in paginator(
authz.audit,
request=request,
effect="allow",
action="Balloon:Inflate"
):
print(page)
# {
# "results": [
# {
# "is_applicable": True,
# "query_result": True,
# "grant": {...},
# "failure": None
# }
# ],
# "error": None,
# "next_page_ref": None
# }
# --- Batch authorize ---
batch_request = {
"identities": {
"User": [
{
"username": "tester",
"email": "tester@example.com",
"department": "Balloon Sales"
}
]
},
"action": "Balloon:Inflate",
"resource_type": "Balloon",
"resource": {
"color": "green",
"size": 2.7,
"psi": 7.2,
"is_inflated": True
},
"context_type": "Team",
"context": {
"Team": "My Team"
},
"batch": [
{},
{
"identities": {
"User": [
{
"username": "tester2",
"email": "tester2@example.com",
"department": "Balloon Popper"
}
]
}
}
]
}
batch_authorize_result = authz.batch_authorize(batch_request)
print(batch_authorize_result)
# {
# "batch": [
# {
# "is_authorized": True,
# "grant": {
# "grant_uuid": "8df01e31-819e-45e4-a06b-95d25b89e927",
# "name": "Balloon Sales Inflate",
# "description": "Allow people in the Balloon Sales department to inflate balloons.",
# "effect": "allow",
# "actions": [
# "Balloon:Inflate"
# ],
# "query": "...",
# "equality": True,
# "applicable_on_failure": False,
# "data": {
# "allowed_departments": [
# "Maintenance",
# "Balloon Sales"
# ]
# }
# },
# "message": "An allow grant is applicable to the request, and there are no deny grants that are applicable to the request. Therefore, the request is authorized.",
# "error": None
# },
# {
# "is_authorized": False,
# "grant": None,
# "message": "No grants are applicable to the request. Therefore, the request is implicitly denied and is not authorized.",
# "error": None
# }
# ],
# "error": None
# }
# --- Batch audit with effect/action filters ---
for page in paginator(
authz.batch_audit,
batch_request=batch_request,
effect="allow",
action="Balloon:Inflate"
):
print(page)
# {
# "results": [
# {
# "grant": {...},
# "batch": [
# {
# "is_applicable": True,
# "query_result": True,
# "failure": None
# },
# {
# "is_applicable": False,
# "query_result": False,
# "failure": None
# }
# ]
# }
# ],
# "error": None,
# "next_page_ref": None
# }
# --- Shutdown ---
authz.shutdown()
#Standard JMESPath Extensions
JMESPath is also the preferred JSON query language for Authzee as it has a specification and JMESPath SDKs generally offer the ability extend functionality by making new functions available in JMESPath queries. Because of this, Authzee SDKs should also offer a set of out of the box JMESPath functions the are helpful to Authzee grant queries.
- INNER JOIN - Join 2 arrays in a fashion similar to an SQL INNER JOIN.
- LEFT JOIN - Join 2 arrays in a fashion similar to an SQL LEFT JOIN.
- OUTER JOIN - Join 2 arrays in a fashion similar to an SQL OUTER JOIN.
- Is Identity Present - Check if the given identity type is in the request and at least one instance was given.
- regex Find - Run a regex pattern on a string or array of strings to find the first match.
- regex Find All - Run a regex pattern on a string or array of strings to find all matches.
- regex Groups - Run a regex pattern on a string or array of strings to find the first match, and extract the groups.
- regex Groups All - Run a regex pattern on a string or array of strings to find all matches, and extract the groups.
- String Lower - Convert string to lower case.
- String Upper - Convert string to upper case.
The sections are given in the same format as the JMESPath Built-in Function Specification
#INNER JOIN
array[object] inner_join(array[any] $lhs, array[any] $rhs, expression->boolean expr)
Modeled after SQL INNER JOIN functionality. Takes 2 arrays and an expression and returns all combinations of elements from the arrays where the expression evaluates to true.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
Simple python function example:
from typing import Any, Dict, List
import jmespath
def inner_join(lhs: List[Any], rhs: List[Any], expr: str) -> List[Dict[str, Any]]:
result = []
for l in lhs:
for r in rhs:
if jmespath.search( # Should use jmespath search function set in Authzee.
expr,
{
"lhs": l,
"rhs": r
}
) is True:
result.append(
{
"lhs": l,
"rhs": r
}
)
return result
#LEFT JOIN
array[object] left_join(array[any] $lhs, array[any] $rhs, expression->boolean expr)
Modeled after SQL LEFT JOIN functionality. Takes 2 arrays and an expression and returns all combinations of elements from the arrays where the expression evaluates to true. If an element from the left hand side does match any elements from the right hand side, then the left hand side element is returned with null for the right hand side.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
Simple python function example:
from typing import Any, Dict, List
import jmespath
def left_join(lhs: List[Any], rhs: List[Any], expr: str) -> List[Dict[str, Any]]:
result = []
for l in lhs:
lhs_match = False
for r in rhs:
if jmespath.search( # Should use jmespath search function set in Authzee.
expr,
{
"lhs": l,
"rhs": r
}
) is True:
lhs_match = True
result.append(
{
"lhs": l,
"rhs": r
}
)
if lhs_match is False:
result.append(
{
"lhs": l,
"rhs": None
}
)
return result
#OUTER JOIN
array[object] outer_join(array[any] $lhs, array[any] $rhs, expression->boolean expr)
Modeled after SQL FULL OUTER JOIN functionality. Takes 2 arrays and an expression and returns all combinations of elements from the arrays where the expression evaluates to true. If an element from the left hand side does match any elements from the right hand side, then the left hand side element is returned with null for the right hand side. If an element from the right hand side does match any elements from the left hand side, then the right hand side element is returned with null for the left hand side.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
Simple python function example:
from typing import Any, Dict, List
import jmespath
def outer_join(lhs: List[Any], rhs: List[Any], expr: str) -> List[Dict[str, Any]]:
result = []
unmatched_rhs = set(rhs)
for l in lhs:
lhs_match = False
for r in rhs:
if jmespath.search( # Should use jmespath search function set in Authzee.
expr,
{
"lhs": l,
"rhs": r
}
) is True:
unmatched_rhs.discard(r)
lhs_match = True
result.append(
{
"lhs": l,
"rhs": r
}
)
if lhs_match is False:
result.append(
{
"lhs": l,
"rhs": None
}
)
for r in unmatched_rhs:
result.append(
{
"lhs": None,
"rhs": r
}
)
return result
#Is Identity Present
boolean is_identity_present(string $itype, object $request)
Return true if the given identity type exists in the request and it has one or more instances present, or else return false.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
|
|
Simple Python Example:
def is_identity_present(itype: str, request: dict) -> bool:
if itype in request['identities'] and len(request['identities'][itype]) > 0:
return True
return False
#regex Find
string|null|array[string|null] regex_find(string $pattern, string|array[string] $subject)
WARNING! - Regex evaluation differs based on the underlying language/library implementation. Regex evaluation is not standardized across programming languages, and it's not expected for the SDKs to create standard regex evaluation at this point. The general functionality of the JMESPath custom functions should match between languages though.
The return value depends on the subject type:
string- Run a regex pattern against a string and return the first occurrence of the pattern ornullif there are none.array[string]- Run a regex pattern on an array of strings and return an equal length array where each element is the first occurrence of the pattern ornullif there are none.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
|
|
|
|
Simple Python Example:
import re
from typing import List, Union
def regex_find(pattern: str, subject: Union[str, List[str]]) -> Union[None, str, List[Union[None, str]]]:
if type(subject) is str:
match = re.search(pattern, subject)
if match is not None:
return match.group()
else:
return None
if type(subject) is list:
result = []
for sub in subject:
match = re.search(pattern, sub)
if match is not None:
result.append(match.group())
else:
result.append(None)
return result
#regex Find All
array[string]|array[array[string]] regex_find_all(string $pattern, string|array[string] $subject)
WARNING! - Regex evaluation differs based on the underlying language/library implementation. Regex evaluation is not standardized across programming languages, and it's not expected for the SDKs to create standard regex evaluation at this point. The general functionality of the JMESPath custom functions should match between languages though.
The return value depends on the subject type:
string- Run a regex pattern against a string and return an array of all occurrences of the pattern in the string.array[string]- Run a regex pattern on an array of strings and return an equal length array of results where each element is an array of all occurrences of the pattern in the string.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
|
|
|
|
Simple Python Example:
import re
from typing import List, Union
def regex_find_all(pattern: str, subject: Union[str, List[str]]) -> Union[List[str], List[List[str]]]:
if type(subject) is str:
return re.findall(pattern, subject)
if type(subject) is list:
result = []
for sub in subject:
result.append(re.findall(pattern, sub))
return result
#regex Groups
null|array[string|null]|array[array[string|null]|null] regex_groups(string|array[string] $subject, string $pattern)
WARNING! - Regex evaluation differs based on the underlying language/library implementation. Regex evaluation is not standardized across programming languages, and it's not expected for the SDKs to create standard regex evaluation at this point. The general functionality of the JMESPath custom functions should match between languages though.
The return value depends on the subject type:
string- Run a regex pattern against a string and return an array of all groups from the first occurrence of the pattern, ornullif there are no pattern matches. If a group has no value it will benull.array[string]- Run a regex pattern on an array of strings and return an equal length array where each element is an array of groups from the first occurrence of the pattern ornullif there are no pattern matches. If a group has no value it will benull.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Simple Python Example:
import re
from typing import List, Union
def regex_groups(
pattern: str,
subject: Union[str, List[str]]
) -> Union[
None,
List[Union[None, str]],
List[
Union[
None,
List[
Union[None, str]
]
]
]
]:
if type(subject) is str:
match = re.search(pattern, subject)
if match is not None:
return list(match.groups())
else:
return None
if type(subject) is list:
result = []
for sub in subject:
match = re.search(pattern, sub)
if match is not None:
result.append(list(match.groups()))
else:
result.append(None)
return result
#regex Groups All
array[array[string|null]]|array[array[array[string|null]]] regex_groups_all(string|array[string] $subject, string $pattern)
WARNING! - Regex evaluation differs based on the underlying language/library implementation. Regex evaluation is not standardized across programming languages, and it's not expected for the SDKs to create standard regex evaluation at this point. The general functionality of the JMESPath custom functions should match between languages though.
The return value depends on the subject type:
string- Run a regex pattern against a string and return an array where each item is an array of groups for each occurrence of the pattern. If a group has no value it will benull.array[string]- Run a regex pattern on an array of strings and return an equal length array where each element is an array of all occurrences of the pattern. Each element in the array of occurrences is an array of the groups. If a group has no value it will benull.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Simple Python Example
import re
from typing import List, Union
def regex_groups_all(pattern: str, subject: Union[str, List[str]]) -> Union[List[str], List[List[str]]]:
if type(subject) is str:
return [list(m.groups()) if m is not None else None for m in re.finditer(pattern, subject)]
if type(subject) is list:
result = []
for sub in subject:
result.append(
[list(m.groups()) if m is not None else None for m in re.finditer(pattern, sub)]
)
return result
#String Lower
string lower(string $subject)
Convert the subject string to lowercase.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
Simple python function example:
def lower(subject: str) -> str:
return subject.lower()
#String Upper
string upper(string $subject)
Convert the subject string to uppercase.
Examples:
| Expression | Result |
|---|---|
|
|
|
|
Simple python function example:
def upper(subject: str) -> str:
return subject.upper()