Office Hours: ACL-aware filtering in your own database with SpiceDB and AuthZed Materialize

Announcing Reflection APIs in SpiceDB

/assets/team/joey-schorr.jpg
June 3, 2024|5 min read

Today we’re happy to announce the addition of new experimental reflection APIs to SpiceDB, starting in version v1.33.0!

These four reflection APIs are the result of a proposal created by the community. The new reflection APIs provide lower level information about the SpiceDB schema, including its relations and permissions, all using the same type system and schema compiler used in production, ensuring it matches SpiceDB’s own understanding.

As with every new API, we’ve added these to the experimental package so the community can start testing and providing early feedback, with the goal of eventually graduating once the API has been battle-tested and its design has stabilized.

Below we briefly summarize each reflection API, its purpose, and how it might be used to make certain use-cases with SpiceDB easier.

Let’s start with a sample schema and see how each API interacts with it:

definition user {}

definition organization {
  relation member: user
}

// resource is some kind of resource
definition resource {
  relation viewer: user
  relation editor: user

  relation org: organization

  permission edit = editor
  permission view = viewer + editor + org->member
}

Here we have a fairly simple resource that has two roles of viewer and editor that grant the view permission, as well allowing any member of the resource’s organization to also view the resource.

NOTE: The reflection APIs are not intended to be used for parsing/understanding schema in offline tools. If you need a parsing system as part of offline tooling, please use the packages exported by SpiceDB in the pkg package.

ExperimentalReflectSchema

ExperimentalReflectSchema provides an API-driven means of receiving the structure of the current schema stored in SpiceDB.

It is designed primarily to allow callers to make dynamic decisions based on the structure of the schema, such as being able to see all the permissions defined for a particular type of resource.

Example: an application dynamically loads roles to be granted to a user in a permissions management UI. Instead of hardcoding the roles, you can now query the SpiceDB ReflectSchema and read the relations of a specific resource type.

Executing ExperimentalReflectSchema for our sample schema produces:

ExperimentalReflectSchemaRequest{}

ExperimentalReflectSchemaResponse{
  Definitions: []{
     { Name: "user" },
     {
        Name: "organization",
        Relations: []{
           { Name: "member", SubjectTypes: []{ { Name: "user" } }, ... },
        },
     },
     {
       Name: "resource",
       Comment: "// resource is some kind of resource",
       Relations: []{ ... },
       Permissions: []{ ... },
     },
  },
}

ExperimentalReflectSchemaRequest also includes support for prefix filters which can be used to filter the response to a specific subset of the schema:

ExperimentalReflectSchemaRequest{
  OptionalFilters: []{
     {
        OptionalDefinitionNameFilter: "a" // filter to defs starting with `a`
     },
  },
}

NOTE: We strongly recommend caching the result of ExperimentalReflectSchema if it is being used to drive CheckPermission requests; while the process is not that slow, it does require a full load of the schema to compute the structure.

ExperimentalDiffSchema

ExperimentalDiffSchema provides an API-driven means of comparing the currently stored schema in SpiceDB to another schema.

This API is useful for tooling such as CI/CD that needs to determine what changes, if any, exist between the current schema and a future schema:

Example: a platform team has built a pipeline to help ship schema changes to a platform-wide centralized SpiceDB cluster. The automation in place helps the developer visualize the effective changes that are going to be deployed, like for example identifying potential breaking changes ahead of the WriteSchema call.

Calling ExperimentalDiffSchema against our schema above with a sample schema:

ExperimentalDiffSchema{
  ComparisonSchema: ```
    definition user  {}
    
    // an added comment
    definition organization {
      relation member: user
    }

    // resource is some kind of resource
    definition resource {
      relation viewer: user
      relation editor: user

      relation org: organization

      permission edit = editor
      permission view = viewer + editor + org->member
    }
  ```
}

ExperimentalReflectSchemaResponse{
  Diffs: []{
     { DefinitionDocCommentChanged: { Name: "organization", ... } },
     { PermissionExprChanged: { Name: "view", ... } },    
  }
}

The difference information provided by ExperimentalDiffSchemaexactly matches what is provided by the schema diff package in the pkg directory of SpiceDB.

ExperimentalDependentRelations

ExperimentalDependentRelations is a reflection API that provides the list of relations and permissions that are used to compute a particular permission.

Calling ExperimentalDependentRelations on the sample schema above:

ExperimentalDependentRelationsRequest{
  DefinitionName: "resource"
  PermissionName: "view"
}

Returns:

ExperimentalDependentRelationsResponse{
  Relations: []{
     { DefinitionName: "organization", RelationName: "member", IsPermission: false},
      { DefinitionName: "resource", RelationName: "org", IsPermission: false},
     { DefinitionName: "resource", RelationName: "viewer", IsPermission: false},
     { DefinitionName: "resource", RelationName: "edit", IsPermission: true},
     { DefinitionName: "resource", RelationName: "editor", IsPermission: false},
  }
}

Note that both relations and permissions are returned.

ExperimentalDependentRelations is useful for determining all the nested relations and permissions that may impact the computation of a permission.

ExperimentalComputablePermissions

ExperimentalComputablePermissions is the inverse of ExperimentalDependentRelations: it helps to determine any permissions impacted by a change to a relation or permission.

For example, given the same schema as above, calling ExperimentalComputablePermissions like so:

ExperimentalComputablePermissionsRequest{
  DefinitionName: "resource"
  RelationName: "viewer"
}

Will return:

ExperimentalComputablePermissionsResponse{
  Permissions: []{
    { DefinitionName: "resource", RelationName: "view", IsPermission: true},
  }
}

ExperimentalComputablePermissions is useful for callers to determine the list of permissions that may be modified by updating a relationship on a particular relation or a change to a particular permission.

Conclusion

We hope you find these new reflection APIs useful in your authorization journey. If you have any questions, concerns or ideas on the new APIs, please do not hesitate to provide feedback in the SpiceDB Discord.

Get started for free

Join 1000s of companies doing authorization the right way.