arizuko

arizuko › howto › Add an OAuth provider

OAuth providers

Some services give a static API key that you paste once. Other services use a "Connect" flow: the user lets arizuko act for them, and the service returns a short-lived access token and a refresh token. For the second kind, arizuko uses a surrogate OAuth provider. arizuko runs the flow, stores the token in the secrets table and refreshes the token before it expires, so the tools of an agent keep working.

A new provider needs only configuration: one .toml file in the data directory, a redirect URI at the provider and two env vars. No code and no rebuild. github and google are built in. This page adds a different provider.

Use an OAuth provider for tokens that act as the user. Examples are Google Drive, Slack, Notion and Linear, where the token expires. For a long-lived API key of a folder, a secrets row for a REST connector is simpler.

A descriptor file names the provider

Write <datadir>/surrogate/<name>.toml. The file name is the provider name. It becomes the URL segment and the start of the env var names. Example for Slack:

# <datadir>/surrogate/slack.toml
auth_url       = "https://slack.com/oauth/v2/authorize"
token_url      = "https://slack.com/api/oauth.v2.access"
revoke_url     = "https://slack.com/api/auth.revoke"
scopes         = ["chat:write", "channels:read"]
secret_key     = "SLACK_TOKEN"        # secrets-table key the token lands in
allowed_domain = "slack.com"
access_type    = ""                   # "offline" where a provider gates refresh (google)

auth_url, token_url and secret_key are required. If one is missing, dashd does not start, and the error names the file. A provider with missing fields cannot run the flow, so the error comes at start and not at the first click. A file with the name of a built-in provider replaces the built-in provider. So you can change the scopes of github.toml without a new binary.

arizuko joins the scopes with spaces. OAuth2 uses that format. Write the scopes as a TOML array.

The provider must know the exact redirect URI

In the app console of the provider, for example the Slack API dashboard, the Google Cloud console or the Notion integrations, add this callback URL:

<AUTH_BASE_URL or WEB_HOST>/dash/me/connections/<name>/callback

dashd reads AUTH_BASE_URL first and uses WEB_HOST when it is not set.

For a Slack provider on acme.example.com, the URL is https://acme.example.com/dash/me/connections/slack/callback. The provider refuses the flow when the redirect URI is not the one it has. Operators often forget this step.

The client credentials go into .env

The client ID and secret from the provider go into the .env of the instance. The key contains the provider name in upper case, with _ in place of -:

SURROGATE_SLACK_CLIENT_ID=1234567890.abcdef
SURROGATE_SLACK_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx

A provider without credentials still loads. The connections page does not show it until it can run, so a user never sees a "Connect" button that fails.

Only the GitHub pair reaches dashd. arizuko generate writes SURROGATE_GITHUB_CLIENT_ID and SURROGATE_GITHUB_CLIENT_SECRET into the env file of dashd, and no other SURROGATE_* key. For every other provider, the pair in .env does not reach dashd, and the provider stays connectable=false.

After a restart, users can connect

sudo systemctl restart arizuko_<instance>

"Connect Slack" then appears at /dash/me/connections. A user clicks it, approves at Slack and comes back. arizuko writes the token into the secrets table under secret_key, here SLACK_TOKEN. The broker refreshes the token before it expires. If the provider revokes the refresh token, the agent gets a "reconnect" error and not a silent failure.

A connector gives agents a tool with the token

The stored token is a secret like any other. Point a REST or MCP connector at secret_key, and the agent gets a tool that calls the service as the connected user. No credential enters the guest. MCP reference lists the tool surface. Grants shows how to select the folders that can call the tool.

dashd logs each provider at start

sudo journalctl -u arizuko_<instance> --since "1 min ago" \
  | grep -i "surrogate provider"

At start, dashd logs each loaded provider and whether it has credentials. A missing provider means that the .toml file did not parse or is in the wrong directory. connectable=false means that the SURROGATE_<NAME>_CLIENT_* variables are not set.

Three pages give the details

secrets
Where the token is stored and who can read it.
env reference
The SURROGATE_* and WEB_HOST variables.
webhooks
The other way an external service reaches an agent.