Skip to Content
ProvidersAuthorization

Authorization

Authorization providers store relationship data and answer access checks for Gestalt. Authorization is separate from Authentication, which identifies the caller, and External Credentials, which provide upstream credentials for configured connections.

Gestalt’s model follows the core ideas from Google Zanzibar : subjects, resources, relations, actions, and relationship tuples.

Core Concepts

Subjects

A subject is the caller being checked. Gestalt resolves each request to a canonical subject, such as user:<id>, service_account:<id>, or a system subject, then evaluates access for that subject.

For non-human automation subjects, see Service Accounts.

Resources

A resource is what the subject wants to access, e.g.:

  • external_identity:google-123
  • managed_subject:deploy-bot

Relations

A relation is a named link from a subject to a resource. For example, triage on an app grants triage membership; admin on a policy grants admin membership.

Relationship Tuples

A tuple stores one relation:

<subject> <relation> <resource>

Examples:

user:alice viewer app_static:github user:bob editor app_static:github

The configured authorization provider stores these tuples and uses them as the source of truth for dynamic access.

Actions

Relations are memberships; actions are permissions. The authorization model defines which actions each relation grants. To answer “can user:alice read this operation?”, the provider checks whether Alice has a relation on the resource that grants read.

Static And Dynamic Grants

Static grants live in authorization.policies. They load at startup, do not change at runtime, and take precedence over provider-backed grants.

Dynamic grants live in the selected authorization provider. Admin APIs can add or remove them without restarting gestaltd.

If static and dynamic grants both match the same subject and resource, static wins. For example, if config grants Alice admin on the admin policy, Gestalt does not ask the provider for Alice’s admin role.

Grant Dynamic App Access

Use the gestalt authorization CLI to grant app access after the server is running. Built-in Gestalt admins can manage every app. App admins can manage members for apps they administer.

gestalt authorization apps list gestalt authorization apps members list github gestalt authorization apps members set github \ --email operator@example.com \ --role viewer gestalt authorization apps members set github \ --subject-id service_account:release-bot \ --role editor

Create service account subjects first, then grant those subjects app roles:

gestalt authorization subjects create release-bot \ --display-name "Release Bot" gestalt authorization subjects grants set service_account:release-bot github \ --role viewer

Deployments that split public and management listeners may need --url set to the management base URL for these admin commands.

Where Gestalt Uses Authorization

Gestalt checks authorization before serving protected surfaces:

  • App and operation invocation
  • Admin APIs and UI routes
  • External identity assumption
  • Managed subjects and service accounts
  • Workflow and agent execution grants

Authentication, operation scope, authorization, and credential selection are separate checks. Passing one does not imply the others.

Provider Contract

Authorization providers implement three groups of RPCs.

GroupMethods
DecisionsEvaluate, EvaluateMany, SearchResources, SearchSubjects, SearchActions, GetMetadata
RelationshipsReadRelationships, WriteRelationships
ModelsGetActiveModel, ListModels, WriteModel

EvaluateMany is important for latency. Gestalt batches role checks instead of calling Evaluate once per possible role.

Optional methods advertise capabilities through GetMetadata. Effective search is paired: providers must support and advertise both methods or neither.

CapabilityMethods
effective_search_resources, effective_search_subjectsEffectiveSearchResources, EffectiveSearchSubjects
expandExpand

If an optional method is not implemented, the SDK returns UNIMPLEMENTED.

Configure

server: providers: indexeddb: main authorization: indexeddb providers: indexeddb: main: source: package: github.com/valon-technologies/gestalt-providers/indexeddb/relationaldb version: 0.0.1-alpha.1 config: dsn: ${DATABASE_URL} authorization: indexeddb: source: package: github.com/valon-technologies/gestalt-providers/authorization/indexeddb version: 0.0.1-alpha.1 config: indexeddb: main

The first-party IndexedDB authorization provider stores models and relationship tuples in a configured IndexedDB provider.

Use The Host Client

Provider code can query the selected authorization provider through the SDK host client.

import ( "context" gestalt "github.com/valon-technologies/gestalt/sdk/go" ) func canJoinTeam(ctx context.Context, req gestalt.Request, userID string) (bool, error) { authz, err := req.Authorization() if err != nil { return false, err } defer authz.Close() decision, err := authz.Evaluate(ctx, gestalt.NewAccessEvaluationRequest( gestalt.NewAuthorizationSubject(gestalt.AuthorizationSubjectTypeSubject, userID), gestalt.NewAuthorizationAction("join"), gestalt.NewAuthorizationResource("team", "support"), )) return decision.Allowed, err }

Build A Provider

An authorization provider manifest uses kind: authorization:

kind: authorization source: github.com/your-org/authorization/example version: 0.0.1 displayName: Example Authorization description: Custom authorization provider.

Authoring support is available in Go, Python, Rust, and TypeScript.

import ( "context" gestalt "github.com/valon-technologies/gestalt/sdk/go" ) type Provider struct{} func New() *Provider { return &Provider{} } func (p *Provider) Evaluate(context.Context, *gestalt.AccessEvaluationRequest) (*gestalt.AccessDecision, error) { return &gestalt.AccessDecision{Allowed: true, ModelId: "model-1"}, nil } func (p *Provider) EvaluateMany(ctx context.Context, req *gestalt.AccessEvaluationsRequest) (*gestalt.AccessEvaluationsResponse, error) { out := &gestalt.AccessEvaluationsResponse{ Decisions: make([]*gestalt.AccessDecision, 0, len(req.Requests)), } for range req.Requests { out.Decisions = append(out.Decisions, &gestalt.AccessDecision{Allowed: true, ModelId: "model-1"}) } return out, nil }

Production providers should implement every required RPC. The snippets above focus on the SDK entrypoints and batch-evaluation shape.

Operational Notes

server.providers.authorization selects the active provider. If multiple entries exist under providers.authorization, set the server provider name or mark one entry default: true.

Static policy members still win over dynamic grants. Gestalt also writes managed models and relationships into the provider for built-in admin, plugin, external-identity, managed-subject, workflow, and agent authorization.

When OTLP tracing is enabled, keep the incoming request context attached to downstream calls so provider work stays in the same trace.

Next

For exact config fields, see Config File. For package publishing, see Releasing provider packages. For credentials, see External Credentials.