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.
- Default settings hard-coded into the
cuiman.api.ClientConfigclass. - Settings loaded from a given or the default configuration file passed as
config_path. - Settings loaded from the selected configuration class's
.envfile. - Settings loaded from environment variables using the selected class's prefix.
- Explicit fields from a configuration object passed as
config. - 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
},
)