Providers and accounts
A provider describes how to authenticate with a service. An account is one saved, reusable instance of it, and an app requirement is the slot it fills.
Provider
A provider is a service and its authentication, declared in app code. It has an ID, one or more named authentication methods and an optional name.
import { defineProvider, object, secrets, string } from "apps";
const vercel = defineProvider({
id: "vercel.com/api",
auth: {
api_key: secrets({
label: "API token",
fields: object({ token: string({ minLength: 1 }) }),
}),
},
});
api_key is the method name. secrets means fields you paste; oauth2 means a
browser sign-in.
The ID names one kind of credential at one vendor. By convention it is the
vendor’s domain, an optional product, and api or mcp, such as
vercel.com/api, vercel.com/mcp or google.com/gmail/api. An MCP server
uses <domain>/api only when every method’s credential works on both the API
and the MCP server. When the MCP server has its own OAuth that the API does not
accept, <domain>/api holds the shared methods and <domain>/mcp holds that
OAuth: a Linear API key works on both and is linear.app/api, while Linear’s
MCP OAuth is linear.app/mcp. A protocol no
vendor owns uses its bare name, such as imap; a private service uses your own
domain, such as acme.com/billing/api; a server that only runs on your machine
uses local/<name>. Any lowercase ID of letters, digits, ., - and /
deploys; the deploy warns when one does not follow the convention and names the
catalog’s ID for the vendor when it knows one. Two apps that declare the same ID share accounts, so
an account saved for one can be selected by the other. They must define each
method of the same name the same way, apart from OAuth scopes; a deploy that
redefines a method fails.
Omit name unless you want a specific one. An app’s own name appears only in
that app’s connect and requirement prompts. Elsewhere, and when the app gives
none, Executor uses the integrations.sh catalog’s name for the ID, then a name
another app gave it, then a name derived from the ID: vercel.com/api shows as
“Vercel” and vercel.com/mcp as “Vercel MCP”.
Tell people where to get credentials with each field’s description and, for
ordered setup or prerequisites, a method guide; an oauth2 method’s
clientGuide explains creating an OAuth client at the service:
api_key: secrets({
label: "API token",
guide: "Sign in as the user the app acts as, then create the token.",
fields: object({
token: string({
description: "Create one under [Account settings](https://vercel.com/account/tokens).",
}),
}),
}),
These are Markdown, shown in the connect form. Links must be https:, and a
deploy refuses HTML, images, guides over 4,000 characters and descriptions over
1,000. Help belongs to the app that writes it: editing it never redefines the
method, and two apps may explain the same method differently.
A provider ID is also not permission. Knowing it does not let an app read an account. Access is authorized separately.
Account
An account is one saved instance of one provider method: a label plus the field values. It is owned, and it is reusable.
Two accounts of the same provider are normal. “Work Vercel” and “Personal Vercel” hold different tokens, and each of your profiles for an app selects one of them. Several apps can use the same account without copying the credential.
An account can also have a description: free text for agents, such as “reads only; use the sandbox account for writes”. Agents read it with the label when they choose between accounts. Set it when you create the account or edit it later; neither changes the credential.
Fields are an object that matches the method’s schema — { token }, or
{ email, key } — not one normalized secret string.
Requirements
An app declares a requirement for each provider it needs. The requirement is a named slot on the app.
const requirements = { accounts: { vercel } };
vercel is the slot name. A plain provider needs exactly one account.
provider.many() accepts zero or more, and the app receives a list.
Setting up a profile means choosing which account fills each slot. The profile saves the account IDs, not copies of the credentials. Replace the credentials on the account and every profile that selected it follows.
A profile cannot run a tool that needs a slot you have not filled.
Not a login
Signing in to Executor with Google or GitHub is not an account in this sense. A login proves who you are. An account is a credential an app uses. A login never creates an account, and a tool never receives your login token.
What is coming later
- Providers backed by a signed-in browser session.
See Connect an account for the steps.