arizuko › howto › Add an OAuth provider
add an OAuth provider
Some services hand out a static API key you paste once. Others
want a proper “Connect” dance — the user
authorizes arizuko to act as them, and the service returns a
short-lived access token plus a refresh token. That second kind
is a surrogate OAuth provider: arizuko runs the
dance, stores the token in the secrets table, and
refreshes it near expiry so an agent’s tools keep working.
Adding one is pure configuration. A .toml file in
the data dir, a redirect URI registered at the provider, two env
vars. No code, no rebuild. github and
google ship built in; here’s how to add any
other.
secrets-table row wired to an
[[connector]] REST provider is simpler.
1. drop a descriptor
Write <datadir>/surrogate/<name>.toml.
The basename is the provider name — it becomes the URL
segment and the env-var stem. Example, 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. Leave one out and the
daemon refuses to boot, naming the file — a half-defined
provider is a broken dance, better caught at startup than at the
first click. A file here that shares a name with a built-in
replaces it, so you can override github.toml’s
scopes without touching the binary.
2. register the redirect URI
In the provider’s app console (Slack API dashboard, Google Cloud console, Notion integrations…), add this exact callback URL:
<WEB_HOST>/dash/me/connections/<name>/callback
For a Slack provider on acme.example.com that is
https://acme.example.com/dash/me/connections/slack/callback.
The provider rejects the dance if the redirect URI doesn’t
match what it has on file — this is the step people forget.
3. set the client creds
The confidential-client id and secret the provider issued go in
the instance .env, keyed by the provider name
upper-cased (- becomes _):
SURROGATE_SLACK_CLIENT_ID=1234567890.abcdef
SURROGATE_SLACK_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
A provider with no creds still loads, but stays hidden from the connections page until it can actually run — so you never show a user a “Connect” button that would 500.
4. restart and connect
sudo systemctl restart arizuko_<instance>
“Connect Slack” now appears in
/dash/me/connections. A user clicks it, approves at
Slack, and lands back with a live token written to the
secrets table under secret_key
(SLACK_TOKEN). The broker refreshes it when it
nears expiry; if the refresh token is revoked, the agent gets a
clear “reconnect” error instead of a silent failure.
give agents a tool backed by it
The stored token reads like any other secret. Point an
[[connector]] REST provider or an
MCP connector at secret_key and the agent gets a
tool that calls the service as the connected user — no
credential ever enters the container. See
reference/mcp for the tool
surface and grants for
gating which folders may call it.
checking it works
sudo journalctl -u arizuko_<instance> --since "1 min ago" \
| grep -i "surrogate provider"
At boot dashd logs each loaded provider and whether it’s
connectable (has creds). A missing provider means the
.toml didn’t parse or landed in the wrong
directory; connectable=false means the
SURROGATE_<NAME>_CLIENT_* vars aren’t set.
go deeper
- concepts/secrets — where the token lives and who can read it.
- reference/env — the
SURROGATE_*andWEB_HOSTvars. - how-to: webhooks — the other way an outside service reaches an agent.