Skip to content

Cuiman Configuration

The cuiman configuration settings may be passed in a couple of ways to the Python API and CLI clients. The different ways also have different precedence.

Passing Configuration

In the following list of configuration methods, a setting of a subsequent entry overrides that of a previous one.

  1. Default settings hard-coded into the cuiman.api.ClientConfig class.
  2. Settings loaded from a given or the default configuration file passed as config_path.
  3. Settings loaded from the selected configuration class's .env file.
  4. Settings loaded from environment variables using the selected class's prefix.
  5. Explicit fields from a configuration object passed as config.
  6. Settings from keyword arguments passed directly to the client as config_kwargs.

ClientConfig.create() implements this precedence. Explicit fields retain their priority even when their values equal class defaults. Partial authentication settings are merged before validating the effective configuration. The file is also validated independently so invalid profiles always produce the documented configure error, even if another source could override their invalid fields.

After resolution, matching operating-system keyring entries can fill missing credentials. They never replace credentials supplied by any configuration source.

Applications using cuiman can select their own ClientConfig subclass for each sync client, async client, and CLI. That class is an isolated settings namespace: it owns the schema, default profile path, dotenv/environment prefix, and field defaults without mutating ClientConfig globally. See Cuiman Customization.

Reusing resolved configuration

The configuration returned by ClientConfig.create() or client.config is a resolved snapshot. Passing it to another client preserves its values, application type, and profile identity without rereading the file, .env, or environment. Keyword overrides update that snapshot; an empty override such as auth={} does not cause unrelated settings to change. Mutable values are copied between clients.

client = Client(config_type=MyConfig)
other = AsyncClient(config=client.config, auth={"access_token": replacement_token})

An explicitly different config_path starts fresh source loading for that profile; the supplied snapshot still has precedence over those sources. To reload all sources without carrying snapshot values, construct a new client with config_type and the desired path, omitting config.

Keyring lookup is a separate decision: a snapshot initially created with resolve_secrets=False can later fill missing credentials with ClientConfig.create(config=snapshot, resolve_secrets=True). It retains whether its originating profile existed, so this does not require rereading the file. Reusing a profile preserves an existing credential persistence hook when the API URL and authentication configuration are unchanged.

Direct MyConfig(...) construction uses Pydantic Settings' own environment and dotenv handling. MyConfig.new_instance(...) validates explicit values without external sources. Both produce input configurations; use create() or a client constructor for Cuiman's full resolution and snapshot behavior.

Replacing or merging authentication

For both Client(auth=auth) and AsyncClient(auth=auth), the supplied value determines whether existing authentication settings are replaced or merged:

Supplied auth value Behavior
Dictionary containing auth_type Replaces previous auth settings, even when the type is unchanged.
Auth model, such as OAuth2AuthConfig(...) Replaces previous auth settings; the model already selects its auth type.
Dictionary without auth_type Merges into the selected auth configuration, preserving unspecified fields.

For example:

from cuiman import Client
from cuiman.api.auth import TokenAuthConfig

# Replace previous auth settings; an old custom header is not inherited.
client = Client(auth={"auth_type": "token", "access_token": token})

# An auth model also replaces previous settings.
client = Client(auth=TokenAuthConfig(access_token=token))

# Merge into existing OAuth settings, retaining the provider configuration.
client = Client(auth={"oauth_token": saved_token})

Partial dictionaries merge recursively, including fields within oauth_token; None values in partial overrides are ignored. To discard previous auth fields, supply auth_type together with the complete desired provider settings and credentials. An explicit auth selection also replaces prior settings from files, environment variables, and config; keyword settings take precedence over config. These overrides affect the new client and do not rewrite its file.

Replacement does not disable keyring lookup. If a public configuration file exists and the selected authentication still lacks usable credentials, the matching profile/API URL/auth-type keyring entry can fill missing secrets. Explicitly supplied credentials take precedence. This applies after both replacement and merging.

URL paths and trailing slashes

Cuiman distinguishes a processing-service base URL from an exact authentication endpoint URL or OIDC issuer identifier:

Setting Path handling
api_url Python and app requests append paths beneath this base. Both /process and /process/ use /process/ for the landing page and /process/processes for the process list.
auth.login_url, auth.token_url Use the provider's exact endpoint path. /auth/login and /auth/login/ remain distinct; Cuiman does not add or remove their trailing slash.
auth.issuer_url Preserve the issuer's trailing slash, including an empty path, because discovery requires an exact issuer match.

Use the endpoint spelling required by your provider. There is no general rule that /endpoint and /endpoint/ identify the same resource; Cuiman does not retry authentication at an alternate spelling. HTTP URL validation can normalize the host and add / to a bare host in api_url, login_url, and token_url; this does not make non-empty paths interchangeable. The OIDC issuer explicitly preserves an empty path.

Configuration Files

from cuiman import Client

client = Client(config_path="./my-config.json")

Configuration files have either YAML or JSON format.

JSON:

{
    "api_url": "https://anolis.api.org/process-api/v1",
    "auth": {
        "auth_type": "token"
    }
}

YAML:

api_url: "https://anolis.api.org/process-api/v1"
auth:
  auth_type: token

Cuiman writes only public connection and authentication metadata to configuration files; credentials are omitted. Existing files are loaded using the current configuration model, including a customized client's schema. A file is considered deprecated or illegal if parsing or validation fails, rather than by checking for particular legacy field names. The error is:

Deprecated or illegal configuration file, please run the 'configure' command.

Run cuiman configure (or your customized client's configure command) to recreate an invalid file from defaults, then log in. No old-format translation is performed. Files that validate are accepted, including supported credential fields already present in a file; reading never rewrites them. Subsequent writes omit credentials. Missing or empty files remain unconfigured; filesystem access errors are reported separately.

Configuring from a Jupyter notebook

Notebook shell commands such as !cuiman configure cannot reliably forward answers to interactive CLI prompts. On Windows, the subprocess's input is a pipe that stays open without receiving notebook input. When standard input is not a terminal, Cuiman exits with an error if an option needs prompting, instead of waiting indefinitely. Run cuiman configure in a shell or JupyterLab terminal for the usual interactive workflow.

To use interactive prompts inside a notebook, call the existing Python helper in the kernel:

from cuiman.cli.config import configure_client_with_prompt

config_path = configure_client_with_prompt()

This collects public settings and uses the kernel's current ClientConfig customization. Credentials are still obtained separately through client login.

Alternatively, provide every prompted setting explicitly to the shell command:

!cuiman configure --api-url https://processing.example.org/process/ --auth-type none

For token or proprietary-login authentication, also provide --access-token-header (an empty value selects Bearer signing). Other auth types have their own provider options; consult cuiman configure --help.

Credential Storage

The cuiman CLI stores passwords, access tokens, refresh tokens, client secrets, and API keys in the operating-system keyring. The keyring entry is scoped to the canonical configuration-file path and the API URL, so profiles for different services or files do not share credentials.

Large token bundles are split across OS-keyring entries to respect Windows Credential Manager's per-entry size limit. Cuiman reassembles them when loading credentials and removes their parts on logout. Tokens remain in the OS keyring; there is no plaintext-file fallback.

Environment variables and direct Python configuration remain available for automated deployments. They take precedence over keyring values and should be provided through the deployment platform's secret-injection mechanism.

Environment Variables

Cuiman reads configuration from environment variables prefixed with EOZILLA_. Top-level configuration fields use their uppercase field name; nested fields use two underscores (__) to separate levels. For example, api_url is configured with EOZILLA_API_URL, while the nested auth.auth_type field is configured with EOZILLA_AUTH__AUTH_TYPE.

The following configures a service using a static bearer token:

export EOZILLA_API_URL="https://anolis.api.org/process-api/v1"
export EOZILLA_AUTH__AUTH_TYPE="token"
export EOZILLA_AUTH__ACCESS_TOKEN="ab989e20-d58609a9-8d4c"

The authentication type determines which other nested authentication variables are accepted:

Authentication type Required environment variables Optional environment variables
none EOZILLA_AUTH__AUTH_TYPE=none
basic EOZILLA_AUTH__AUTH_TYPE=basic, EOZILLA_AUTH__USERNAME, EOZILLA_AUTH__PASSWORD
token EOZILLA_AUTH__AUTH_TYPE=token, EOZILLA_AUTH__ACCESS_TOKEN EOZILLA_AUTH__USE_BEARER, EOZILLA_AUTH__ACCESS_TOKEN_HEADER
login EOZILLA_AUTH__AUTH_TYPE=login, EOZILLA_AUTH__LOGIN_URL, EOZILLA_AUTH__USERNAME, EOZILLA_AUTH__PASSWORD EOZILLA_AUTH__ACCESS_TOKEN, EOZILLA_AUTH__USE_BEARER, EOZILLA_AUTH__ACCESS_TOKEN_HEADER
oauth2 EOZILLA_AUTH__AUTH_TYPE=oauth2, EOZILLA_AUTH__TOKEN_URL, EOZILLA_AUTH__CLIENT_ID EOZILLA_AUTH__GRANT_TYPE, EOZILLA_AUTH__USERNAME, EOZILLA_AUTH__PASSWORD, EOZILLA_AUTH__CLIENT_SECRET, EOZILLA_AUTH__OAUTH_TOKEN
oidc EOZILLA_AUTH__AUTH_TYPE=oidc, EOZILLA_AUTH__ISSUER_URL, EOZILLA_AUTH__CLIENT_ID EOZILLA_AUTH__SCOPES, EOZILLA_AUTH__OAUTH_TOKEN
api-key EOZILLA_AUTH__AUTH_TYPE=api-key, EOZILLA_AUTH__API_KEY EOZILLA_AUTH__API_KEY_HEADER

For OAuth 2.0, grant_type defaults to password. The password grant requires USERNAME and PASSWORD; the client_credentials grant requires CLIENT_ID and CLIENT_SECRET. Alternatively, provide a complete token snapshot as JSON in EOZILLA_AUTH__OAUTH_TOKEN.

Environment settings override values from the configuration file. Providing EOZILLA_AUTH__AUTH_TYPE selects a complete authentication configuration, so provide the variables required by that type as well. To override only a field of the authentication configuration selected in the file, omit EOZILLA_AUTH__AUTH_TYPE; for example, set only EOZILLA_AUTH__ACCESS_TOKEN to replace a stored login token.

Treat credential environment variables as secrets. Use the secret-injection mechanism of your deployment platform and do not commit them to source control.

Configuration Object

from cuiman import Client, ClientConfig

config = ClientConfig(
    api_url="https://anolis.api.org/process-api/v1",
    auth={
        "auth_type": "basic",
        "username": "polly",
        "password": "1234",
    },
)

client = Client(config=config)

Keyword Arguments

Pass configuration settings as keyword arguments directly to the client constructor:

from cuiman import Client

client = Client(
    api_url="https://anolis.api.org/process-api/v1",
    auth={
        "auth_type": "basic",
        "username": "polly",
        "password": "1234",
    },
)

Using the CLI

Before using the CLI, configure the public service settings and then log in:

$ cuiman configure
$ cuiman login

configure asks only for public connection and authentication metadata and writes it to the configuration file. login asks for credentials only when the selected authentication type requires them and stores them in the OS keyring. logout removes the matching keyring entry. For authentication type none, configure does not offer login.

When a configured authenticated service is used without available credentials, the CLI reports Please use 'cuiman login' to provide credentials. instead of showing an implementation traceback.

You can override settings anytime from environment variables or by using the --config/-c <file> option supported by most CLI commands.

For Python clients, client.login() (or await client.login() for AsyncClient) is optional when credentials are already available. The first API call performs non-interactive authentication when necessary. Explicit login also permits credential prompts or browser OIDC authentication; ordinary API calls never initiate interaction. See Client API.

OAuth2 client credentials supplied through environment variables or Python configuration can obtain their initial access token automatically. They do not require a pre-existing access token or an interactive CLI login.

Remote notebooks

A deployment can provide the processing API URL and an access token through EOZILLA_API_URL, EOZILLA_AUTH__AUTH_TYPE=token, and EOZILLA_AUTH__ACCESS_TOKEN. Python clients use these credentials without prompting or consulting the OS keyring. The token must be accepted by the processing API; a login session for JupyterLab alone does not supply it.

An injected access token has no automatic renewal mechanism. If the API rejects it, Cuiman reports the API error without starting interactive login. The deployment or user must provide fresh credentials. Environment variables are read when the client configuration is created; an existing client does not automatically receive later changes from the deployment.

OAuth2 and OIDC configurations can instead use explicitly supplied renewal credentials. Cuiman keeps renewed tokens in memory unless the configuration has a credential persistor, such as one attached when loading CLI keyring credentials. Renewal never opens a browser or prompts for credentials.

For the shared Authlib implementation and app ownership rules, see Authentication lifecycle.

Basic Settings

The most important configuration setting is api_url which provides the base URL to the OGC API - Processes.

By default, cuiman assumes the service the API URL is pointing to does not perform any authorisation on the incoming requests - which is rarely the case. Therefore, the client need to be configured with respect to some service-specific authorisation method.

Authentication Settings

The cuiman package allows for a limited set of client authentication types. The authentication type is provided by the nested auth.auth_type configuration setting.

Auth type none

The authentication type none means, the server doesn't require any client authentication. This is usually the case only for development environments.

config = ClientConfig(api_url="...", auth={"auth_type": "none"})

Auth type basic

Basic HTTP authentication is quite common for simple and older processing services. It requires username and password.

config = ClientConfig(
    api_url="...",
    auth={
        "auth_type": "basic",
        "username": "...",
        "password": "...",
    },
)

Auth type token

Authentication via API access tokens is widely used. cuiman supports bearer tokens (as used by OAuth 2.0) as well as custom headers.

For auth type token, cuiman treats access tokens as static and does not attempt refresh. Use auth type oauth2 when the server supports OAuth 2.0 refresh tokens.

config = ClientConfig(
    api_url="...",
    auth={
        "auth_type": "token",
        "access_token": "...",
    },
)

Omit access_token_header (or set it to None) for Bearer signing. Set it to a header name to send the raw token in that header; there is no separate bearer switch. This setting also applies to proprietary login authentication.

With custom header:

config = ClientConfig(
    api_url="...",
    auth={
        "auth_type": "token",
        "access_token": "...",
        "access_token_header": "X-Auth-Token",
    },
)

Auth type login

The authorisation type login is for a proprietary username/password endpoint. Cuiman posts the credentials as form fields to login_url and extracts an access token from the response. It does not use the OAuth 2.0 protocol or refresh tokens.

config = ClientConfig(
    api_url="...",
    auth={
        "auth_type": "login",
        "login_url": "https://identity.example.org/login",
        "username": "...",
        "password": "...",
        "access_token": "...",  # obtained by `cuiman login`
    },
)

Auth type oauth2

The oauth2 type uses an Authlib client for the password grant (the default) or client_credentials. Both require the provider's client ID. Authlib handles expiry and refresh before protected requests; a resource 401 is not replayed.

config = ClientConfig(
    api_url="https://processing.example.org",
    auth={
        "auth_type": "oauth2",
        "token_url": "https://identity.example.org/realms/example/protocol/openid-connect/token",
        "grant_type": "password",
        "client_id": "cuiman",
        "username": "...",
        "password": "...",
    },
)

If the password-grant client requires a client secret, supply client_secret through Python configuration, environment variables, or the keyring. Login prompts for username/password when needed. Client-credentials login prompts for a missing client secret. Both grants support cuiman login and save a complete oauth_token snapshot in the keyring. OAuth signing always uses a bearer header.

To bootstrap from an existing token in Python, provide auth={"oauth_token": saved_token} for the configured OAuth type. Preserve the complete mapping, including expires_at and any refresh token. Read subsequent token updates through client.token, not through the configuration snapshot.

Auth type oidc

The oidc type signs a user in through an OpenID Connect provider. Configure the provider's issuer URL (not its token endpoint) and a public client ID. For example, a Keycloak realm issuer is commonly https://identity.example.org/realms/example; Cuiman obtains its endpoints from <issuer>/.well-known/openid-configuration.

api_url: "https://anolis.api.org/process-api/v1"
auth:
  auth_type: oidc
  issuer_url: "https://identity.example.org/realms/example"
  client_id: "cuiman"
  scopes:
    - profile
    - email

openid is always requested, even when it is omitted from scopes. Add only provider- or service-specific scopes that are required, such as profile, email, or offline_access. The configuration file contains these public values only; access and refresh tokens are stored in the operating-system keyring after login.

config = ClientConfig(
    api_url="https://anolis.api.org/process-api/v1",
    auth={
        "auth_type": "oidc",
        "issuer_url": "https://identity.example.org/realms/example",
        "client_id": "cuiman",
        "scopes": ["profile", "email"],
    },
)

Logging in with OIDC

Run cuiman login after configuring OIDC. Cuiman discovers the provider, opens its authorization page, and starts a temporary HTTP server bound only to 127.0.0.1 on an ephemeral port. The provider redirects the browser to http://127.0.0.1:<port>/callback; Cuiman validates the response state and exchanges the authorization code using PKCE.

Register that loopback callback pattern with the OIDC client. For example, Keycloak clients can allow Cuiman's callback with:

http://127.0.0.1/*

Do not register a broad internet-facing wildcard redirect URI. The loopback address restricts the callback to the local computer, and the port is chosen for each login so concurrent or stale login attempts do not claim a fixed port.

If Cuiman cannot open a browser, or the browser must be opened manually, use:

$ cuiman login --no-browser

This prints the authorization URL while Cuiman continues to wait for the local callback. Open the URL in a browser on the same machine. cuiman logout attempts token revocation when the provider advertises a revocation endpoint, then always removes the locally stored credentials. When an OIDC access token is rejected and a refresh token is available, Cuiman refreshes it and persists any replacement token in the keyring.

Auth type api-key

The authorisation via API keys is also very common in SaaS scenarios. A simple API key api_key must be given, which is usually passed by a request header named X-API-Key:

| API Key Header | X-API-Key: abc123 | Very common in SaaS

config = ClientConfig(
    api_url="...",
    auth={
        "auth_type": "api-key",
        "api_key": "...",
        "api_key_header": "X-API-Key",  # default
    },
)