# Configuring Secrets and API Keys in the Agent-Native Onboarding Checklist

> Easily configure API keys and secrets in the Agent-Native onboarding checklist using registerRequiredSecret() in a Nitro plugin. Streamline your setup process.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-27

---

**Use `registerRequiredSecret()` in a Nitro plugin to automatically inject API key configuration steps into the Agent-Native sidebar checklist, which hides automatically once all required secrets are stored in the scoped database.**

Agent-Native provides a built-in onboarding system that guides users through essential configuration—including LLM engines, databases, and third-party API keys—via a collapsible checklist in the agent sidebar. According to the BuilderIO/agent-native source code, templates declare required secrets programmatically, and the framework automatically generates corresponding UI steps that persist values to a secure, scoped secret store rather than plain environment variables.

## How Secrets Become Onboarding Steps

The framework converts secret declarations into interactive checklist items through a three-stage pipeline involving registration, auto-injection, and UI rendering.

### Registering Required Secrets

Templates declare secrets using the `registerRequiredSecret()` function exported from [`packages/core/src/secrets/register.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/register.ts). This function accepts a configuration object specifying the environment variable name, human-readable label, scope, and whether the secret is mandatory.

```ts
// packages/core/src/secrets/register.ts
export function registerRequiredSecret(secret: RegisteredSecret): void {
  if (secret.required) {
    import("./onboarding.js")
      .then((mod) => mod.maybeRegisterSecretOnboardingStep(secret))
      .catch(() => {});
  }
}

```

When `required: true` is set, the function lazily imports [`packages/core/src/secrets/onboarding.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/onboarding.ts) to trigger automatic step generation without blocking the main thread.

### Auto-Injecting Steps

The helper `maybeRegisterSecretOnboardingStep()` in [`packages/core/src/secrets/onboarding.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/onboarding.ts) creates a standardized onboarding step that appears alongside built-in steps like "Connect an AI engine." This step registers itself with the internal API routes served at `/_agent-native/onboarding/*`.

### Rendering the Checklist

The UI consumes the checklist via `GET /_agent-native/onboarding/steps` (documented in [`packages/core/docs/content/onboarding.md`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/docs/content/onboarding.md)). The endpoint returns steps marked with *required* or *optional* pills. When a user saves an API key, the value writes to the scoped database secret store (handled in [`packages/core/src/secrets/routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/routes.ts)), and the `isComplete` callback evaluates whether the step is satisfied. The panel auto-hides when all required steps return true.

## Custom Onboarding Steps

Beyond auto-generated secret steps, templates can define fully custom onboarding workflows using `registerOnboardingStep()` within a Nitro plugin. This enables complex authentication flows like OAuth connections or multi-step forms.

```ts
// server/plugins/my-onboarding.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerOnboardingStep } from "@agent-native/core/onboarding";
import { listOAuthAccounts } from "@agent-native/core/oauth-tokens";

export default defineNitroPlugin(() => {
  registerOnboardingStep({
    id: "gmail",
    order: 100,
    title: "Connect Gmail",
    description: "Grant read/send access so the agent can work with email.",
    methods: [
      {
        id: "oauth",
        kind: "link",
        primary: true,
        label: "Sign in with Google",
        payload: { url: "/_agent-native/google/auth-url?scope=mail", external: false },
      },
      {
        id: "delegate",
        kind: "agent-task",
        label: "Let the agent set it up",
        badge: "beta",
        payload: { prompt: "Walk me through connecting Gmail. Set env vars as needed." },
      },
    ],
    isComplete: async () => (await listOAuthAccounts("google")).length > 0,
  });
});

```

The `isComplete` function determines whether the step displays as finished, while the `methods` array defines the available interaction patterns—either direct links, agent tasks, or form inputs.

## Workspace-Aware Secret Handling

When a template requires credentials that might already exist as a **workspace connection** (for example, a centrally managed Slack or Gmail integration), the onboarding step can query the existing connection catalog rather than prompting for duplicate API keys.

```ts
import { listWorkspaceConnectionProviderCatalogForApp } from "@agent-native/core/workspace-connections";

isComplete: async () => {
  const catalog = await listWorkspaceConnectionProviderCatalogForApp({
    appId: "mail",
    templateUse: "mail",
    provider: "gmail",
  });
  const conn = catalog.providers[0];
  return conn?.readiness.status === "ready" && conn.workspaceConnection.grantState === "granted"
    ? true
    : !!process.env.GMAIL_REFRESH_TOKEN;
};

```

This pattern checks `packages/core/src/workspace-connections` logic to determine if a valid connection exists before falling back to environment variable checks.

## Implementation Examples

### Register a Required OpenAI API Key

Create a server plugin that registers the secret and automatically generates the onboarding step:

```ts
// src/server/plugins/secrets.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerRequiredSecret } from "@agent-native/core/secrets";

export default defineNitroPlugin(() => {
  registerRequiredSecret({
    key: "OPENAI_API_KEY",
    label: "OpenAI API key",
    description: "Key for OpenAI LLMs",
    scope: "user",
    kind: "api-key",
    required: true,
  });
});

```

### Custom Step with Form Input

For secrets requiring complex input (like JSON service accounts), use a form method:

```ts
// src/server/plugins/custom-onboarding.ts
import { defineNitroPlugin } from "@agent-native/core/server";
import { registerOnboardingStep } from "@agent-native/core/onboarding";

export default defineNitroPlugin(() => {
  registerOnboardingStep({
    id: "firebase",
    order: 50,
    title: "Connect Firebase",
    description: "Provide your Firebase service account JSON.",
    methods: [
      {
        id: "form",
        kind: "form",
        label: "Paste JSON",
        payload: {
          fields: [
            { name: "FIREBASE_JSON", type: "textarea", placeholder: "{ … }" },
          ],
          writeScope: "workspace",
        },
      },
    ],
    isComplete: async () => !!process.env.FIREBASE_JSON,
  });
});

```

### Client-Side Hook for the Checklist

Access the onboarding state in React components using the client-side hooks:

```tsx
import { useOnboarding, OnboardingBanner } from "@agent-native/core/client/onboarding";

function SetupPanel() {
  const { steps, dismiss, reopen } = useOnboarding();

  return (
    <OnboardingBanner onDismiss={dismiss} />
  );
}

```

## Summary

- **`registerRequiredSecret()`** in [`packages/core/src/secrets/register.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/register.ts) is the entry point for declaring API keys that must appear in the onboarding checklist.
- Setting `required: true` automatically triggers `maybeRegisterSecretOnboardingStep()` to inject the step into the UI.
- Secrets persist to a scoped database store (user, workspace, or org) rather than plaintext environment variables.
- Use **`registerOnboardingStep()`** for non-secret configuration flows like OAuth or custom forms.
- Query **`listWorkspaceConnectionProviderCatalogForApp()`** to avoid redundant credential entry when workspace connections already exist.

## Frequently Asked Questions

### How do I make an API key optional in the onboarding checklist?

Set `required: false` (or omit the property) when calling `registerRequiredSecret()` in [`packages/core/src/secrets/register.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/register.ts). Optional secrets still appear in the onboarding UI but are marked with an optional pill and do not prevent the panel from auto-hiding.

### What scopes are available for secrets in Agent-Native?

The `scope` parameter accepts three values: **`user`** (tied to the individual account), **`workspace`** (shared across a workspace), or **`org`** (organization-wide). The value determines which database partition stores the secret and who can access it.

### How does the onboarding panel know when to hide?

The panel evaluates the `isComplete` callback for every required step. When all required steps return `true`, the UI automatically collapses. For built-in secret steps, completion is verified by checking the scoped secret store; for custom steps, you define the completion logic in the `registerOnboardingStep()` configuration.

### Can I use workspace connections instead of manual API key entry?

Yes. In your `isComplete` callback, import `listWorkspaceConnectionProviderCatalogForApp()` from `@agent-native/core/workspace-connections` to check if a valid connection exists. This allows the onboarding step to mark itself complete when a central admin has already configured the integration, bypassing manual key entry for end users.