The connect flow — one link that returns an organization key and an API token
Mirrored from
iblai/vibe·docs/connect-flow.md. This page is generated — edit it in the repository, not here.
Status: specification. The client half (a script and a skill) ships in this
repo; the hosted half is one page on login.iblai.app that the ibl.ai web team
implements from this document. Until it exists, the client falls back to the
manual path (/iblai-vibe-ops-init's questions), so nothing breaks.
The problem it removes
Today a builder must: open ibl.ai/join, sign up, find their organization key
on login.iblai.app/me, open os.ibl.ai, switch to Admin, go to
Integrations → APIs → Add API, copy a secret, paste it into a chat, and never
paste it anywhere else. Every one of those steps has a way to go wrong, and
the token passes through the conversation.
With the connect flow the agent says "opening your browser to connect your ibl.ai organization", the builder signs in (or creates an organization), clicks Connect, and the agent already has what it needs — the token never appears in the chat.
The contract
1. The client opens a URL
https://login.iblai.app/connect
?callback=http://127.0.0.1:<port>/callback
&state=<random 32+ chars>
&name=<app name, e.g. "my-app on Miguel's laptop">
[&org=<org key, to preselect>]
callback— a loopback URL the client is listening on (127.0.0.1orlocalhostonly; the page must refuse anything else). Omitted → manual mode (§4).state— echoed back unchanged; the client rejects a callback whosestatedoes not match (CSRF guard, exactly as OAuth loopback flows do).name— the label the minted token gets (Platform API Token→ Name), so the user can recognize and revoke it later under Integrations → APIs.org— optional preselection when the client already knows the key.
2. The page
Hosted on login.iblai.app (that is where the session lives; ibl.ai/connect
may 302 here). Behavior:
Not signed in → the normal login flow, with
joinoffered (ibl.ai/joincreates the account and an organization), returning to/connectwith the same query string afterwards.Signed in → show the account and the organizations the user belongs to (the same data
/merenders).mainis listed but disabled with the note "shared organization — create your own" and a Create organization button (→ibl.ai/join, then back).The user picks an organization and clicks Connect (button text: "Connect
<org name>to<name>"). The page mints a Platform API Token with the session'sdm_token:POST https://api.iblai.app/dm/api/core/platform/api-tokens/ Authorization: Token <dm_token> { "username": "<username>", "name": "<name>", "key": "", "platform_key": "<org>", "created": "<now>", "expires": "" }(platform_key, name)must be unique — on a collision, append a short suffix (my-app-2) rather than failing.Callback mode → redirect the browser to
callback?state=…&code=<one-time code>; the client exchanges the code (§3). Show "Connected — you can close this tab". Manual mode → show the values with copy buttons (§4).
Also add the loopback origin the app will use to the organization's allowed
redirect origins when the client passes &origin=http://localhost:3000 —
this is the step new apps most often miss (sign-in never returns).
3. The code exchange (why not the token in the URL)
The redirect carries a one-time code, not the secret, so the secret never lands in browser history or a proxy log:
POST https://login.iblai.app/connect/exchange
Content-Type: application/json
{ "code": "<code>", "state": "<state>" }
200 { "domain": "iblai.app", "org": "<org key>", "org_name": "<display name>",
"username": "<username>", "token": "<platform api token>", "expires": "" }
Codes expire in 60 seconds and are valid once. A wrong state is a 400.
(For a first version, redirecting straight to
callback?state=…&org=…&username=…&token=…&domain=… is acceptable — the
listener is on the machine the user is sitting at — but the exchange is the
target.)
4. Manual mode (no loopback: SSH, containers, a remote agent)
https://login.iblai.app/connect with no callback: after Connect the
page shows
DOMAIN=iblai.app
PLATFORM=<org key>
TOKEN=<platform api token> (shown once)
IBLAI_USERNAME=<username>
as a copyable block, plus the one line to run:
npx -y @iblai/connect --paste (or simply "paste this into the chat" — the
skill accepts it and writes the files without echoing the token).
The client (in this repo)
skills/start/iblai-vibe-connect/scripts/connect.mjs (Node 18+, no dependencies):
- Starts an HTTP listener on
127.0.0.1:<random port>with a 5-minute timeout. - Opens
https://login.iblai.app/connect?callback=…&state=…&name=…[&origin=…]in the default browser (open/xdg-open/start); prints the URL too (remote sessions copy it). - On the callback: verifies
state, exchangescode(or reads the fields), verifies the token withGET /dm/api/core/token/verify/, and writesiblai.env:DOMAIN,PLATFORM,TOKEN,IBLAI_USERNAME.env:IBLAI_ORG,IBLAI_USERNAME,IBLAI_API_KEY.env.local(when a Next.js app is present):NEXT_PUBLIC_MAIN_TENANT_KEY,IBLAI_API_KEYcreating each from its.examplewhen missing, updating lines in place otherwise, and making sure all three are gitignored.
- Prints
connected: <org name> (<org key>) as <username> · token ****ab12and exits. The token is never printed. --pastereads the manual-mode block from stdin instead of opening a browser.
/iblai-vibe-connect is the skill that runs it and is what /iblai-vibe-start,
/iblai-vibe-ops-init, and /iblai-api-login call first; if the script exits
with HOSTED_PAGE_UNAVAILABLE (a 404 on /connect), they fall back to their
manual questions.
Security notes for the web team
- Loopback only for
callback; reject other hosts and non-http(s)schemes. - Bind the code to
stateand to the session that created it; single use; 60 s. - Mint with the minimal scope the platform offers for a token that will be used from a builder's server (Owner today; a narrower "app" scope when available).
- Log the mint (who, which org, which name) — the same audit as Add API.
- Never put the token in a
GETURL when the exchange endpoint exists.
What changes for users
/iblai-vibe-start → "Connect your ibl.ai organization" → browser → click →
back in the chat with the organization named and the files written. The
platform lifecycle doc's steps 3–4 become one step.