---
title: Providers and accounts
description: "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.

```ts
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:

```ts
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](/concepts/apps-and-deployments#profile) 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.

```ts
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](/connect-an-account) for the steps.
