Skip to main content

HTTP Basic Authentication

experimental

Prompts for a username and password and attaches them as an HTTP Basic credential.

Credential source for the basic secret type. Registers an auth broker so any feature can require login for a named context, then stores the username/password in memory only and lets HttpClient attach Authorization: Basic. Prefer server-side proxy credentials when the login is per-deployment rather than per-user.

IDbasic-auth
Version1.0.0
Categoriesauth
Sourcemodules/basic-auth

Keywords: auth · basic · credentials · http

Documentation

basic-auth

Credential source for HTTP Basic authentication.

HttpClient has always shipped a "basic" auth handler — it turns a {username, password} secret into an Authorization: Basic … header (src/classes/http-client.ts). Nothing produced such a secret, so the handler always returned {}. This module fills that gap: it registers a broker with APPLICATION_CONTEXT.auth, prompts the user with the shared UI.LoginModal, and stores the credential in XOpatUser under the basic secret type.

Choose the right mechanism first

SituationUse
One credential for the whole deployment (an API key, a service account)server.secure.proxies.<alias>.headers = { "Authorization": "Basic <% ENV_VAR %>" } — the credential never reaches the browser
Each user has their own username/passwordthis module
The upstream speaks OIDC or SAMLoidc-client-ts / oidc-server-ts / saml-auth — short-lived, revocable tokens

Basic is the weakest of the three: the credential is replayable, cannot be revoked, cannot expire, and is sent on every single request. Prefer a token-based broker whenever the upstream offers one.

Configuration

Contexts come from static config (include.json merged with the deployment ENV.modules["basic-auth"]), never from session config — a session bundle must not be able to point an auth context somewhere of its choosing (AGENTS.md §7).

"modules": {
"basic-auth": {
"permaLoad": true,
"contexts": {
"archive": {
"serviceName": "Slide archive", // shown in the prompt
"autoLogin": false, // prompt at boot; default false (lazy)
"allowInsecure": false // permit plain HTTP; DEV ONLY
}
}
}
}

A feature then requires that context the same way it would for OIDC or SAML — authMode / authContext static meta plus this.requireAuthContext(), or an HttpClient built with auth: { contextId: "archive", required: true }. No feature ever names this module: it declares a context, and whichever broker claims that context provides the credential.

Each context declares secretTypes: ["basic"], so HttpClient and XOpatAuth.isAuthenticated / getToken follow it automatically instead of assuming jwt.

The refresh handler is bound per context from init(), not swept once at registration — a context installed later through a requireContext fallback reaches init() and nothing else, and without a secret-needs-update provider its 401s went unanswered forever with nothing on screen. A dismissed prompt (or one refused for an insecure origin) now also reports to the core recovery gate, so the appbar badge and the awaitInteractive request hold work here as they do everywhere else.

autoLogin: true is acted on by core (XOpatAuth.runAutoLogin), not by this module's init(). There is no silent route here — the credential only exists once the user types it — so core's ladder falls straight through to the interactive rung, which is what autoLogin on a Basic context is asking for. The broker declares canLoginWithoutGesture: true (the prompt is an in-page modal, not a popup a blocker can refuse) and, explicitly, navigatesOnLogin: false — nothing here unloads the document, so it must not consume the single boot-navigation slot that core arbitrates between the redirect brokers.

Security properties

  • Memory only. The credential lives in XOpatUser._secret and is gone on reload. It is never written to AppCache, localStorage or sessionStorage: unlike a short-lived bearer token it cannot be revoked or expired, so persisting it turns one compromised browser profile into a permanent account takeover.
  • HTTPS required. Authorization: Basic is base64, not encryption. Login is refused on a plain-HTTP origin unless the context sets allowInsecure: true (localhost is always allowed, for development).
  • Same-origin only. XOpatRemoteEndpoint._authHeaders drops auth headers for cross-origin absolute URLs. A direct-to-tile-server deployment therefore needs the server proxy; the credential is not attached to a third-party origin.
  • No sign-up. The prompt hides the sign-up tab (showSignup: false) — Basic verifies existing credentials, it cannot create them.
  • No server-side verifier. This module provides an outbound credential. The xOpat server cannot validate an inbound Authorization: Basic — the built-in proxy/RPC verifiers are jwt / bearer and both require the Bearer prefix.

Logout

broker.logout(contextId) calls XOpatUser.logout(contextId), which clears both the identity and every secret bound to that context.