# nauthera-cli Reference

> Every command and flag of nauthera-cli, the development tool that manages organizations, OIDC clients and identity providers through the gRPC AdminService.

`nauthera-cli` drives the gRPC `AdminService` from a terminal. For clients and identity
providers, it uses the same idempotent upserts the [operator](https://www.nauthera.io/docs/v1/operator)
drives. It is a **local
development tool**; in a cluster the operator manages clients. It connects in one of two
ways:

- **Without TLS**, the default. Only a server with `server.grpc.allow_insecure: true`
  answers, and the server accepts that setting only on a loopback `server.grpc.address`,
  as in `config.dev.yaml` and the chart's kind profiles.
- **With mutual TLS**, when you pass `--tls-ca-file`, `--tls-cert-file` and
  `--tls-key-file` together. The Compose stack runs the control plane this way: `just
  certs` writes a CA, the server's key pair and a `nauthera-cli` client certificate to
  `.certs/grpc/`, and the server admits only that client certificate.

Run it from a checkout of nauthera-server:

```bash
go run ./cmd/nauthera-cli <command> [flags]
```

Against the Compose stack:

```bash
go run ./cmd/nauthera-cli get org \
  --tls-ca-file .certs/grpc/ca.pem \
  --tls-cert-file .certs/grpc/client.pem \
  --tls-key-file .certs/grpc/client-key.pem
```

To reach a server in a kind cluster, where the AdminService listens on `127.0.0.1` inside
the pod, port-forward the deployment first:

```bash
kubectl -n nauthera port-forward deploy/nauthera-nauthera-server 9091:9091
```

## Global flags

| Flag | Default | Meaning |
|---|---|---|
| `--addr` | `localhost:9091` | Address of the gRPC AdminService |
| `--namespace` | `default` | Namespace of the client and identity provider resources the command reads or writes. They are addressed by namespace and resource name, not by client ID or slug. |
| `--timeout` | `15s` | Limit for dialing plus the call |
| `-o`, `--output` | `table` | `table`, `json` or `yaml` |
| `--tls-ca-file` | none | PEM CA bundle the server's certificate must chain to |
| `--tls-cert-file` | none | PEM client certificate to present |
| `--tls-key-file` | none | PEM private key of the client certificate |
| `--config` | none | A YAML file with any of the keys above. A path that does not exist is an error. |

Each setting can also come from an environment variable, `NAUTHERA_CLI_` followed by the
upper-cased flag name with dashes as underscores, for example `NAUTHERA_CLI_ADDR` or
`NAUTHERA_CLI_TLS_CA_FILE`. The three TLS settings go together: setting only some of them
is an error. A flag on the command line wins,
then the environment, then the config file.

## Organizations

### `create org <slug>`

Creates an organization. It refuses a slug that already exists. It returns no secret for
the organization's `{slug}-admin-m2m` client, so nobody holds that secret and the client
cannot be used. An organization created through the [admin API](https://www.nauthera.io/docs/v1/user-management)
gets that secret once, as `admin_m2m_secret`.

| Flag | Meaning |
|---|---|
| `--display-name` | Human-readable name. Defaults to the slug. |
| `--fapi-mode` | Apply the FAPI 2.0 subset: PAR required, PKCE S256 only, ES256 only |
| `--fips-mode` | Put the organization under the FIPS policy. The server must run the Go FIPS 140-3 module, on and pinned to a frozen version. On any other process the create fails with `FAILED_PRECONDITION`, and an existing FIPS organization is not served. |
| `--require-email-verification` | Keep an account with an unverified address out of a session until it follows an emailed link. The organization needs an email relay to send one. |
| `--second-factor-file` | A YAML or JSON file holding the organization's second-factor policy, in the control plane's field names: `methods`, `required`, `passwordless`, `remember_for_seconds`, `spare_zones`, `always_challenge`, `rules`. |
| `--zone` | A network zone as `name=cidr[,cidr...]`. Repeat the flag for more zones. |

FIPS mode can be set only when the organization is created. FAPI mode, email
verification, the second-factor policy and the zones can be changed later with
`update org`. An organization's policy can only tighten the deployment's; see
[Configuration](https://www.nauthera.io/docs/v1/configuration#the-second-factor-policy). See also
[Organizations](https://www.nauthera.io/docs/v1/organizations#fapi-mode-and-fips-mode).

```yaml
# policy.yaml
methods: [passkey, totp]
required: true
rules:
  - name: passkey-off-site
    outside_zones: [office]
    methods: [passkey]
```

`spare_zones` names zones of the deployment's `security.network_zones` only, because no
level spares a sign-in the deployment would not.

```bash
go run ./cmd/nauthera-cli create org acme --display-name "Acme" \
  --zone office=203.0.113.0/24 --second-factor-file policy.yaml
```

### `update org <slug>`

Changes an existing organization. Only the flags given are changed; pass
`--fapi-mode=false` or `--require-email-verification=false` to lift one. It refuses a
call that changes nothing, and answers an unknown slug with an error.

| Flag | Meaning |
|---|---|
| `--display-name` | Human-readable name |
| `--fapi-mode` | Hold the organization to FAPI 2.0, or with `=false` release it |
| `--require-email-verification` | Require a verified address before sign-in completes, or with `=false` stop requiring it |
| `--second-factor-file` | Replace the whole second-factor policy |
| `--zone` | Replace every network zone; repeatable |
| `--clear-zones` | Remove every network zone. Cannot be combined with `--zone`. |

The slug and FIPS mode are fixed at creation. The main organization's settings come from
`orgs.main` in the server's configuration, not from here; the control plane never
changes the main organization.

### `get org [slug]`

Reads one organization, or lists all of them when the slug is omitted.

### `delete org <slug>`

Deletes an organization's record. Its users, clients and sessions stay in the database,
and its reserved admin clients keep the slug taken, so `create org` with the same slug
then fails with an internal error (#283). Deleting an organization that does not exist
succeeds. The main organization cannot be deleted. See [Deleting an org](https://www.nauthera.io/docs/v1/organizations#deleting-an-org).

## Clients

### `create client <client-id>`

Creates the client, or replaces its configuration if it exists. A secret is generated
and printed **once**, by the run that mints it: the run that creates the client, or a
later run that switches a client without a secret, such as a public one, to
`client_secret_basic`. Store it then. Running the command again never rotates the
secret: to get a new one, delete the client and create it again.

| Flag | Default | Meaning |
|---|---|---|
| `--name` | the client ID | Resource name the client is stored under |
| `--display-name` | | Name shown on the consent screen |
| `--org` | | Home the client in this organization. Cannot be combined with `--issuer`. |
| `--issuer` | the main org | Home the client at this issuer URL |
| `--redirect-uri` | | Exact redirect URI. Repeat the flag or separate with commas. Required with the `authorization_code` grant. |
| `--post-logout-redirect-uri` | | Allowed post-logout redirect URI. Repeatable. |
| `--frontchannel-logout-uri` | | Front-channel logout URI |
| `--frontchannel-logout-session-required` | `false` | The client needs `iss` and `sid` on the front-channel logout request. It is skipped when no `sid` is available. |
| `--scopes` | `openid,profile,email,offline_access` | Scopes the client may request |
| `--grant-types` | `authorization_code,refresh_token` | Grants the client may use |
| `--response-types` | `code` | |
| `--pkce` | `required_s256` | `required_s256`, `optional` or `disabled` |
| `--allow-refresh` | `true` | Allow refresh tokens |
| `--public` | `false` | Public client: no secret, PKCE required, authenticates with `none` |
| `--jwks-uri` | | Make it a `private_key_jwt` client verified against the keys at this https URL. No secret is generated. Cannot be combined with `--public`. |
| `--token-auth-signing-alg` | either | `ES256` or `RS256` for the client's assertions. Needs `--jwks-uri`. |
| `--identity-provider` | | Offer an identity provider of the client's organization on its sign-in page: `<slug>` for sign-in and sign-up, `<slug>:sign-in` or `<slug>:sign-up` for one of them. Repeat the flag or separate with commas. The organization's own sign-up setting still applies. |
| `--second-factor-file` | | The client's second-factor policy, in the same format as for `create org`. It can only tighten its organization's. |

Without `--public` or `--jwks-uri`, the client authenticates with
`client_secret_basic`.

```bash
go run ./cmd/nauthera-cli create client my-app \
  --org acme \
  --redirect-uri https://app.example.com/callback \
  --post-logout-redirect-uri https://app.example.com/
```

### `get client [name]`

Reads one client by resource name, or lists the clients in `--namespace` when the name
is omitted. Add `-A` (`--all-namespaces`) to list every namespace.

### `delete client <name>`

Deletes a client by resource name. Deleting one that does not exist succeeds.

## Identity providers

### `create identity-provider <slug>`

Creates or replaces an external OpenID Connect provider, or GitHub
(`--provider-issuer https://github.com/login/oauth`), that an organization's users can
sign in with (see [Social sign-in](https://www.nauthera.io/docs/v1/sign-in-flows/social-sign-in)). Like
`create client`, it is an idempotent upsert, stored under `--namespace` and the resource
name. It prints the redirect URI to register at the provider. A client offers the
provider with `create client --identity-provider <slug>`.

| Flag | Default | Meaning |
|---|---|---|
| `--name` | the slug | Resource name the provider is stored under |
| `--display-name` | the slug | The name on the provider's sign-in button |
| `--org` | | The organization the provider belongs to. Cannot be combined with `--issuer`. |
| `--issuer` | the main org | The issuer URL of the organization the provider belongs to |
| `--provider-issuer` | | Required. The provider's own issuer, whose discovery document is read (https, public host), or `https://github.com/login/oauth` for [GitHub](https://www.nauthera.io/docs/v1/identity-provider-resource#github) |
| `--client-id` | | Required. The client ID this server is registered under at the provider |
| `--client-secret-file` | | File holding the client secret the provider issued; `/dev/stdin` reads it from a pipe. Required on create; on an update, leaving it out keeps the stored secret. An empty file is refused. |
| `--scopes` | `openid email profile` (GitHub: `read:user user:email`) | Scopes requested from the provider |
| `--trust-email` | `false` | Trust the provider's `email_verified` claim, which lets an upstream account link to an existing account with that address |
| `--allowed-email-domain` | | Admit only verified addresses in these domains. Repeatable. Needs `--trust-email`. |
| `--trust-mfa` | `false` | Let the provider's own multi-factor sign-in stand in for this server's second factor |
| `--mfa-acr-value` | | The `acr` values the provider issues for a multi-factor sign-in. Repeatable. Needs `--trust-mfa`. |
| `--spare-second-factor` | `false` | Let a sign-in through the provider that it did not vouch for skip this server's second factor, as a single-factor sign-in |

```bash
printf '%s' "$GOOGLE_CLIENT_SECRET" | go run ./cmd/nauthera-cli create identity-provider google \
  --org acme --display-name Google \
  --provider-issuer https://accounts.google.com \
  --client-id 1234.apps.googleusercontent.com \
  --client-secret-file /dev/stdin --trust-email
```

There is no `get` or `delete` command for identity providers yet; use the admin API, the
dashboard or an [IdentityProvider](https://www.nauthera.io/docs/v1/identity-provider-resource) resource.

## What it cannot do

There are no commands for branding, users, roles or client labels, and no `get` or
`delete` for identity providers. Write branding with the gRPC `UpsertBranding` call
directly or a [Branding](https://www.nauthera.io/docs/v1/branding-resource) resource. Users and their roles
are managed through the [admin API](https://www.nauthera.io/docs/v1/user-management) and the
[admin dashboard](https://www.nauthera.io/docs/v1/admin-dashboard).
