Desktop account connectors
Company OS Desktop's Connectors → Accounts view is for linking an account. Select Outlook, Gmail, or another supported account app, press Connect, approve access with the provider in the system browser, and return to the account shown in Company OS. The flow does not open localhost Company Console. Custom MCP servers and additional integration setup live in Advanced.
Selection checks availability through a read-only RPC. Missing Company OS provider registration appears as a short installation-availability message; administrator details are secondary. Check again never starts OAuth. A configured installation opens the provider's approval URL directly and shows native progress, cancellation, expiry, and retry. Saved email/account identity is displayed separately from permissions and diagnostics.
Company OS owns state, PKCE, principal/company binding, code exchange, scope validation, encrypted credentials, refresh, and receipts. Tokens are never placed in UI projections, tool arguments, or provider approval query strings. Provider OAuth is separate from authentication to Company OS's MCP server. Company OS's already-authenticated agents do not require an additional MCP-host OAuth authorization server for this flow.
One-time provider registration
For a self-hosted installation, register an OAuth app for Company OS. A model subscription or an installed coding-agent plugin does not supply this app's provider credentials. Configure the registrations once for the installation; customers only approve their own account access. The complete secret-free template is config/company-os-oauth.env.example.
For Google, create a Desktop app OAuth client in Google Cloud, configure the consent screen and its permitted users, and enable the APIs the company will use. Set these values on the Company OS server:
HSM_OAUTH_GOOGLE_CLIENT_ID
HSM_OAUTH_GOOGLE_CLIENT_SECRETThe desktop uses http://127.0.0.1:<port>/connector/callback. Desktop OAuth clients support a loopback callback; a web-client registration must match the callback actually used. To reserve a specific registered port, set HSM_OAUTH_GOOGLE_REDIRECT_URI to the complete loopback URI. The native app binds that port and reports an error if it is occupied.
For Microsoft, register the app in Microsoft Entra with a native/public-client loopback redirect accepted by that registration:
HSM_OAUTH_MICROSOFT_CLIENT_ID
HSM_OAUTH_MICROSOFT_REDIRECT_URIThe configured URI must use the exact loopback form above. An optional HSM_OAUTH_MICROSOFT_TENANT_ID selects common, organizations, consumers, or a tenant UUID. Confidential clients can also supply HSM_OAUTH_MICROSOFT_CLIENT_SECRET. Provider registration and organizational consent policies still apply.
The existing company credential vault must be configured. Keep credentials in the server's protected configuration; do not put secrets in connector metadata or browser URLs. Restart the Company OS server after changing its environment. Connectors keeps installation availability in the desktop. Open Administrator details for administrator instructions and the missing configuration names. No browser opens when readiness is false.
GitHub, Slack, Notion, and Stripe
| Provider | Server configuration | Registered callback | Permissions |
|---|---|---|---|
| GitHub OAuth App | HSM_OAUTH_GITHUB_CLIENT_ID, HSM_OAUTH_GITHUB_CLIENT_SECRET, HSM_OAUTH_GITHUB_REDIRECT_URI | http://127.0.0.1:43821/connector/callback | read:user; profile and public repository reads |
| Slack app | HSM_OAUTH_SLACK_CLIENT_ID, HSM_OAUTH_SLACK_CLIENT_SECRET | {public-origin}/api/company/connectors/oauth/callback/slack | Bot channels:read,channels:history; public channels shared with the app |
| Notion public integration | HSM_OAUTH_NOTION_CLIENT_ID, HSM_OAUTH_NOTION_CLIENT_SECRET | {public-origin}/api/company/connectors/oauth/callback/notion | Configure Read content capability; users select shared pages. No OAuth scope strings |
| Stripe Extension | HSM_OAUTH_STRIPE_CLIENT_ID, HSM_OAUTH_STRIPE_CLIENT_SECRET, HSM_OAUTH_STRIPE_INTEGRATION_TYPE=extension | {public-origin}/api/company/connectors/oauth/callback/stripe | read_only; ordinary Stripe Platform registrations do not support this scope |
HSM_OAUTH_PUBLIC_BASE_URL must be the deployed HTTPS origin of the same Company OS API configured in the desktop. It cannot be a separate domain that forwards unverified codes or a localhost URL. Configure the exact callback at each provider. No public callback address is configured on the current installation.
GitHub uses PKCE plus its app secret. Slack uses bot-installation credentials, checks ok on API responses, and never substitutes an installer user token. Notion uses JSON plus HTTP Basic and a pinned Notion-Version. Nullable Notion refresh tokens are accepted; documented long-lived tokens have no invented expiry. Refresh responses retain the previously confirmed scopes when omitted.
Stripe now returns a connected account ID rather than necessarily returning an OAuth access token. The platform credential remains encrypted in the company vault, and native requests bind Stripe-Account to the verified acct_… identity. The runtime restricts native calls to the reviewed origin, GET paths, and scopes. A generic OpenAPI connection cannot borrow that credential. A Stripe restricted API key is a separate credential flow; this registration is specifically Connect.
BaseLayer uses its API key. Generic OpenAPI and custom MCP servers retain their configured credential/trust flow in Advanced. Automatic OAuth discovery for an arbitrary MCP server is not implemented by these provider adapters.
Official references: GitHub, Slack, Notion, and Stripe.
Account apps and agent access
One reviewed identity list now supplies OAuth mappings and account catalog entries. A partially seeded registry no longer hides Outlook or the other supported Google apps. Company overrides and disabled connectors take precedence over platform defaults.
| Account app | Included native read tools |
|---|---|
| Outlook / Microsoft 365 Mail | Search/list messages; read a message |
| Gmail / Google Workspace mail | Search/list messages; read a message |
| Google Drive | Search files; read details; export supported document text |
| Google Calendar | List calendars; read events |
| Google Sheets | Read spreadsheet details and cells |
| Google Docs | Read a document |
| Google Slides | Read a presentation |
| Google Analytics | List accounts and properties |
| YouTube | Read channel and video details |
| GitHub | Read profile; list public repositories |
| Slack | List shared public channels; read channel history |
| Notion | Read shared page details and blocks |
| Stripe | Read connected-account balance and payment records |
These are 24 read-only tools. They do not send email, modify documents, delete items, or publish content. Scopes match the reviewed read operations. Google Ads remains a sign-in-only integration here: its separately approved developer token and Executor integration are still required; no native Ads tools are advertised or installed by OAuth.
The callback saves credentials and installs the app's reviewed tools in the same governed database transaction. A conflicting custom source/tool is not overwritten. Reconnect updates account choices rather than duplicating tools. It invalidates old refresh claims; the broker reads client and refresh-token configuration from the same claimed credential version. Final activation rechecks connector availability after provider I/O.
Agents discover these operations through the normal company tool catalog. Each schema lists the connected account identities and requires account_id. The admitted HTTP adapter validates company, provider, connector, state, scopes, registry availability, and permitted HTTPS origin before retrieving a token from the canonical broker. Selection stays in execution arguments and receipts and is stripped from the provider request. Generic OpenAPI fallback cannot silently choose a native OAuth account.
Connection health
A successful identity lookup alone is not verified service access. Outlook, Gmail, Drive, Calendar, Analytics, YouTube, GitHub, Slack, and Stripe perform a minimal data API read before a checked connection is recorded. Probe content is not persisted. Sheets, Docs, Slides, and Notion require a caller-selected document/page ID, so their saved sign-in remains access-unverified until a governed read succeeds.
Successful reads update access evidence; 401 requests reconnect, and 403 records a permission error. Evidence updates are fenced against newer credentials. A missing individual document (404) is not treated as revoked account authorization. A settled run or connected badge does not establish business-output quality.
Runtime contract
Routes are scoped under /api/company/companies/:company_id/connectors/oauth/:connector_key:
GET: read-only readiness without secrets or a session.POST /start: prepare a company/principal-bound provider approval URL.POST /complete: verify the callback, identity, scopes and supported access probe; revalidate authority and atomically save the account and reviewed tools.POST /cancel: cancel a pending session; claimed/saved sessions cannot be falsely reported as cancelled.
Sessions bind company, principal, connector, nonce, registered callback, and PKCE verifier where supported for ten minutes. For HTTPS providers, the public GET /api/company/connectors/oauth/callback/:provider only deposits one state-bound result in the pending session. It performs no token exchange or vault write. Authenticated desktop polling submits only session ID and state to /complete, which checks principal authority again before exchanging the code and saving the account. The browser receives a static, no-store result with no-referrer policy. Public callbacks do not carry company access tokens. Invalid callbacks cannot consume another session. Successful completion is replayable under the same binding without exchanging the provider code again. Refusals and successful writes retain governance receipts. Provider calls use the existing admitted integration executor and terminal settlement; no direct tool-execution bypass was added.
Pending sessions and the bounded completion cache are process-local. A server restart requires starting sign-in again; replicas must keep one handshake on the same instance. Saved accounts remain in the company vault.
Deployment and evidence
The September 7 provisioning follow-up created a Company OS native/public Microsoft app in Gestion Velora's tenant and saved its client ID, tenant ID, and registered loopback callback in the ignored, mode-0600 server .env. The live Microsoft readiness endpoint now returns supported=true, ready=true, and the installed desktop presents Connect for Outlook. This installation uses a single-tenant registration. Its delegated permission save and account consent remain pending explicit approval required by automatic approval review. No live mailbox read or token refresh has been verified.
A dedicated Google Cloud project, company-os-velora, was created. Google consent setup and the nine-service API activation form are prepared. After automatic approval review required explicit approval of the testing audience and API activation, the operator chose Leave Google pending. No Google OAuth client has been created, no connector APIs were enabled by this follow-up, and Google readiness remains false.
These provisioning results do not constitute live provider consent or service access. The installed artifact and exact checks are recorded in docs/company-os/DESKTOP_UX_VERIFICATION_2026-09-07.md.
September 7 adapter extension (source verification)
Added GitHub, Slack, Notion, and Stripe protocol support and desktop Accounts presentation. Added migration 20260907010000__company_account_oauth_providers.sql, which upgrades only the four platform catalog rows; it preserves company overrides. This migration has not been applied by this follow-up, and the new binaries have not been installed or restarted.
python3 scripts/company-os-oauth-contract-tests.py: 27 tests passed, including production callback handlers, pure provider contracts, and native request construction. The new catalog test failed against the saved prior catalog before passing against the implementation.bash scripts/cargo-reliable.sh check --lib: passed.- Desktop engine sign-in suite: 19 tests passed, including HTTPS RPC fixtures.
- Desktop presentation harness: 17 tests passed; UI metadata typecheck passed.
- Full root
test --lib connector_oauth: refused by the repository disk guard (about 12 GiB available; 24 GiB required); no full linked Rust suite passed. - Provider registrations, consent, refresh, and live API reads remain unverified.
GitHub's Company OS registration form is prepared with homepage https://github.com/PermutationResearch/HSM-II, exact loopback callback http://127.0.0.1:43821/connector/callback, access-token expiry enabled, and wildcard redirects/device flow disabled. Automatic approval review rejected submission because exact app/callback approval was required. No GitHub app or client secret was created. Google remains pending from the earlier setup; Slack, Notion, and Stripe additionally need the public API origin and provider application registration.
September 7 continuation: builds and live installation check
Both complete development binaries built successfully, with no provider registration or database mutation:
- Desktop:
RUSTC_WRAPPER= CARGO_PROFILE_DEV_DEBUG=0 cargo build -p company-os-desktop --offlinepassed in 7.36 seconds. Unsigned build SHA-256:81d2c8227c24fe91fd858ee814e1fd7f1272f2d584e036d8c7c9f8ca4b4b5d41. - API:
RUSTC_WRAPPER= bash scripts/cargo-reliable.sh build --bin hsm_console --offline --config 'profile.dev.package.hyper-stigmergy.debug=0'passed in 2m44s, with the existing unusedresolve_document_brand_profilewarning. SHA-256:65d800d8930ef6837d5b1376525ffcb93f099c7f7b96c5de8942a0fdf91a33d0. - Collected final library-check and focused test results: library check passed; backend contracts 27/27; desktop engine sign-in 19/19. The previously run desktop presentation harness passed 17/17. These are not live OAuth tests.
- Packaged
/private/tmp/company-os-auth-stage/Company OS.appusing the existing installed icon after the standard installer reportedInvalid Iconset. Ad-hoc signing and strict signature verification passed.
The live API on port 3847 returned HTTP 200 for health and the connector catalog, but HTTP 404 for each of the Microsoft, Google, GitHub, Slack, Notion, and Stripe direct sign-in setup routes. This observation supersedes the earlier Microsoft readiness observation for the currently running process. It does not invalidate the saved Microsoft registration. The running binary was ~/.company-os-desktop/runtime-target/debug/hsm_console; it was not restarted.
Read-only database inspection through the configured migration login and its existing hsm_company_migration_owner role confirmed that the four platform catalog entries still use bearer authentication. Migration 20260907010000 remains unapplied. The published-migration guard in crates/company-os-core/src/migration_provenance.rs requires publication or authorization of the specific unpublished version before applying it. No other pending migration was applied or allowlisted.
The active company had zero running agent runs. Across the local database, 57 rows were still marked running; the newest started August 28 and none had an unexpired signed run grant. This is evidence of stale ledger state, not evidence that the active desktop has no unsaved UI state.
Installation stopped before replacing either binary because Company OS became active during staging. Automatic approval review rejected a subsequent request to quit it, citing possible unsaved UI state and lack of explicit authorization to close the app. The signed bundle and protected-backup installation script /private/tmp/company-os-auth-install.py are prepared, but the update is not installed. Any later installation must first check for newer shared-tree builds, an active app, and live work again.
Remaining operator inputs: permission to close/reopen the desktop and update its local runtime; exact unpublished catalog-migration authorization or normal publication; approval of the prepared GitHub registration; and the deployed HTTPS API origin for Slack, Notion, and Stripe. Google remains pending under the earlier operator choice. No account consent, live provider data read, or refresh was completed in this continuation.