Authzee

#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:

Language Code Repo Package Repo Authzee Compliant Maintained SDK Standard Official Notes
python btemplep/authzee-py authzee - pypi.org

#Table of Contents

#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

These docs will use python as the example language. For languages that don't support Classes and methods, translate as well as you can:

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:

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:

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 - audit and authorize functions 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_audit and batch_authorize functions 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:

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):

  1. Default config values — The built-in defaults shown below.
  2. Instance-level config — Passed via the config parameter at Authzee construction. Only provided keys override the defaults.
  3. Method-call config override — Passed via the config parameter 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 Authzee app 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: effect and action. 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.

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:

#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

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:

#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:

#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:

#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.

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
inner_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other thing"
        }
    },
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    }
]           
inner_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[]

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
left_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other thing"
        }
    },
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    }
]           
left_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": null
    }
]           

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
outer_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other thing"
        },
        {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other thing"
        }
    },
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": {
            "r_field": "hello",
            "r_other_field": "other other other thing"
        }
    },
    {
        "lhs": null,
        "rhs": {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    }
]           
outer_join(
    `[
        {
            "l_field": "hello",
            "other_field": "thing"
        },
        {
            "l_field": "goodbye",
            "other_field": "another thing"
        },
        {
            "l_field": "goodbye",
            "other_field": "another another thing"
        }
    ]`,
    `[
        {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    ]`,
    lhs.l_field == rhs.r_field
) 
[
    {
        "lhs": {
            "l_field": "hello",
            "other_field": "thing"
        },
        "rhs": null
    },
    {
        "lhs": {
            "l_field": "goodbye",
            "other_field": "another thing"
        },
        "rhs": {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    },
    {
        "lhs": {
            "l_field": "goodbye",
            "other_field": "another another thing"
        },
        "rhs": {
            "r_field": "goodbye",
            "r_other_field": "other thing"
        }
    }
]           

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
is_identity_present("ADGroup", `{"identities": {"ADUser": []}}`)
false
is_identity_present("ADGroup", `{"identities": {"ADGroup": []}}`)
false
is_identity_present("ADGroup", `{"identities": {"ADGroup": [{"name": "thing"}]}}`)
true

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:

Examples:

Expression Result
regex_find('pattern.*', 'some string here')
null
regex_find('string.+', 'some string here')
"string here"
regex_find('string.+', `["something", "here"]`)
[null, null]
regex_find('string.+', `["something", "a string now", "here"]`)
[null, "string now", null]

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:

Examples:

Expression Result
regex_find_all('pattern', 'some string here')
[]
regex_find_all('string[0-9]', 'some string3 here string4')
["string3", "string4"]
regex_find_all('string.+', `["something", "here"]`)
[[], []]
regex_find_all(
    'string[0-9]',
    `[
        "something",
        "a string2 now string7 too",
        "here", 
        "another string3 here"
    ]`
)
[
    [], 
    [
        "string2", 
        "string7"
    ], 
    [], 
    [
        "string3"
    ]
]

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:

Examples:

Expression Result
regex_groups('pattern.*', 'some string here')
null
regex_groups('string.+', 'some string here')
[]
regex_groups(
    'string (my_group[0-4])|string (my_other_group[5-9])', 
    'a string my_other_group9 another string my_group2'
)
[null, "my_group9"]
regex_groups('string.+', `["something", "here"]`)
[null, null]
regex_groups('string.+', `["something", "a string now", "here"]`)
[null, [], null]
regex_groups(
    'string (my_group[0-4])|string (my_other_group[5-9])', 
    `[
        "something", 
        "a string my_other_group9 another string my_group2", 
        "here"
    ]`
)
[null, [null, "my_group9"], null]

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:

Examples:

Expression Result
regex_groups_all('pattern.*', 'some string here')
[]
regex_groups_all('string.+', 'some string here')
[[]]
regex_groups_all(
    'string (my_group[0-4])|string (my_other_group[5-9])', 
    'a string my_other_group9 another string my_group2'
)
[
    [
        null, 
        "my_group9"
    ], 
    [
        "my_group2", 
        null
    ]
]
regex_groups_all('string.+', `["something", "here"]`)
 [[], []]
regex_groups_all('string.+', `["something", "a string now", "here"]`)
[[], [[]], []]
regex_groups_all(
    'string (my_group[0-4])|string (my_other_group[5-9])', 
    `[
        "something", 
        "a string my_other_group9 another string my_group2", 
        "here"
    ]`
)
[
    [],
    [
        [
            null, 
            "my_group9"
        ],
        [
            "my_group2",
            null
        ]
    ], 
    []
]

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
lower('BALLOON')
"balloon"
lower('balloon')
"balloon"

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
upper('balloon')
"BALLOON"
upper('BALLOON')
"BALLOON"

Simple python function example:

def upper(subject: str) -> str:
    return subject.upper()