SGL Reference

NOTE 1: SGL can be rendered in various styles. The definitions given here in the reference section just use the recommended JSON rendering, for conciseness and simplicity. With the documentation on renderings, you should be able to interpolate into ProtoBuf, MsgPack, CBOR, human-friendly text, or another style if that is of interest.

Rules

A rule is an object in the form:

{
  "grant": privileges, // An array of strings
  "when": condition    // A condition object
}

Rule.grant

Contains a set of strings that name privileges meaningful in your problem domain. For more on semantics, see Privileges below.

Rule.when

Contains a condition.

Rule.id

This field is optional and often omitted – hence it is not shown in the example above. If present, it is a string that provides a convenient identifier to reference the rule. It is not used by SGL processing.

Privileges

You make up privilege names. They should be short tokens without leading, trailing, or internal whitespace, and without punctuation characters that could cause problems for parsers. Unicode is supported (using NFKC form is strongly recommended to guarantee deterministic comparison). However, snake_case ASCII is the best choice if practical, for maximum interoperability. Privileges are compared case-sensitive. Order doesn’t matter, and duplicates are removed.

Principal

Principals are objects that contain whatever properties are evaluated when determining whether a condition has been met. Two properties of a principal are predefined; custom ones can be added.

Principal.id

Contains a string that uniquely identifies the principal. This might be an employee UUID, a customer email address, or a first name. In the context of decentralized identity or self-sovereign identity, which provided foundational SGL use cases, making the ID a DID is a good idea. The id field is optional and, when present, is used to match against a condition with id.

Principal.roles

A set of strings that name roles belonging to this principal. These are matched against a condition with role.

Role names have the same rules about format and comparison as privilege names.

Condition

A condition defines the circumstances that must exist before someone can exercise the privileges listed in a rule.

There are 4 variants of condition. The variants cannot be combined (e.g., mixing “id” with “roles” or “any” or “all”), although they can be implemented with a single structure that assigns null to unused fields.

Condition with id

This variant requires that the principal seeking a privilege possess a specific identifier:

{"id": "Fred"}

Normally, conditions like this test for an id that equals the specified value. However, other operators can be used instead. This allows tests such as >, !=, and like (regex). Conditions that evaluate custom scalar properties work the same way. See Custom Properties for more details.

Condition with roles

This variant requires the specified value to be in the roles set belonging to one or more of the principals seeking a privilege:

{"n": 3, "roles": "friend"}

The n field is optional. If omitted, "n": 1 is assumed.

Conditions that evaluate custom array/set properties work the same way. See Custom Properties for more details.

Condition with any

This variant provides boolean OR features. It requires a match against any of the conditions nested in its array:

{"any": [
    {"roles": "grandparent"},
    {"roles": "sibling"}
]}

Conditions with any can also have an n field. If present, it specifies that n subconditions must be satisfied from among all the alternatives (instead of the default, 1). Note that this is NOT requiring n matching principals from the group. This condition says that out of the list of 3 subconditions, any 2 must be satisfied, NOT that any of the 3 listed roles must match twice:

{"any": [
    {"roles": "employee"},
    {"roles": "investor"},
    {"roles": "customer"}
], "n": 2}

In this situation, n can be a number larger than the number of elements in the any array of condition. For example, if the above rule were changed so n equaled 5, the semantics would be that 5 times a match would have to be found for one of the 3 listed subconditions. (The behavior here is affected by the disjoint parameter to the satisfies() API.)

Condition with all

This provides boolean AND features. It requires a match against all of the conditions nested in its array:

{"any": [
    {"roles": "employee"},
    {"roles": "customer"},
    {"id":  "8675309"}
]}

See the note about disjoint for advanced usage.

API

satisfies()

Python:

def satisfies(group, condition, disjoint=True) -> bool  

Tells whether a group satisfies the condition embodied in a rule. See Reference for an explanation of disjoint.

Here, group is one or more principals–the set about which we want to check privileges. Taking advantage of python’s loose typing, group can be an array of Principal, or a single Principal, or a dict built from Principal-compatible JSON. A Principal identifies an entity with an id or a set of roles that the entity holds, or both. So a valid group arg might be:

[ {"id": "Bob", "roles": ["employee", "friend"]} ]

or maybe:

Principal( id="Sally", roles=["CEO"] )

See also