Documentation
Add Dialogues auth
Pick your integration mode, then implement Grant Access
Updated July 4, 2026
Add Dialogues auth to your app
This tutorial implements the client facet of your Connector — the auth path software uses to connect. Owner-mediated connectors (file upload, in-UI entry) never need this tutorial.
Grant Access (Attach Dialogues) lets a signed-in user approve your connector and gives your client a plugin attach token plus resource_id for app_ingest.
Start with Integration Modes below. That table is the distinguisher: it tells you whether you follow the PKCE path (browser extension, public web, mobile without a trusted backend) or the client secret path (web or mobile app with a server that can hold credentials).
Prerequisite: Register a Connector (scopes, source declarations, redirects, and the matching client_auth_mode).
Prerequisites
- Tutorial 1 complete — app registered with the
client_auth_modethat matches your row in Integration Modes. - Your client can open a browser window or tab for user login and consent (all modes).
Integration Modes
Find your integration. Follow the Auth path column for the rest of this tutorial.
| Integration mode | Typical examples | client_auth_mode | Auth path | Where token exchange runs |
|---|---|---|---|---|
| Browser extension | Chrome / Chromium MV3 plugin (e.g. browser-history-plugin) | public_pkce | PKCE | In the extension — no client_secret in the shipped bundle |
| Web app with backend | Next.js + API routes, Rails/Django server, any app with a trusted server | client_secret_required | Client secret | On your server only — issue cas_* in App Sheaf; never in frontend code |
| Web SPA (no backend) | React/Vue SPA, static site with Attach in the browser | public_pkce | PKCE | In the browser — same PKCE flow as extensions |
| Mobile app (no backend) | iOS/Android app without a secure server for secrets | public_pkce | PKCE | In the app — PKCE in the mobile client |
| Mobile app with backend | App + your API that holds the Dialogues secret | client_secret_required | Client secret | On your backend after the user completes /connect in the app |
| Local dev only | Quick prototypes | legacy_none | Dev / legacy | Not for production — set public_pkce or client_secret_required before ship |
Checkpoint: You know your row. PKCE rows → Sections B–E. Client secret rows → Section F.
Concepts (do not confuse these)
| Name | What it is | Where it lives |
|---|---|---|
public_pkce | Registry policy: this app_id is a public OAuth client | App metadata (Sheaf or API) |
client_secret_required | Registry policy: exchange must prove possession of cas_* | Secret only on your server |
| PKCE verifier / challenge | Proof for this attach session | Generated in the client when using PKCE |
erk_* | Optional key for extension redirect registration only | Operator-issued; unrelated to PKCE |
Section B — Generate PKCE (PKCE path only)
Skip to Section F if your Integration Mode uses client secret.
- Generate a random
code_verifier(43–128 characters). - Compute
code_challenge= BASE64URL(SHA256(verifier)) and setcode_challenge_method=S256. - Create a new verifier/challenge pair for every attach attempt (do not reuse).
Reference: lib/pkce.js in browser-history-plugin
Checkpoint: Client holds the verifier locally; challenge is ready for /connect.
Section C — Start Grant Access
All modes start here in the user’s browser. PKCE modes must include challenge parameters; client-secret modes may omit PKCE on /connect (exchange still uses the secret on the server).
Build GET /connect with query parameters:
app_id— your registered idredirect_uri— must match an allowed redirect for this appcode_challengeandcode_challenge_method=S256— required forpublic_pkcescopes— subset of yourallowed_scopes(e.g.activity:write)source_id— optional; often the primary ingest source you will usestate— random string you verify on callbackforce_login=1— optional; require fresh login
Example (browser extension, PKCE):
https://cp.logu3s.com/connect?app_id=my-extension&redirect_uri=https%3A%2F%2F<extension-id>.chromiumapp.org%2F&code_challenge=...&code_challenge_method=S256&scopes=activity%3Awrite&source_id=browser_visits&state=grant-abc&force_login=1- Open the URL; user signs in via Dialogues (Keycloak) if needed.
- User sees the consent screen listing your app name and requested access.
- On approve, the browser redirects to
redirect_uriwith a one-time?code=...(and usuallystate).
Reference: lib/grantAccess.js → buildGrantConnectUrl in browser-history-plugin
Checkpoint: You received code on your redirect URI (or your backend received it via redirect to your web callback).
Section D — Exchange the code (PKCE path)
curl -sS -X POST "https://cp.logu3s.com/connect/exchange" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"code": "ONE_TIME_CODE_FROM_REDIRECT",
"app_id": "my-extension",
"code_verifier": "YOUR_CODE_VERIFIER"
}'POST /connect/exchangewithcode,app_id, andcode_verifier.- Do not send
client_secretwhenclient_auth_modeispublic_pkce. - Parse response:
plugin_attach_token,resource_id, optionalmcp_access_token. - Store tokens securely (
chrome.storage, mobile secure storage, etc.).
Reference: lib/grantAccess.js → exchangeGrantCode in browser-history-plugin
Checkpoint: Attach succeeded; token and resource_id persisted.
Section E — Operate and recover (all modes)
- 401 Unauthorized — token expired or invalid. Clear stored credentials and re-run attach + exchange for your path.
- 403 Forbidden — user revoked access in Topos → Sharing → Connected apps. Clear credentials; prompt re-attach.
- Code already used or expired — codes are single-use and short-lived. Start a new attach (new PKCE pair for public clients).
Checkpoint: Error handling is implemented in your UI.
Section F — Exchange with client secret (server path)
For Web app with backend and Mobile app with backend in Integration Modes.
- User completes
GET /connectin the browser; your redirect lands on your frontend or deep link with?code=.... - Send the
codeto your backend (never exposecas_*to the browser or mobile binary). - Your server calls exchange:
curl -sS -X POST "https://cp.logu3s.com/connect/exchange" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"code": "ONE_TIME_CODE_FROM_REDIRECT",
"app_id": "my-web-app",
"client_secret": "cas_YOUR_SECRET_FROM_APP_SHEAF"
}'- Store
plugin_attach_tokenandresource_idin your server session or database, scoped to the signed-in user. - Your frontend calls your API for ingest; your API uses the stored token on
app_ingest.
Checkpoint: Exchange ran only on the server; no Dialogues secret in client-side code.
Verify with the reference smoke script (PKCE / extension)
From a clone of browser-history-plugin:
CONTROL_PLANE_URL=https://cp.logu3s.com APP_ID=browser-history-plugin ./scripts/smoke-test-connect.shIf this passes for browser-history-plugin, your Dialogues API host and PKCE contract match production.
Checkpoint: Attach and token exchange work for your integration mode; implement app_ingest and Connected apps in your client.