Configuration and authentication — bRRAIn Docs

How a Platform SDK client authenticates: the supervisor's internal URL and token, client options, the app slug and namespace isolation, timeouts, and secrets hygiene.

Configuration and authentication

An SDK client authenticates as your extension, not as a person. The brain pod's extension supervisor gives your process a URL, a token and your slug; the client sends the token on every request and asserts the slug so the platform can isolate your vault namespace. There are no API keys to create or rotate in your code.

The Options struct

type Options struct {
	BaseURL    string       // required, absolute: scheme + host (BRRAIN_INTERNAL_URL)
	Token      string       // BRRAIN_INTERNAL_TOKEN; sent as "Authorization: Bearer <token>"
	HTTPClient *http.Client // optional; the default has a 30 s timeout
	UserAgent  string       // optional; default "brrain-platform-sdk/1.2.0"
	AppSlug    string       // optional; default os.Getenv("BRRAIN_APP_SLUG")
}

What platformsdk.New checks, and what it does not:

  • An empty BaseURL returns platformsdk: BaseURL is required. A URL with no scheme, such as 127.0.0.1:7843, returns BaseURL must be absolute.
  • An empty Token is accepted: the client simply sends no Authorization header, and the pod answers every call with 401. Check the token yourself at start-up.
  • AppSlug is trimmed and lowercased. A value containing /, \, NUL, or equal to . or .. is dropped silently, and no slug header is sent. Leave it empty in production so the supervisor's BRRAIN_APP_SLUG flows through; set it explicitly only in tests.

A production constructor

func newClient() *platformsdk.Client {
	client, err := platformsdk.New(platformsdk.Options{
		BaseURL:    mustEnv("BRRAIN_INTERNAL_URL"),
		Token:      mustEnv("BRRAIN_INTERNAL_TOKEN"),
		UserAgent:  "hello-notes/0.1.0",
		HTTPClient: &http.Client{Timeout: 150 * time.Second}, // room for model calls
	})
	if err != nil {
		log.Fatalf("hello-notes: build SDK client: %v", err)
	}
	return client
}

mustEnv exits with a message naming the missing variable; see the Quickstart. The full server is in Go with net/http.

Decisions in that constructor:

  1. Fail fast on missing configuration. A missing token is a deployment fault; say so at start-up rather than through a stream of 401s.
  2. Read the URL from the environment. Do not hard-code a host or port.
  3. Size the transport timeout for your slowest call. http.Client.Timeout caps every request regardless of a longer context deadline. Calls to the Handler can take well over 30 seconds on CPU-only pods, so model-calling extensions need a longer client timeout, with per-call context deadlines for everything else.
  4. Build one client per process and share it. Sub-client accessors are cheap.

Prove the platform is reachable

Make one cheap call at start-up whose "not found" answer still means healthy:

func bootCanary(ctx context.Context, c *platformsdk.Client) error {
	probeCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	_, err := c.Vault().Stat(probeCtx, "extensions/hello-notes")
	var apiErr *platformsdk.APIError
	switch {
	case err == nil:
		return nil // token accepted, namespace exists
	case errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusNotFound:
		return nil // token accepted, first run: namespace not created yet
	default:
		return err // 401: wrong token; transport error: wrong URL or pod not ready
	}
}

The slug and namespace isolation

When a slug is set, every request carries X-Brrain-App-Slug: <slug>. The platform uses it to enforce vault namespaces:

| Path | Who may use it | | --- | --- | | extensions/<your-slug>/ | Your extension. Other extensions get 403 and do not see it in unscoped searches. | | extensions/_<name>/ | The platform only. Any extension asserting a slug gets 403. Use the owning SDK call instead (for example OperatorEnv()). | | Everything else (projects/<Name>/, session files, standards) | Shared organization knowledge. Other controls apply; prefer Ingestion().Commit for content you publish here. |

Acting for a person

The internal API authorizes the extension. It does not know which person clicked a button in your interface, and a user's project permissions are not applied to your calls. When your extension acts for a user:

  • Take the user's identity from the authenticated request the console proxies to you, never from the request body or a query parameter the browser composed, and never on a route declared public.
  • Ask the policy engine before acting, and record the outcome in the audit chain.
  • Scope reads to what that user could see in Nexus.

Secrets hygiene

  • Never log, print or store BRRAIN_INTERNAL_TOKEN, and never send it anywhere except the client.
  • Never store vendor credentials. Resolve them at call time with OAuth().ResolveBearer or OperatorEnv().Get (see Examples).
  • Keep .env files used for local experiments out of version control. Tests should use a fake token against an httptest server.

Next