openfga-cli

module
v0.265.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: MIT

README ΒΆ

ofga

A modern CLI & TUI for OpenFGA.

Manage stores, authorization models, relationship tuples, and run checks from your terminal β€” or explore everything interactively in a full-screen TUI.

Quick start Β· The TUI Β· Commands Β· Configuration Β· Contributing

CI CodeQL Go Report Card Release Go version GHCR Conventional Commits PRs welcome

ofga playground TUI demo


πŸ“‘ Table of contents


✨ What is this?

ofga is a single, dependency-free binary that gives you two ways to work with an OpenFGA server:

  • 🧰 A scriptable CLI β€” create stores, write and inspect authorization models, manage relationship tuples, run check/list-objects/list-users, and run assertion suites. Read commands provide consistent JSON/YAML output, tabular commands support --plain, and failures return meaningful exit codes.
  • πŸ–₯ A full-screen TUI β€” launch it by running ofga with no arguments. Browse stores, visualize a model as a colored relation graph, edit tuples, run queries and expand their resolution trees, and manage assertions β€” all with the keyboard or the mouse.

It talks to any OpenFGA-compatible server and reuses your connection profiles so you can switch between local, staging, and production in one flag.

Naming: the official OpenFGA CLI is fga. This is a separate, independent reimagining focused on ergonomics and an interactive TUI, distributed as ofga. It is not affiliated with OpenFGA.


πŸš€ Quick start

# 1. Start a local OpenFGA server in another terminal
docker run --rm --name openfga -p 8080:8080 openfga/openfga run

# 2. Point ofga at it (guided; uses http://localhost:8080 by default)
ofga init

# 3. Create a store and make it active
ofga stores create demo --use

# 4. Write an authorization model
cat > model.fga <<'FGA'
model
  schema 1.1

type user

type document
  relations
    define viewer: [user]
FGA
ofga model write --file model.fga
# `.fga` DSL is transformed to JSON for you. `--file` also takes a `.json`
# model, or `-` to read from stdin.

# 5. Add a relationship tuple
ofga tuples write user:anne viewer document:roadmap

# 6. Ask an authorization question
ofga query check user:anne viewer document:roadmap
# βœ“ ALLOWED  user:anne viewer document:roadmap

# 7. …or explore everything interactively
ofga

Already have a server? Skip step 1 and pass its URL to ofga init.


πŸ“¦ Installation

Homebrew (macOS / Linux)
brew install sergiught/tap/ofga
Arch Linux (AUR)
yay -S ofga-bin        # or: paru -S ofga-bin
go install
go install github.com/sergiught/openfga-cli/cmd/ofga@latest
# Latest stable release.
curl -fsSL https://raw.githubusercontent.com/sergiught/openfga-cli/main/install.sh | bash

# A specific release.
curl -fsSL https://raw.githubusercontent.com/sergiught/openfga-cli/main/install.sh | bash -s -- v1.0.0

# Install without sudo.
BIN_DIR="$HOME/.local/bin" bash <(curl -fsSL https://raw.githubusercontent.com/sergiught/openfga-cli/main/install.sh)

The script detects Linux or macOS on x86-64 or ARM64, downloads the matching GoReleaser archive, verifies its SHA-256 checksum, and installs ofga. Review the install.sh source before piping it to Bash if preferred. Every release also includes checksums, an SPDX SBOM, and signed provenance.

Docker
docker run --rm -it --network host ghcr.io/sergiught/ofga:latest stores list
From source
git clone https://github.com/sergiught/openfga-cli
cd openfga-cli
go build -o ofga ./cmd/ofga

Verify your install:

ofga version

⬆️ Upgrade and uninstall

Upgrade with the same installation method used to install ofga:

brew upgrade ofga
yay -Syu ofga-bin
go install github.com/sergiught/openfga-cli/cmd/ofga@latest
curl -fsSL https://raw.githubusercontent.com/sergiught/openfga-cli/main/install.sh | bash

Before removing the binary, use ofga profiles remove <name> for saved profiles whose keyring credentials should also be deleted. Then uninstall the package (brew uninstall ofga, your system package manager, or rm "$(command -v ofga)"). Remove the remaining configuration directory only if it is no longer needed:

rm -rf "$(dirname "$(ofga config path)")"

πŸ–₯ The interactive TUI

Run ofga with no arguments to launch the interactive playground. It's a keyboard- and mouse-driven cockpit for the whole OpenFGA surface.

The playground uses the same resolved profile as CLI commands: ofga --profile staging playground opens staging without changing the saved default. Profile, store, and model switches made inside the playground are reflected immediately in its footer and subsequent actions.

Sections (switch with tab, the number keys 1–8, ctrl+k for the command palette, or click a tab): Profiles Β· Stores Β· Model Β· Tuples Β· Changes Β· Tuple Queries Β· Assertions Β· API Logs.

Highlights

  • 🎨 Model graph β€” the authorization model rendered as a colored tree of types, relations, and inherited (tuple-to-userset) paths.
  • πŸ”Ž Query + resolution tree β€” run check/list-objects/list-users/list-relations and expand why a decision was made.
  • ✍️ Inline editing β€” add/delete tuples, edit assertions, and edit the model DSL, with inline validation as you type.
  • πŸ–± Full mouse support β€” wheel-scroll the graph and lists, click tabs and list rows, click the footer keycaps as buttons, and click outside a dialog to dismiss it.
  • 🎭 Themes β€” aurora, catppuccin, charm, dracula, gruvbox, nord, tokyonight, and a mono (NO_COLOR-friendly) theme.

Keys: press ? at any time for the full, context-aware keybinding overlay.

The TUI only launches on an interactive terminal. In a pipe or CI, bare ofga prints help instead of hanging.


πŸ“‹ Command reference

Command What it does
ofga Launch the interactive TUI
ofga playground Explicit subcommand form of bare ofga; launches the interactive TUI
ofga init Guided first-run setup (creates a connection profile)
ofga stores Create, list, inspect and delete stores
ofga model Write (from JSON or .fga DSL), list, inspect, and visualize authorization models (model graph)
ofga tuples Write, delete, read relationship tuples and follow the changelog
ofga query Ask authorization questions: check, batch-check, expand, list-objects, list-users
ofga assertions Read, write, and run a model's assertion test-suite
ofga api Send a raw request to the OpenFGA API using the active profile's auth
ofga profiles Manage connection profiles (add/list/show/current/use/set/unset/remove/cleanup-credentials)
ofga config Inspect configuration (config path)
ofga theme Show or set the color theme
ofga completion Generate a shell completion script
ofga version Print version and build info

Run ofga <command> --help for details and examples on any command.


πŸ›  Configuration

ofga stores configuration in the platform config directory (the XDG config directory on Linux and the user Preferences directory on macOS). Find the exact file with:

ofga config path
Profiles

A profile bundles an API URL, an optional store and model ID, and auth settings. Switch between environments with --profile/-p or the OPENFGA_PROFILE env var.

ofga profiles add prod --api-url https://fga.example.com \
  --auth-method api_token --token-stdin < token.txt
ofga profiles use prod
ofga profiles show                # resolved active config (secrets masked)
ofga --profile staging stores list

The file is intentionally straightforward TOML:

version = 1
active_profile = "local"
theme = "aurora"

[profiles.local]
api_url = "http://localhost:8080"

[profiles.local.auth]
method = "none"

Prefer ofga profiles add, set, unset, and remove over editing the file: they preserve atomic writes and keep managed credentials synchronized with the OS keyring. If another process changes the file while ofga is running, the save is rejected rather than overwriting the newer configuration.

Precedence

Connection values are resolved in increasing order of precedence:

profile β†’ environment variables β†’ command-line flags (including secret-file flags)

Authentication overrides are method-aware: client secrets apply only to client_credentials, private keys apply only to private_key_jwt, and an explicit API-token file selects API-token authentication for that process.

Environment variables
Variable Purpose
OPENFGA_API_URL API URL (alias: FGA_API_URL)
OPENFGA_STORE_ID Active store ID (alias: FGA_STORE_ID)
OPENFGA_MODEL_ID Authorization model ID (aliases: OPENFGA_AUTHORIZATION_MODEL_ID, FGA_MODEL_ID, FGA_AUTHORIZATION_MODEL_ID)
OPENFGA_API_TOKEN API bearer token compatibility fallback; prefer --auth-token-file (alias: FGA_API_TOKEN)
OPENFGA_CLIENT_ID OAuth2 client ID for client_credentials (alias: FGA_CLIENT_ID)
OPENFGA_CLIENT_SECRET OAuth2 secret compatibility fallback; prefer --auth-client-secret-file (alias: FGA_CLIENT_SECRET)
OPENFGA_TOKEN_URL OAuth2 token endpoint for client_credentials (alias: FGA_TOKEN_URL)
OPENFGA_API_AUDIENCE OAuth2 audience for client_credentials (alias: FGA_API_AUDIENCE)
OPENFGA_SCOPES OAuth2 scopes for client_credentials (alias: FGA_SCOPES)
OPENFGA_KEY_FILE Path to the PEM signing key; applies to a private_key_jwt profile (alias: FGA_KEY_FILE)
OPENFGA_PROFILE Profile to use (alias: FGA_PROFILE)
OPENFGA_CONFIG Path to the config file (overridden by the --config flag)
OPENFGA_ICONS Icon mode: nerdfont (default), unicode, or off
OPENFGA_REDUCED_MOTION Suppress TUI animations (alias: OFGA_REDUCED_MOTION)
NO_COLOR Disable colored output
CLICOLOR_FORCE Force colored output even when piped or redirected
FORCE_COLOR Force colored output even when piped or redirected (equivalent to CLICOLOR_FORCE)

FGA_* aliases are accepted for compatibility with the official CLI.


πŸ”‘ Authentication

ofga supports the same auth methods as OpenFGA:

  • None β€” for a local, unauthenticated server.
  • API token β€” a pre-shared bearer token.
  • Client credentials β€” OAuth2 client-credentials grant.
  • Private key JWT β€” OAuth2 with a client-assertion JWT.

Secrets should be provided without exposing them in your shell history or ps:

# API token
ofga profiles add prod --api-url https://fga.example.com \
  --auth-method api_token --token-stdin < token.txt

# OAuth2 client credentials
ofga profiles add ci --api-url https://fga.example.com \
  --auth-method client_credentials --client-id "$CLIENT_ID" \
  --client-secret-stdin --token-url https://issuer.example.com/oauth/token \
  --audience https://fga.example.com < client-secret.txt

# OAuth2 private-key JWT
ofga profiles add workload --api-url https://fga.example.com \
  --auth-method private_key_jwt --client-id "$CLIENT_ID" \
  --token-url https://issuer.example.com/oauth/token \
  --audience https://issuer.example.com/ \
  --api-audience https://fga.example.com --key-file ./signing-key.pem

The config file is written atomically with 0600 permissions. Tokens, client secrets, and private-key contents supplied through profiles set private_key are stored in the OS keyring under a namespace derived from the config path, so two --config files cannot share credentials accidentally. The TOML file contains managed-secret markers rather than plaintext credentials, and profiles show masks secrets. key_file is different: TOML stores its path and the PEM remains in that file on disk.

For one process only, override a profile's managed credential from a file:

ofga --profile prod --auth-token-file /run/secrets/fga-token stores list
ofga --profile ci --auth-client-secret-file /run/secrets/oauth-secret stores list
ofga --profile workload --auth-private-key-file /run/secrets/signing.pem stores list

These flags avoid both argv secret values and environment inheritance. Secret environment variables remain available for compatibility and CI systems that cannot mount secret files. Use ofga profiles unset token (or client_secret/private_key) to remove a saved credential from the keyring. To delete all ofga-managed secrets from the OS keyring at once β€” every profile's credentials plus orphans left by deleted configs β€” run ofga profiles cleanup-credentials --purge (it prompts for confirmation; --force skips it). Authentication settings are checked before a request, so incomplete profiles fail locally with an actionable error. Secret files should be mode 0600; ofga warns when they are accessible by other users.

API and OAuth token endpoints must be configured at their final URLs. Redirects are rejected rather than followed so credentials cannot be forwarded to a different host or downgraded connection.

🩺 Troubleshooting

Symptom Resolution
connection refused at localhost:8080 Start OpenFGA (see Quick start) or select the correct --profile/--api-url.
no store selected Pass --store-id, set OPENFGA_STORE_ID, or run ofga profiles set store_id <id>.
The OS keyring is unavailable in a headless container Mount a secret and use a process-scoped --auth-*-file flag. Saved secrets deliberately fail closed rather than entering TOML.
Credential cleanup was deferred Restore keyring access, then run ofga profiles cleanup-credentials. Pending exact-field cleanup is stored in the same config file and never deletes a credential still used by a profile.
config changed on disk since it was loaded Another process saved first. Re-run the command or reopen the playground to load the newer file.
An API or OAuth URL returns a redirect Configure the final destination URL directly. Redirects are intentionally disabled for credential safety.
The playground does not start It requires an interactive terminal. Use ofga playground locally; in CI use a CLI subcommand with --no-input.
Warning about credentials over HTTP Use HTTPS for both the OpenFGA API and OAuth token URL. HTTP is only treated as safe for loopback development.

⌨️ Shell completion

# bash
source <(ofga completion bash)
# zsh
ofga completion zsh > "${fpath[1]}/_ofga"
# fish
ofga completion fish | source
# PowerShell
ofga completion powershell | Out-String | Invoke-Expression

Completion is dynamic: --profile, --store-id, and --model-id (and the matching positional args) complete real profile names, store IDs, and model IDs from your server. Network-backed completions are bounded by a short timeout so they never hang your shell.


🀝 Scripting & automation

ofga is built to compose:

  • --json emits clean, machine-readable JSON (secrets omitted) for jq.
  • --yaml (or -o yaml / --output yaml) emits the same structured data as YAML, for tools that prefer it (e.g. diffing against a YAML-based config).
  • --plain emits unstyled TSV for both reads and mutations; embedded tabs, newlines, and control characters are normalized to spaces so every item remains one record. Key/value results are key<TAB>value, and query check --plain prints allowed/denied.
  • Meaningful exit codes: 0 success, 1 generic failure, 2 usage error, 3 failed assertions test, 4 network error, 130 interrupted by Ctrl-C/SIGINT.
  • First-class server mutation commands support -n/--dry-run; ofga api is an expert escape hatch.
  • Destructive replacements and deletes prompt on a TTY and require --force when non-interactive, so scripts fail safe.
  • Piped output drops colors and box-drawing automatically.
  • --timeout bounds each HTTP request (30 seconds by default; 0 disables it).
  • --no-input prevents prompts and disables the bare-command TUI for automation running under a pseudo-TTY.
  • A downstream consumer that closes stdout early (for example | head) is treated as normal pipeline completion unless a command-specific failure must take precedence.
  • ofga api --plain preserves the response body bytes rather than pretty-printing JSON, adding only a missing final newline.

Bulk tuple writes/deletes are sent in server-sized batches and are not transactional across batches. If a later batch fails, JSON/YAML and plain output report written/deleted, total, and complete: false before the command exits non-zero. Automation should inspect the exit status and treat the reported count as already committed.

Note: ofga tuples read, ofga tuples changes, ofga stores list, and ofga model list auto-paginate and return all rows by default (--page-size only sets the per-request page size, not a total cap). Against a large store that can be a lot of outputβ€”cap it with --max-results (alias --limit), or pipe through head or --json | jq.

# Which documents can anne view?
ofga query list-objects document viewer user:anne --plain

# Fail a CI job if the assertion suite regresses
ofga assertions test || exit 1

πŸ— Contributing

Contributions are welcome! Please read CONTRIBUTING.md for the build/test/lint workflow and the Conventional Commits convention used for automated releases.

Report bugs and request features through GitHub Issues. Report vulnerabilities privately as described in SECURITY.md.

go build ./...
go test ./...

βš–οΈ License

MIT Β© Sergiu Ghitea. Built for the excellent OpenFGA project (not affiliated).

Directories ΒΆ

Path Synopsis
cmd
ofga command
Command ofga is a modern CLI and TUI for OpenFGA.
Command ofga is a modern CLI and TUI for OpenFGA.
internal
apilog
Package apilog captures OpenFGA HTTP traffic for the playground's API Logs view.
Package apilog captures OpenFGA HTTP traffic for the playground's API Logs view.
cli
Package cli holds the shared dependencies threaded through every command: the logger, the loaded config, and the global flag overrides.
Package cli holds the shared dependencies threaded through every command: the logger, the loaded config, and the global flag overrides.
client
Package client constructs a configured go-openfga client from resolved config.
Package client constructs a configured go-openfga client from resolved config.
clierr
Package clierr centralizes how command errors map to user-facing messages and process exit codes, so main can stay a thin shell and every command surfaces failures consistently.
Package clierr centralizes how command errors map to user-facing messages and process exit codes, so main can stay a thin shell and every command surfaces failures consistently.
command
Package command defines the shared Command abstraction used by every ofga command, mirroring the structure of task-pilot-cli: each command exposes its cobra command, registers its sub-commands, and implements its run logic.
Package command defines the shared Command abstraction used by every ofga command, mirroring the structure of task-pilot-cli: each command exposes its cobra command, registers its sub-commands, and implements its run logic.
command/api
Package api implements `ofga api`: send a raw request to the OpenFGA API using the active profile's connection and authentication.
Package api implements `ofga api`: send a raw request to the OpenFGA API using the active profile's connection and authentication.
command/assertions
Package assertions implements `ofga assertions`: read and write the assertion test-suite attached to an authorization model, and run it.
Package assertions implements `ofga assertions`: read and write the assertion test-suite attached to an authorization model, and run it.
command/base
Package base provides the root `ofga` command: persistent flags, the help banner, and registration of every top-level sub-command.
Package base provides the root `ofga` command: persistent flags, the help banner, and registration of every top-level sub-command.
command/configcmd
Package configcmd implements `ofga config`: inspect where ofga's configuration lives and what it resolves to.
Package configcmd implements `ofga config`: inspect where ofga's configuration lives and what it resolves to.
command/model
Package model implements `ofga model`: write, list, inspect, and visualize authorization models (including a colored relation graph).
Package model implements `ofga model`: write, list, inspect, and visualize authorization models (including a colored relation graph).
command/playground
Package playground implements the interactive `ofga` TUI: a full-screen, Crush-style shell for exploring a store β€” picking models, browsing tuples, running live checks, and visualizing the authorization model as a graph.
Package playground implements the interactive `ofga` TUI: a full-screen, Crush-style shell for exploring a store β€” picking models, browsing tuples, running live checks, and visualizing the authorization model as a graph.
command/profiles
Package profiles implements `ofga profiles`: manage named connection profiles β€” list, switch, inspect, create, edit and remove them.
Package profiles implements `ofga profiles`: manage named connection profiles β€” list, switch, inspect, create, edit and remove them.
command/query
Package query implements `ofga query`: the read-side authorization questions β€” check, batch-check, expand, list-objects and list-users.
Package query implements `ofga query`: the read-side authorization questions β€” check, batch-check, expand, list-objects and list-users.
command/store
Package store implements `ofga stores`: create, list, inspect and delete OpenFGA stores.
Package store implements `ofga stores`: create, list, inspect and delete OpenFGA stores.
command/tuple
Package tuple implements `ofga tuples`: write, delete, read relationship tuples and follow the changelog.
Package tuple implements `ofga tuples`: write, delete, read relationship tuples and follow the changelog.
config
Package config loads and persists ofga configuration: a set of named connection profiles (contexts) plus the name of the active one.
Package config loads and persists ofga configuration: a set of named connection profiles (contexts) plus the name of the active one.
dsl
Package dsl provides syntax highlighting and syntax-error diagnostics for OpenFGA DSL text, built on the openfga/language ANTLR lexer and parser.
Package dsl provides syntax highlighting and syntax-error diagnostics for OpenFGA DSL text, built on the openfga/language ANTLR lexer and parser.
fga
Package fga holds OpenFGA domain helpers shared by the CLI commands and the TUI: parsing tuple shorthand and turning an authorization model into a graph.
Package fga holds OpenFGA domain helpers shared by the CLI commands and the TUI: parsing tuple shorthand and turning an authorization model into a graph.
output
Package output renders command results either as a styled table/summary for humans or as indented JSON for machines (--json).
Package output renders command results either as a styled table/summary for humans or as indented JSON for machines (--json).
prompt
Package prompt provides consistent confirmation gates for destructive commands: interactive y/N (or type-to-confirm) on a terminal, and a required --force flag when running non-interactively so scripts fail safe.
Package prompt provides consistent confirmation gates for destructive commands: interactive y/N (or type-to-confirm) on a terminal, and a required --force flag when running non-interactively so scripts fail safe.
readlimit
Package readlimit provides bounded reads for user-controlled files, stdin, and HTTP bodies.
Package readlimit provides bounded reads for user-controlled files, stdin, and HTTP bodies.
style
Package style centralizes the lipgloss palette and reusable styles.
Package style centralizes the lipgloss palette and reusable styles.
theme
Package theme defines named color palettes for the CLI and TUI.
Package theme defines named color palettes for the CLI and TUI.
ui/field
Package field provides a minimal themed form: labeled text inputs with an accent bar on focus, inline validation, tab-cycled focus, and enter-to-submit.
Package field provides a minimal themed form: labeled text inputs with an accent bar on focus, inline validation, tab-cycled focus, and enter-to-submit.
ui/icons
Package icons resolves the glyph set once per run: Nerd Font when available (default), universal Unicode fallback, or off for decorative glyphs.
Package icons resolves the glyph set once per run: Nerd Font when available (default), universal Unicode fallback, or off for decorative glyphs.
ui/list
Package list wraps bubbles/list with a task-pilot-style delegate: a thick left-border selection accent, title+description rows, and built-in filtering.
Package list wraps bubbles/list with a task-pilot-style delegate: a thick left-border selection accent, title+description rows, and built-in filtering.
ui/logo
Package logo renders the OPENFGA block wordmark, in the spirit of charmbracelet/crush's stylized title.
Package logo renders the OPENFGA block wordmark, in the spirit of charmbracelet/crush's stylized title.
ui/shell
Package shell renders the Crush-style playground frame: a left sidebar (gradient logo + context + nav + status footer), a main content pane, and a bottom status bar, composited flat on a lipgloss canvas with no painted panel backgrounds β€” structure comes from headers and rules.
Package shell renders the Crush-style playground frame: a left sidebar (gradient logo + context + nav + status footer), a main content pane, and a bottom status bar, composited flat on a lipgloss canvas with no painted panel backgrounds β€” structure comes from headers and rules.
ui/toast
Package toast renders transient bottom-right status chips that auto-expire.
Package toast renders transient bottom-right status chips that auto-expire.
version
Package version holds build information, injected at release time via -ldflags.
Package version holds build information, injected at release time via -ldflags.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL