Pure.Authorization.OpenFGA.Model 0.1.0-preview.0.1.0

This is a prerelease version of Pure.Authorization.OpenFGA.Model.
dotnet add package Pure.Authorization.OpenFGA.Model --version 0.1.0-preview.0.1.0
                    
NuGet\Install-Package Pure.Authorization.OpenFGA.Model -Version 0.1.0-preview.0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Pure.Authorization.OpenFGA.Model" Version="0.1.0-preview.0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pure.Authorization.OpenFGA.Model" Version="0.1.0-preview.0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Pure.Authorization.OpenFGA.Model" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Pure.Authorization.OpenFGA.Model --version 0.1.0-preview.0.1.0
                    
#r "nuget: Pure.Authorization.OpenFGA.Model, 0.1.0-preview.0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Pure.Authorization.OpenFGA.Model@0.1.0-preview.0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Pure.Authorization.OpenFGA.Model&version=0.1.0-preview.0.1.0&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Pure.Authorization.OpenFGA.Model&version=0.1.0-preview.0.1.0&prerelease
                    
Install as a Cake Tool

Pure.Authorization.OpenFGA.Model

Concrete implementations of the OpenFGA authorization model for the Pure ecosystem: immutable, AOT-compatible records implementing the Pure.Authorization.OpenFGA.Model.Abstractions contracts, plus OpenFGA text forms of subjects, objects and tuples.

.NET build & test Build and Deploy NuGet License: MIT

Overview

Pure.Authorization.OpenFGA.Model provides sealed record implementations of every interface defined in Pure.Authorization.OpenFGA.Model.Abstractions. Each type is immutable by construction, taking all values through its constructor, and uses IString from Pure.Primitives.Abstractions for all string-valued properties.

On top of the records, the package ships text forms that render model values into the canonical strings OpenFGA uses.

Records do no validation. Checking a tuple or a relation against an authorization model belongs to Pure.Authorization.OpenFGA.Model.Conditions, and parsing text back into records belongs to Pure.Authorization.OpenFGA.Model.Abstractions.Serialization.System.

Types

Records

One sealed record per interface. Each namespace mirrors the matching folder of the abstractions.

Namespace Type Implements Description
Pure.Authorization.OpenFGA.Model.Model AuthorizationModel IAuthorizationModel Schema version, type definitions and conditions
TypeDefinition ITypeDefinition An object type and its relations (type document)
RelationDefinition IRelationDefinition A named relation and its rewrite (define viewer: ...)
Pure.Authorization.OpenFGA.Model.Rewrite Direct IDirect Directly assignable subject forms ([user, group#member])
ComputedRelation IComputedRelation Another relation on the same object (editor)
RelationFrom IRelationFrom A relation on related objects (viewer from parent)
Union IUnion Any of the children (a or b)
Intersection IIntersection All of the children (a and b)
Difference IDifference Base minus subtracted part (a but not b)
Pure.Authorization.OpenFGA.Model.SubjectForm TypeForm ITypeForm Any object of a type (user)
SubjectSetForm ISubjectSetForm Holders of a relation on a type (group#member)
WildcardForm IWildcardForm Public-access wildcard (user:*)
ConditionalForm IConditionalForm A form written with a condition (user with non_expired)
Pure.Authorization.OpenFGA.Model.Condition Condition ICondition A named CEL expression over typed parameters
ConditionParameter IConditionParameter A typed parameter (grant_time: timestamp)
ConditionParameterType IConditionParameterType A parameter type with generic arguments (list<string>)
Pure.Authorization.OpenFGA.Model.Object Object IObject An object of a type (document:1); also a subject
Pure.Authorization.OpenFGA.Model.Subject SubjectSet ISubjectSet Holders of a relation on an object (group:eng#member)
TypedWildcard ITypedWildcard Every object of a type (user:*)
Pure.Authorization.OpenFGA.Model.Tuple Tuple ITuple Subject, relation and object of a relationship tuple
ConditionalTuple IConditionalTuple Decorates an ITuple with a condition; subject, relation and object come from the wrapped tuple
RelationshipCondition IRelationshipCondition A condition name and its JSON context

Constructors whose last parameter is a collection take it as params IEnumerable<T>, so new Union(a, b, c), new Direct(new TypeForm(user)) and new TypeDefinition(document, viewer, editor) read naturally. A collection can still be passed as is.

Object, Condition and Tuple share their name with the last segment of their namespace, as Table and Index do in Pure.RelationalSchema. Outside their own namespace, refer to them through a using alias, e.g. using Object = Pure.Authorization.OpenFGA.Model.Object.Object;.

Text forms

Each text form implements IString and composes the string lazily from Pure.Primitives building blocks, so it reflects the record it wraps at the time it is read.

Type Namespace Renders
ObjectString Pure.Authorization.OpenFGA.Model.Object An IObject
SubjectString Pure.Authorization.OpenFGA.Model.Subject An ISubject
SubjectFormString Pure.Authorization.OpenFGA.Model.SubjectForm An ISubjectForm, in DSL syntax
TupleString Pure.Authorization.OpenFGA.Model.Tuple An ITuple
Input Shape Example
IObject (object or direct subject) type:id document:roadmap, user:anne
ISubjectSet type:id#relation group:eng#member
ITypedWildcard type:* user:*
ITypeForm type user
ISubjectSetForm type#relation group#member
IWildcardForm type:* user:*
IConditionalForm <form> with <condition> user with non_expired, group#member with in_region
ITuple object#relation@subject document:1#viewer@group:eng#member

Notes:

  • SubjectString and SubjectFormString dispatch over the closed variant sets. An implementation of ISubject or ISubjectForm that is none of the known variants makes reading the text throw ArgumentException.
  • The condition of an IConditionalTuple is not part of TupleString: a conditional tuple is written exactly like the tuple it wraps.
  • Parts are written as they are, with no validation or escaping.
  • The text forms only write strings. Parsing is not part of this package.

Design Principles

  • Immutable: all properties are get-only; values are set once in the constructor and never changed.
  • Composable: records depend only on abstractions, so any implementation can be substituted.
  • No implicit text or hashing: GetHashCode() and ToString() throw NotSupportedException, as in the rest of the Pure ecosystem. Use the text forms to get OpenFGA strings.
  • AOT-compatible: sealed records with no reflection-based code paths; the package is fully compatible with Native AOT.

Dependencies

Target Frameworks

  • .NET 7
  • .NET 8
  • .NET 9
  • .NET 10

Installation

dotnet add package Pure.Authorization.OpenFGA.Model

The package has not been published yet; this command will work after the first release.

Usage

using System.Text.Json.Nodes;
using Pure.Authorization.OpenFGA.Model.Abstractions.Model;
using Pure.Authorization.OpenFGA.Model.Abstractions.Tuple;
using Pure.Authorization.OpenFGA.Model.Model;
using Pure.Authorization.OpenFGA.Model.Rewrite;
using Pure.Authorization.OpenFGA.Model.Subject;
using Pure.Authorization.OpenFGA.Model.SubjectForm;
using Pure.Authorization.OpenFGA.Model.Tuple;
using Pure.Primitives.Abstractions.String;
using Condition = Pure.Authorization.OpenFGA.Model.Condition.Condition;
using ConditionParameter = Pure.Authorization.OpenFGA.Model.Condition.ConditionParameter;
using ConditionParameterType = Pure.Authorization.OpenFGA.Model.Condition.ConditionParameterType;
using Object = Pure.Authorization.OpenFGA.Model.Object.Object;
using String = Pure.Primitives.String.String;
using Tuple = Pure.Authorization.OpenFGA.Model.Tuple.Tuple;

// model
//   schema 1.1
//   type user
//   type group
//     relations
//       define member: [user]
//   type document
//     relations
//       define editor: [user]
//       define viewer: [user, user:*, group#member, user with non_expired] or editor
//   condition non_expired(grant_time: timestamp, duration: duration) {
//     request.current_time < grant_time + duration
//   }
IAuthorizationModel model = new AuthorizationModel(
    new String("1.1"),
    [
        new TypeDefinition(new String("user")),
        new TypeDefinition(
            new String("group"),
            new RelationDefinition(
                new String("member"),
                new Direct(new TypeForm(new String("user")))
            )
        ),
        new TypeDefinition(
            new String("document"),
            new RelationDefinition(
                new String("editor"),
                new Direct(new TypeForm(new String("user")))
            ),
            new RelationDefinition(
                new String("viewer"),
                new Union(
                    new Direct(
                        new TypeForm(new String("user")),
                        new WildcardForm(new String("user")),
                        new SubjectSetForm(new String("group"), new String("member")),
                        new ConditionalForm(
                            new TypeForm(new String("user")),
                            new String("non_expired")
                        )
                    ),
                    new ComputedRelation(new String("editor"))
                )
            )
        ),
    ],
    [
        new Condition(
            new String("non_expired"),
            new String("request.current_time < grant_time + duration"),
            new ConditionParameter(
                new String("grant_time"),
                new ConditionParameterType(new String("timestamp"))
            ),
            new ConditionParameter(
                new String("duration"),
                new ConditionParameterType(new String("duration"))
            )
        ),
    ]
);

ITuple tuple = new Tuple(
    new SubjectSet(new Object(new String("group"), new String("eng")), new String("member")),
    new String("viewer"),
    new Object(new String("document"), new String("roadmap"))
);

IString text = new TupleString(tuple);
// text.TextValue == "document:roadmap#viewer@group:eng#member"

ITuple temporary = new ConditionalTuple(
    new Tuple(
        new Object(new String("user"), new String("anne")),
        new String("viewer"),
        new Object(new String("document"), new String("roadmap"))
    ),
    new RelationshipCondition(
        new String("non_expired"),
        new JsonObject
        {
            ["grant_time"] = "2026-01-01T00:00:00Z",
            ["duration"] = "24h",
        }
    )
);
// new TupleString(temporary).TextValue == "document:roadmap#viewer@user:anne"

IString form = new SubjectFormString(
    new ConditionalForm(new TypeForm(new String("user")), new String("non_expired"))
);
// form.TextValue == "user with non_expired"
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-preview.0.1.0 108 10/23/2026