Skip to content

Authentication and Security

The dapcli authentication module supports two distinct operational modes: interactive browser-based OIDC login for human operators and headless client-credentials token minting for automation. The browser flow simulates a full Keycloak redirect chain to capture portal session cookies, which are then persisted with full attribute fidelity to avoid cross-domain routing issues. Conversely, the headless flow mints short-lived bearer tokens via the on-prem token service, which are required for the generic REST API layer. Both modes enforce strict secret handling, rejecting command-line or environment variable inputs in favor of interactive prompts, stdin, or file-based reading.

The browser_login function implements a programmatic walk of the OIDC authorization code flow, mimicking the behavior of a real browser interacting with Keycloak 1. The process begins by constructing an authentication URL that includes a state parameter. This state must be a URL-encoded base64 string representing the post-login landing path (defaulting to /home). If the state is not properly encoded, the portal’s callback handler returns a 4xx error, which the portal’s nginx layer redirects to dell.com, causing a silent failure rather than a clear OIDC error.

The client retrieves the Keycloak login form, extracts the action URL, and submits the username and password. If the login succeeds, the client follows the 302 redirect chain to the portal’s callback endpoint, where the session cookie is set [src: src: dap/auth/browser.py:L1-120]. The function returns a BrowserLoginState containing the captured cookies and cluster configuration.

To handle transient infrastructure issues, specifically a bug in DAP 2.0.0.1 where stale Keycloak session_code requests bounce to a marketing page, the login function retries up to five times. Each retry opens a fresh httpx client and a new Keycloak session code. Terminal failures, such as invalid credentials or realm changes, are raised immediately without retry.

diagram

After a successful browser login, the resulting session cookies are persisted to disk to avoid repeated authentication prompts. The save_session function writes the session data to ~/.config/dap-cli/session-<cluster>.json with file permissions set to 0600 2.

Crucially, the persistence mechanism saves the full cookie attributes, including domain, path, secure, and http-only flags, rather than just the name and value pairs. This is necessary because portal session cookies are domain-scoped to the portal host, while orchestrator-side cookies may be scoped to the orchestrator host. Stripping the domain attribute would cause httpx to send portal cookies to the orchestrator (and vice versa), leading to rejection by the respective nginx filters.

When a command is executed, load_session reads the JSON file and reconstructs the Session object. The Session.attach method then populates the httpx.Client’s cookie jar with these cookies, ensuring the correct domain scoping is maintained for subsequent requests. The portal session is short-lived (typically 1-2 hours); if a command receives a 401 from the orchestrator, the system surfaces a “session expired” message rather than silently re-authenticating, keeping the operator in control of credential entry.

For headless automation, the system uses the mint_onprem_token function to obtain a bearer token from the on-prem token service at /api/v1/oidc/token 3. This token universe is distinct from Keycloak realm tokens; the on-prem token service is the issuer for internal services and is the only type accepted by the orchestrator’s hzp-iam-proxy for customer-facing REST APIs.

The minting process requires client_id and client_secret corresponding to an admin client registered in iam_mgmt_svc.clients. The on-prem token service enforces strict requirements: the grant_type must be client_credentials, and the org_id must be explicitly included in the form body, even though it is implied by the client registration. The request is sent with Content-Type: application/x-www-form-urlencoded.

Upon receiving a 200 OK response, the function extracts the access_token, expires_in, and token_type. It also performs a best-effort decode of the JWT payload to surface the roles claim to the operator, though this is never used for authorization decisions.

The authentication module enforces strict policies regarding the handling of sensitive credentials. Passwords are never accepted via command-line arguments or environment variables 4. Instead, the dap auth login command provides three secure input methods:

  1. Interactive Prompt: The default method uses hide_input=True to prompt the user in the TTY.
  2. Stdin: The --password-stdin flag allows scripts to pipe the password securely.
  3. File: The --password-file flag reads the password from a managed file, with whitespace trimmed.

For the headless token minting path, the client_secret is retrieved from a persisted credential store rather than being passed as a command-line argument. The dap auth mint-token command loads the persisted admin client credentials and passes them to mint_onprem_token. This ensures that secrets are stored securely and only accessed programmatically when needed for token exchange.