syntax = "proto3"; package authzed.api.v1; option go_package = "github.com/authzed/authzed-go/proto/authzed/api/v1"; option java_package = "com.authzed.api.v1"; import "google/protobuf/struct.proto"; import "google/api/annotations.proto"; import "validate/validate.proto"; import "authzed/api/v1/core.proto"; // PermissionsService implements a set of RPCs that perform operations on // relationships and permissions. service PermissionsService { // ReadRelationships reads a set of the relationships matching one or more // filters. rpc ReadRelationships(ReadRelationshipsRequest) returns (stream ReadRelationshipsResponse) { option (google.api.http) = { post: "/v1/relationships/read" body: "*" }; } // WriteRelationships atomically writes and/or deletes a set of specified // relationships. An optional set of preconditions can be provided that must // be satisfied for the operation to commit. rpc WriteRelationships(WriteRelationshipsRequest) returns (WriteRelationshipsResponse) { option (google.api.http) = { post: "/v1/relationships/write" body: "*" }; } // DeleteRelationships atomically bulk deletes all relationships matching the // provided filter. If no relationships match, none will be deleted and the // operation will succeed. An optional set of preconditions can be provided that must // be satisfied for the operation to commit. rpc DeleteRelationships(DeleteRelationshipsRequest) returns (DeleteRelationshipsResponse) { option (google.api.http) = { post: "/v1/relationships/delete" body: "*" }; } // CheckPermission determines for a given resource whether a subject computes // to having a permission or is a direct member of a particular relation. rpc CheckPermission(CheckPermissionRequest) returns (CheckPermissionResponse) { option (google.api.http) = { post: "/v1/permissions/check" body: "*" }; } // ExpandPermissionTree reveals the graph structure for a resource's // permission or relation. This RPC does not recurse infinitely deep and may // require multiple calls to fully unnest a deeply nested graph. rpc ExpandPermissionTree(ExpandPermissionTreeRequest) returns (ExpandPermissionTreeResponse) { option (google.api.http) = { post: "/v1/permissions/expand" body: "*" }; } // LookupResources returns all the resources of a given type that a subject // can access whether via a computed permission or relation membership. rpc LookupResources(LookupResourcesRequest) returns (stream LookupResourcesResponse) { option (google.api.http) = { post: "/v1/permissions/resources" body: "*" }; } // LookupSubjects returns all the subjects of a given type that // have access whether via a computed permission or relation membership. rpc LookupSubjects(LookupSubjectsRequest) returns (stream LookupSubjectsResponse) { option (google.api.http) = { post: "/v1/permissions/subjects" body: "*" }; } } // Consistency will define how a request is handled by the backend. // By defining a consistency requirement, and a token at which those // requirements should be applied, where applicable. message Consistency { oneof requirement { option (validate.required) = true; // minimize_latency indicates that the latency for the call should be // minimized by having the system select the fastest snapshot available. bool minimize_latency = 1 [ (validate.rules).bool.const = true ]; // at_least_as_fresh indicates that all data used in the API call must be // *at least as fresh* as that found in the ZedToken; more recent data might // be used if available or faster. ZedToken at_least_as_fresh = 2; // at_exact_snapshot indicates that all data used in the API call must be // *at the given* snapshot in time; if the snapshot is no longer available, // an error will be returned to the caller. ZedToken at_exact_snapshot = 3; // fully_consistent indicates that all data used in the API call *must* be // at the most recent snapshot found. // // NOTE: using this method can be *quite slow*, so unless there is a need to // do so, it is recommended to use `at_least_as_fresh` with a stored // ZedToken. bool fully_consistent = 4 [ (validate.rules).bool.const = true ]; } } // RelationshipFilter is a collection of filters which when applied to a // relationship will return relationships that have exactly matching fields. // // resource_type is required. All other fields are optional and if left // unspecified will not filter relationships. message RelationshipFilter { string resource_type = 1 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$", max_bytes : 128, } ]; string optional_resource_id = 2 [ (validate.rules).string = { pattern : "^([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})?$", max_bytes : 128, } ]; string optional_relation = 3 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; SubjectFilter optional_subject_filter = 4; } // SubjectFilter specifies a filter on the subject of a relationship. // // subject_type is required and all other fields are optional, and will not // impose any additional requirements if left unspecified. message SubjectFilter { message RelationFilter { string relation = 1 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; } string subject_type = 1 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$", max_bytes : 128, } ]; string optional_subject_id = 2 [ (validate.rules).string = { pattern : "^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)?$", max_bytes : 128, } ]; RelationFilter optional_relation = 3; } // ReadRelationshipsRequest specifies one or more filters used to read matching // relationships within the system. message ReadRelationshipsRequest { Consistency consistency = 1; RelationshipFilter relationship_filter = 2 [ (validate.rules).message.required = true ]; } // ReadRelationshipsResponse contains a Relationship found that matches the // specified relationship filter(s). A instance of this response message will // be streamed to the client for each relationship found. message ReadRelationshipsResponse { ZedToken read_at = 1 [ (validate.rules).message.required = true ]; Relationship relationship = 2 [ (validate.rules).message.required = true ]; } // Precondition specifies how and the existence or absence of certain // relationships as expressed through the accompanying filter should affect // whether or not the operation proceeds. // // MUST_NOT_MATCH will fail the parent request if any relationships match the // relationships filter. // MUST_MATCH will fail the parent request if there are no // relationships that match the filter. message Precondition { enum Operation { OPERATION_UNSPECIFIED = 0; OPERATION_MUST_NOT_MATCH = 1; OPERATION_MUST_MATCH = 2; } Operation operation = 1 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ]; RelationshipFilter filter = 2 [ (validate.rules).message.required = true ]; } // WriteRelationshipsRequest contains a list of Relationship mutations that // should be applied to the service. If the optional_preconditions parameter // is included, all of the specified preconditions must also be satisfied before // the write will be committed. message WriteRelationshipsRequest { repeated RelationshipUpdate updates = 1 [ (validate.rules).repeated .items.message.required = true ]; repeated Precondition optional_preconditions = 2 [ (validate.rules).repeated .items.message.required = true ]; // To be bounded by configuration } message WriteRelationshipsResponse { ZedToken written_at = 1; } // DeleteRelationshipsRequest specifies which Relationships should be deleted, // requesting the delete of *ALL* relationships that match the specified // filters. If the optional_preconditions parameter is included, all of the // specified preconditions must also be satisfied before the delete will be // executed. message DeleteRelationshipsRequest { RelationshipFilter relationship_filter = 1 [ (validate.rules).message.required = true ]; repeated Precondition optional_preconditions = 2 [ (validate.rules).repeated .items.message.required = true ]; // To be bounded by configuration } message DeleteRelationshipsResponse { ZedToken deleted_at = 1; } // CheckPermissionRequest issues a check on whether a subject has a permission // or is a member of a relation, on a specific resource. message CheckPermissionRequest { Consistency consistency = 1; // resource is the resource on which to check the permission or relation. ObjectReference resource = 2 [ (validate.rules).message.required = true ]; // permission is the name of the permission (or relation) on which to execute // the check. string permission = 3 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; // subject is the subject that will be checked for the permission or relation. SubjectReference subject = 4 [ (validate.rules).message.required = true ]; /** context consists of named values that are injected into the caveat evaluation context **/ google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ]; } message CheckPermissionResponse { enum Permissionship { PERMISSIONSHIP_UNSPECIFIED = 0; PERMISSIONSHIP_NO_PERMISSION = 1; PERMISSIONSHIP_HAS_PERMISSION = 2; PERMISSIONSHIP_CONDITIONAL_PERMISSION = 3; } ZedToken checked_at = 1 [ (validate.rules).message.required = false ]; // Permissionship communicates whether or not the subject has the requested // permission or has a relationship with the given resource, over the given // relation. // // This value will be authzed.api.v1.PERMISSIONSHIP_HAS_PERMISSION if the // requested subject is a member of the computed permission set or there // exists a relationship with the requested relation from the given resource // to the given subject. Permissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ]; // partial_caveat_info holds information of a partially-evaluated caveated response PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ]; } // ExpandPermissionTreeRequest returns a tree representing the expansion of all // relationships found accessible from a permission or relation on a particular // resource. // // ExpandPermissionTreeRequest is typically used to determine the full set of // subjects with a permission, along with the relationships that grant said // access. message ExpandPermissionTreeRequest { Consistency consistency = 1; // resource is the resource over which to run the expansion. ObjectReference resource = 2 [ (validate.rules).message.required = true ]; // permission is the name of the permission or relation over which to run the // expansion for the resource. string permission = 3 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; } message ExpandPermissionTreeResponse { ZedToken expanded_at = 1; // tree_root is a tree structure whose leaf nodes are subjects, and // intermediate nodes represent the various operations (union, intersection, // exclusion) to reach those subjects. PermissionRelationshipTree tree_root = 2; } // LookupResourcesRequest performs a lookup of all resources of a particular // kind on which the subject has the specified permission or the relation in // which the subject exists, streaming back the IDs of those resources. message LookupResourcesRequest { Consistency consistency = 1; // resource_object_type is the type of resource object for which the IDs will // be returned. string resource_object_type = 2 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$", max_bytes : 128, } ]; // permission is the name of the permission or relation for which the subject // must Check. string permission = 3 [ (validate.rules).string = { pattern : "^[a-z][a-z0-9_]{1,62}[a-z0-9]$", max_bytes : 64, } ]; // subject is the subject with access to the resources. SubjectReference subject = 4 [ (validate.rules).message.required = true ]; /** context consists of named values that are injected into the caveat evaluation context **/ google.protobuf.Struct context = 5 [ (validate.rules).message.required = false ]; } // LookupPermissionship represents whether a Lookup response was partially evaluated or not enum LookupPermissionship { LOOKUP_PERMISSIONSHIP_UNSPECIFIED = 0; LOOKUP_PERMISSIONSHIP_HAS_PERMISSION = 1; LOOKUP_PERMISSIONSHIP_CONDITIONAL_PERMISSION = 2; } // LookupResourcesResponse contains a single matching resource object ID for the // requested object type, permission, and subject. message LookupResourcesResponse { ZedToken looked_up_at = 1; string resource_object_id = 2; // permissionship indicates whether the response was partially evaluated or not LookupPermissionship permissionship = 3 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ]; // partial_caveat_info holds information of a partially-evaluated caveated response PartialCaveatInfo partial_caveat_info = 4 [ (validate.rules).message.required = false ]; } // LookupSubjectsRequest performs a lookup of all subjects of a particular // kind for which the subject has the specified permission or the relation in // which the subject exists, streaming back the IDs of those subjects. message LookupSubjectsRequest { Consistency consistency = 1; // resource is the resource for which all matching subjects for the permission // or relation will be returned. ObjectReference resource = 2 [ (validate.rules).message.required = true ]; // permission is the name of the permission (or relation) for which to find // the subjects. string permission = 3 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; // subject_object_type is the type of subject object for which the IDs will // be returned. string subject_object_type = 4 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$", max_bytes : 128, } ]; // optional_subject_relation is the optional relation for the subject. string optional_subject_relation = 5 [ (validate.rules).string = { pattern : "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$", max_bytes : 64, } ]; /** context consists of named values that are injected into the caveat evaluation context **/ google.protobuf.Struct context = 6 [ (validate.rules).message.required = false ]; } // LookupSubjectsResponse contains a single matching subject object ID for the // requested subject object type on the permission or relation. message LookupSubjectsResponse { ZedToken looked_up_at = 1; // subject_object_id is the Object ID of the subject found. May be a `*` if // a wildcard was found. // deprecated: use `subject` string subject_object_id = 2 [deprecated = true]; // excluded_subject_ids are the Object IDs of the subjects excluded. This list // will only contain object IDs if `subject_object_id` is a wildcard (`*`) and // will only be populated if exclusions exist from the wildcard. // deprecated: use `excluded_subjects` repeated string excluded_subject_ids = 3 [deprecated = true]; // permissionship indicates whether the response was partially evaluated or not // deprecated: use `subject.permissionship` LookupPermissionship permissionship = 4 [ deprecated = true, (validate.rules).enum = {defined_only: true, not_in: [0]} ]; // partial_caveat_info holds information of a partially-evaluated caveated response // deprecated: use `subject.partial_caveat_info` PartialCaveatInfo partial_caveat_info = 5 [ deprecated = true, (validate.rules).message.required = false ]; // subject is the subject found, along with its permissionship. ResolvedSubject subject = 6; // excluded_subjects are the subjects excluded. This list // will only contain subjects if `subject.subject_object_id` is a wildcard (`*`) and // will only be populated if exclusions exist from the wildcard. repeated ResolvedSubject excluded_subjects = 7; } // ResolvedSubject is a single subject resolved within LookupSubjects. message ResolvedSubject { // subject_object_id is the Object ID of the subject found. May be a `*` if // a wildcard was found. string subject_object_id = 1; // permissionship indicates whether the response was partially evaluated or not LookupPermissionship permissionship = 2 [ (validate.rules).enum = {defined_only: true, not_in: [0]} ]; // partial_caveat_info holds information of a partially-evaluated caveated response PartialCaveatInfo partial_caveat_info = 3 [ (validate.rules).message.required = false ]; }