BuildBaseBuildBase

Set up agent and app access

Let AI agents and other companies' apps act for one of your users, with that person's approval, through BuildBase's OAuth 2.0 server.

Your users may want an AI agent, such as Claude, ChatGPT or Cursor, or another company's app to work in your app for them: read their notes, file a report, start a job. BuildBase is an OAuth 2.0 server for every app, so the agent can ask for that access the standard way. The person signs in on your hosted sign-in page, sees a consent screen that names the agent and what it wants, and presses Allow access. The agent then acts as that person and can never do more than they can. They can take the access back at any time from your app.

Warning

This is not a way for people to sign in, and it adds no button to your sign-in page. People still sign in with the methods you already offer. This page is about what they let an agent or an app do afterwards.

Before you start

  • A BuildBase plan that includes the OAuth 2.0 server, for the client the agent uses, and one that includes agent readiness, for the switches on the Agent readiness tab. Your plan's limit on connected agents applies to each new one a person allows.
  • A token address on your own server (the Application token URL), reachable from the internet. BuildBase asks it for the agent's token after each approval, so your server decides what the token is.
  • For agents that call tools in your app, an MCP server on your side. The SDK has one: see MCP and agents.

Step by step

There are two ways for an agent to get a client: you create one for an agent or app you know, or you let agents register themselves. Both use the consent screen.

1. Create a client for the agent

  1. In the BuildBase console, press Users in the left-hand bar (the User management area), then Authentication under Access, and the Settings tab.
  2. Press Create auth client. Give it a Title, such as Acme Assistant: it is the name people see on the consent screen. Choose the OAuth 2.0 provider type, fill in the Application token URL (https://app.acme.example/api/agent/token) and the Application profile URL, and press Create.
  3. Copy the client ID and the Client secret from the next dialog. It is shown once. Your token address checks every request from BuildBase with this secret. (The dialog is the same as for a device client.)
  4. Press Edit on the new client. Under Client kind, choose Agent (third-party). That is what makes people see the consent screen. An Application (first-party) client is your own software and signs people in without one.

Client kind in the Edit auth setting sheet for Acme Assistant: Agent (third-party) chosen, for AI agents and external integrations that need the person to approve on a consent screen

  1. Fill in the Application revoke URL (https://app.acme.example/api/agent/token/revoke). When a person takes access back, BuildBase tells your server there, so it can stop accepting the tokens it gave out. It is optional, but without it a token you minted keeps working until it runs out. Keep Require PKCE ticked: agents prove each sign-in with a one-time secret of their own.

The OAuth 2.0 settings of Acme Assistant: Application token URL and Application revoke URL on app.acme.example, Require PKCE, and Device code sign-in off

  1. Under Redirect URLs, press Add redirect URL and paste the address the agent gave you, such as https://assistant.acme.example/oauth/callback. People are sent back there after they allow or deny.

Redirect URLs for Acme Assistant: https://assistant.acme.example/oauth/callback, where the person is sent back after they allow or deny

  1. Under Methods, tick how people sign in before they approve, such as Email and password, and press Update.

Give the agent its client ID, its secret if it runs on a server it controls, and your OAuth 2.0 addresses (from the client's Edit sheet, under OAuth 2.0 addresses).

2. Turn on agent readiness

Open the Agent readiness tab. The card at the top explains the three steps: agents discover where your users sign in, get a client, and ask for consent.

The Agent readiness tab: How AI agents connect to your app, in three steps: Discover, Get a client, Consent, where the agent acts as that user and never beyond their permissions

In the Agent access card:

SettingWhat it does
Agent readinessPublishes where your users sign in, so an agent can find your OAuth 2.0 addresses by itself
Let agents register themselvesAgents such as Claude or ChatGPT connect to your app on their own, with no client to create for each. A person still signs in and approves. Off until you turn it on (Dynamic Client Registration)
Base client for self-registered agentsEvery agent that registers itself is copied from this client: its token, profile and revoke URLs, its sign-in methods and its secret, so your server checks every agent with the one secret it holds
Allow agent self-signupSomething else: lets your own server make user accounts for bots. Leave it off unless you run bots that need accounts. See Agent accounts

Turn on Agent readiness and, if you want, Let agents register themselves with Acme Assistant as the base client, then press Save changes.

The Agent access card: Agent readiness on, Allow agent self-signup off, Let agents register themselves on, and Acme Assistant picked as the base client for self-registered agents, with Save changes

Further down, Discovery URLs lists the addresses agents read, each with a copy button. An MCP server built with the SDK points agents to them, so you rarely send them anywhere yourself.

The discovery addresses agents read: the authorization server metadata, the issuer, and the client registration endpoint, each with a copy button

Self-registered agents do not crowd the Settings tab: they are hidden from the list until you pick Self-registered by agents in its Source filter. Each one is read-only and follows its base client.

The clients on the Settings tab: Acme Assistant with the type Agent, and Acme CLI and Acme Analytics with the type App, each with its masked client ID and secret

3. Your token address

After each approval, BuildBase asks your Application token URL for the token the agent will use, signed with the client's secret. The SDK has the whole handler:

// app/api/agent/token/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { handleAppTokenRequest, mintAgentToken } from '@buildbase/sdk';

export async function POST(request: NextRequest) {
  const { status, body } = await handleAppTokenRequest({
    authorization: request.headers.get('authorization'),
    clientSecret: process.env.BUILDBASE_AGENT_CLIENT_SECRET!,
    mintToken: (claims) =>
      mintAgentToken({ claims, secret: process.env.SYSTEM_SECRET! }),
  });
  return NextResponse.json(body, { status });
}

The revoke address has a matching handleAppRevokeRequest({ authorization, clientSecret, onRevoke }). MCP and agents covers the MCP server and tools that use the token.

Scopes

A scope is a name for one kind of access, such as notes:read. BuildBase passes the scope names an agent asks for through to the consent screen and to your token address, and your app decides what each one allows. The standard ones are said in words on the consent screen:

ScopeThe consent screen says
openidConfirm who you are
profileSee your name and profile
emailSee your email address
offline_accessStay connected when you are not using it
Your ownThe name as written, such as notes:read

Name your own scopes in your MCP server's scope catalog, so agents can find them, and check them in each tool with requiredScopes.

What people see

The agent opens your hosted sign-in page in the person's browser. They sign in as usual, then see the consent screen, named after the agent: what it will be able to do, Allow access and Deny.

Acme Assistant wants to access your account: this will allow Acme Assistant to confirm who you are, see your name and profile and your email address, stay connected when you are not using it, and notes:read, with Allow access and Deny

Allow access sends them back to the agent's redirect URL with a one-time code, which the agent exchanges for its tokens. Deny sends them back with error=access_denied, and nothing is recorded.

A self-registered agent's consent screen shows the name the agent gave itself:

Notes Helper, an agent that registered itself, wants to access your account: confirm who you are, see your name and profile, and notes:read, with Allow access and Deny

On a phone:

The consent screen on a phone for Notes Helper: Review the requested access, the list of what it may do, then Allow access and Deny

People are asked once for each scope an agent wants. When the same agent comes back for the same scopes, the consent screen is not shown again. When it asks for more, it is shown again. To be asked about everything again, the person disconnects the agent first. The consent screen follows the person's language, in any of the 8 languages the sign-in page speaks.

Check it yourself

The sign-in page preview has no consent screen. To see the real one, have the agent connect, or open an authorization address in a browser. It needs a PKCE pair:

VERIFIER=$(openssl rand -hex 32)
CHALLENGE=$(printf %s "$VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')
echo "https://api.console.buildbase.app/api/v1/auth/oauth2/authorize?org=$BUILDBASE_ORG_ID&client_id=$AGENT_CLIENT_ID&response_type=code&redirect_uri=https%3A%2F%2Fassistant.acme.example%2Foauth%2Fcallback&scope=openid%20profile%20notes%3Aread&state=check&code_challenge=$CHALLENGE&code_challenge_method=S256"

In your app (SDK)

People see and take back the access they gave on the Connected agents screen of your app's settings dialog. Each agent shows the access it was given and when, with Disconnect.

The Connected agents screen in the app: Acme Assistant and Notes Helper, each with the access it was given, when, and a Disconnect button

Disconnect asks first, naming the agent, and Cancel leaves it connected.

The question Disconnect asks: "Disconnect Acme Assistant? It loses access to your account at once. You can connect it again at any time." with Cancel and Disconnect

Once confirmed, it takes effect at once: the agent's grant and every token it holds for that person are deleted, its refresh token stops working, and BuildBase calls your Application revoke URL so your server can stop accepting the tokens it minted.

Connected agents after Disconnect: only Notes Helper is left; Acme Assistant lost its access at once

Open it from your own button, or put the screen anywhere with ConnectedAgents:

// components/agent-access.tsx
import { ConnectedAgents, useSaaSAuth } from '@buildbase/sdk/react';

export function ManageAgentsButton() {
  const { openWorkspaceSettings } = useSaaSAuth();
  return (
    <button onClick={() => openWorkspaceSettings('connected-agents')}>
      Connected agents
    </button>
  );
}

export function AgentAccessPage() {
  return <ConnectedAgents />;
}

useConnectedAgents() gives agents, loading, error and revoke(clientId) for a screen of your own. Pass mcp={{ url: 'https://app.acme.example/mcp', name: 'Acme' }} to SaaSOSProvider to add a Connect an agent guide to the screen. To hide the screen, pass ui={{ settings: { sections: { 'connected-agents': false } } }}.

Check it works

  • An authorization request for your agent client shows the consent screen after sign-in, named after the client.
  • Allow access returns a code to the redirect URL, and the token exchange answers with an access_token your server minted.
  • The person's Connected agents screen lists the agent.
  • After Disconnect, the agent's refresh token is refused and your revoke address was called.

Things to watch out for

  • People are asked again only for new access. An agent that comes back for the same scopes gets them without the consent screen. One that asks for more shows it again. To be asked about everything again, the person disconnects the agent first.
  • A self-registered agent chooses its own name. Nothing checks it, so anyone can register an agent named after a well-known one. Leave Let agents register themselves off unless any agent may ask your users for access.
  • An agent's refresh token works once. Each refresh gives a new one. Using an old one again, for example from two copies of the agent at once, ends every token in that chain, and the person connects the agent again. An agent's refresh token also expires after 30 days unused.
  • If your token address fails during a refresh, the agent has to reconnect. BuildBase spends the refresh token before it asks your server for the new access token.
  • Your token address has 10 seconds and gets no redirects. BuildBase does not follow a redirect, so an address that redirects, such as http:// to https://, fails with 503 temporarily_unavailable.
  • Without a revoke URL, disconnecting does not stop tokens you minted. They keep working until they expire.

If something goes wrong

What you seeWhyWhat to do
No consent screen; the agent gets a code straight awayThe client is Application (first-party), or the person already allowed this agent everything it asks forChoose Agent (third-party). To ask again, the person disconnects the agent
error=invalid_request, "code_challenge is required (PKCE)", at the redirect URLRequire PKCE is on and the request has no code_challengeSend a PKCE pair, as every agent should
"Connecting new agents is not available right now."Your plan's limit on connected agents is reachedRaise the plan, or have people disconnect agents they no longer use
503 temporarily_unavailable, "The application server failed to issue a token. Try again later."Your Application token URL did not answer with a tokenCheck the route is reachable and checks with this client's secret
400 invalid_grant, "Invalid refresh token"The person disconnected the agentThe agent asks the person to connect again
The agent cannot register itselfLet agents register themselves is off, or no base client is pickedTurn it on and pick a base client on the Agent readiness tab

Next steps