CLI authentication for DotID

The FGAI CLI uses DotID control-plane APIs. It does not call a separate /cli/* API family and it does not scrape console web pages.

Supported credential profiles

Profile

Use it when

Credential

Human interactive

You are operating your Account, Organization, Identity Center, quotas, or audit logs as yourself.

Keycloak OAuth/OIDC bearer token. Account/org commands also use a backend-issued session context.

Service user

A long-running tool or script must call APIs on behalf of an Account.

Account-owned service-user access key.

Workload identity

CI/CD or a deployed workload needs a short-lived token without storing a long-lived secret.

External OIDC subject token exchanged at /oauth2/token.

These are separate provider families. The CLI must not hide all three behind a single configure --kind switch:

  • fgai configure is the static access-key path, equivalent in spirit to aws configure, and stores service-user credentials only.

  • fgai auth login is the human interactive path. The target implementation is a browser/device login with refreshable cached sessions, not a pasted token as a permanent interface.

  • fgai sts exchange-token is the workload federation path. It is for CI and deployed runtimes, not local operator profiles.

Human interactive flow

Human CLI commands use an already-issued DotID bearer token and then discover available contexts:

GET /api/me/contexts
Authorization: Bearer <token>

For account-scoped or organization-scoped commands, the CLI sends the chosen context:

X-Session-Context-Id: <context_id>

Account and organization discovery is caller-derived:

GET /iam/v1/portal/my-accounts
GET /iam/v1/portal/my-organizations

Do not pass another user’s email, Account ID, or Organization ID to discover their access.

Current fgai command shape:

fgai auth login \
  --profile dev-intl \
  --token "$DOTID_TOKEN" \
  --context-id "$DOTID_CONTEXT_ID"

fgai contexts list --auth default --json
fgai accounts list --auth default --json
fgai organizations list --auth default --json

For local simulation, use the local profile or override the API base URL:

fgai accounts list \
  --auth default \
  --profile localstack \
  --api-base-url http://api.dev.fgai.test \
  --json

The CLI does not call the Keycloak Admin API and does not scrape console routes to discover contexts.

Service-user flow

Service users are non-human Account users for API automation. They are created by an Account root or authorized Account administrator. A service user has no Profile, no password-based console login, and no web-console access.

Current service-user creation endpoint:

POST /identity/v1/accounts/{accountId}/service-users
Authorization: Bearer <human-admin-token>
X-Session-Context-Id: <account-context-id>

DotID authorizes this with iam:User:CreateServiceUser.

After creation, use the Account credential flow to issue an access key for the service user. Do not create passwords or MFA credentials for service users.

Current fgai command shape for storing a service-user credential profile:

fgai configure \
  --profile dev-intl \
  --account-id "$ACCOUNT_ID" \
  --access-key-id "$ACCESS_KEY_ID" \
  --secret-access-key "$SECRET_ACCESS_KEY" \
  --name ci-service-user

fgai auth service-user configure \
  --profile dev-intl \
  --account-id "$ACCOUNT_ID" \
  --access-key-id "$ACCESS_KEY_ID" \
  --secret-access-key "$SECRET_ACCESS_KEY" \
  --name ci-service-user

The CLI stores this as an Account-bound API credential profile with the no_console_access invariant. It does not create the service user; the Account root or authorized Account admin must create the service user and key first.

Workload-identity flow

Workload identities are for CI/CD and runtime workloads. They are not service users and do not hold long-lived access keys.

Bind an external OIDC issuer and subject to a workload identity:

POST /identity/v1/accounts/{accountId}/workload-identities/federated
Authorization: Bearer <human-admin-token>
X-Session-Context-Id: <account-context-id>

DotID authorizes this with iam:WorkloadIdentity:CreateFederated.

At runtime, exchange the external OIDC token:

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<external-oidc-jwt>
&subject_token_type=urn:ietf:params:oauth:token-type:jwt
&requested_token_type=urn:ietf:params:oauth:token-type:access_token
&audience=<registered-service-audience>

The subject token audience must be dotid-token-exchange. DotID returns a short-lived access token when the workload identity is trusted and has iam:ExchangeToken on the target service.

Current fgai command shape:

fgai auth workload configure \
  --profile dev-intl \
  --subject-token-file ./github-oidc.jwt \
  --audience <registered-service-audience> \
  --name github-actions

fgai sts exchange-token \
  --profile dev-intl \
  --subject-token-file ./github-oidc.jwt \
  --audience <registered-service-audience> \
  --json

Store workload configuration separately from service-user configuration. A workload identity is not a service user and should not hold a long-lived access key.

Local credential storage

The CLI stores local credential profiles under the user config directory. Set FGAI_CLI_HOME to isolate credentials during tests:

FGAI_CLI_HOME="$(mktemp -d)" fgai auth login \
  --profile localstack \
  --token test-token \
  --context-id test-context

Credential files are written with owner-only permissions. CLI output redacts bearer tokens and access-key secrets; use fgai auth status --json to inspect metadata without printing secret values.

Logout removes the local credential profile:

fgai auth logout --name default

Logout does not revoke a service-user access key in DotID. Delete or rotate the key from the Account workbench when you need to invalidate the credential.

Forbidden shortcuts

Do not use these from the CLI:

  • console routes such as /account/, /organization/, /identitycenter/, or /profile/.

  • browser-shaped profile routes that are not documented as control-plane APIs.