Developer

Credentials API

Securely store API keys and secrets for your custom applet.

The Credentials API provides secure key-value storage for secrets such as API keys, tokens, and passwords. Values are encrypted at rest using SQLCipher and are scoped by your applet’s manifest ID - each applet has its own isolated credential namespace.

Capability required: credentials:store

Frontend (iframe)

import { createResourceClient } from "@rightplace/sdk";

const rp = createResourceClient();
await rp.ready();

// Store an API key
await rp.credentials.set("openai_api_key", "sk-...");

// Retrieve it later
const apiKey = await rp.credentials.get("openai_api_key");
// → "sk-..."

// List stored credential keys (returns key names only, not values)
const keys = await rp.credentials.list();
// → ["openai_api_key"]

// Delete a credential
await rp.credentials.delete("openai_api_key");

Backend (Node.js)

The same API is available in backend methods via the rp host object:

import { createResourceServer } from "@rightplace/sdk/server";

const server = createResourceServer({
  methods: {
    saveApiKey: async (params, { rp }) => {
      await rp.credentials.set("api_key", params.apiKey);
      return { ok: true };
    },

    fetchData: async (_params, { rp }) => {
      const apiKey = await rp.credentials.get("api_key");
      if (!apiKey) throw new Error("API key not configured");

      const res = await rp.http.request("https://api.example.com/data", {
        headers: { Authorization: `Bearer ${apiKey}` },
      });
      return JSON.parse(res.body);
    },
  },
});

server.start();

MCP

Credentials are intentionally not exposed over MCP. Secrets never leave the owning applet - no agent tool can read, list, or enumerate stored credential keys or values.

If an agent needs to call an external API that requires a secret, route the call through an applet method that owns the credential (createResourceServer method -> rp.credentials.get -> outbound rp.http.request).

RobinPath Bridge

Also not exposed through rightplace.*. A RobinPath script that needs a secret should either:

  1. Call the applet’s own method (which reads the credential internally), e.g.

    rightplace.hook "res_abc" "fetchData" {query: "ping"} into $result
  2. Or, for ad-hoc scripts you own, use RobinPath environment variables (robinpath_env_set, robinpath_env_list). These are stored in the RobinPath config, not the applet credential store.

API Reference

rp.credentials.get(key)

ParameterTypeDescription
keystringThe credential key to retrieve
ReturnsPromise<string | null>The value, or null if not found

rp.credentials.set(key, value)

ParameterTypeDescription
keystringThe credential key to store
valuestringThe secret value to store
ReturnsPromise<void>

rp.credentials.delete(key)

ParameterTypeDescription
keystringThe credential key to delete
ReturnsPromise<void>

rp.credentials.list()

ParameterTypeDescription
ReturnsPromise<string[]>Array of credential key names (not values)

Manifest Configuration

{
  "capabilities": [
    "credentials:store"
  ]
}

Notes

  • Values are encrypted at rest via SQLCipher. They are never exposed in logs.
  • list() returns key names only, never the secret values.
  • Credentials are scoped by manifest ID, not applet instance. All instances of the same applet type share the same credential store.
  • Credentials persist across app restarts and applet updates.
  • Use credentials for secrets (API keys, tokens, passwords). For non-sensitive data, use the Storage API instead.