Skip to main content
Two connectors, both type: oauth_pkce, share this page: Microsoft Personal (microsoft) and Microsoft Work or School (microsoft_work). Catalog entry: src/gaia/connectors/catalog/microsoft.py
GAIA connects to Microsoft accounts through two separate connectors — you can have a personal mailbox and a work/school mailbox connected at the same time, each with its own client credentials and its own grant list: The authority each connector signs in against is spec data, not an environment variable — every connect, refresh, and daemon restart resolves it the same way, regardless of what environment the process happens to be running in. There are two ways to sign in to either connector:
  • Browser (PKCE) — the default. Needs an Azure App registration you create once (below). Best when you control your own app registration.
  • Device codegaia connectors connect <id> --device. You enter a short code at a Microsoft URL; no loopback redirect. This is the zero-setup path when a pre-registered public client ID is supplied via env var. See Device-code sign-in below.

What you’ll need (browser flow)

Microsoft requires every app — including GAIA running locally — to identify itself with an App registration that you create once in the Azure portal, per connector (personal and work/school each need their own client credentials; do not reuse one registration’s client ID for both). For a single-developer machine each registration takes a few minutes and is free. You will register an app and paste a single value into the GAIA Agent UI: an Application (client) ID. Unlike Google, the standard desktop flow needs no client secret — Microsoft forbids secrets for public (desktop) clients. GAIA stores the Client ID encrypted in your OS keyring, per connector.

Step 1 — Register an app in Azure

  1. Go to the Azure portal → App registrations.
  2. Click New registration.
  3. Name: GAIA (or whatever you like — include “Personal” or “Work” if you’re registering one for each connector).
  4. Supported account types — pick the audience matching the connector you’re registering for:
    • Microsoft Personal (microsoft): choose Personal Microsoft accounts only (or the combined “any organizational directory and personal Microsoft accounts” audience, which also authenticates fine against the consumers authority this connector uses).
    • Microsoft Work or School (microsoft_work): choose an organizational-directory audience — Accounts in this organizational directory only for a single tenant, or Accounts in any organizational directory for multi-tenant.
  5. Click Register. The Overview page shows the Application (client) ID — copy it for Step 3. If you registered a single-tenant work/school app, also copy the Directory (tenant) ID shown on the same page — you’ll need it in Step 3 too.

Step 2 — Add the loopback redirect URI

GAIA runs a temporary loopback web server on 127.0.0.1 to receive the OAuth callback, so it needs a localhost redirect URI of the public-client type.
  1. In your app, go to Authentication → Add a platform.
  2. Pick Mobile and desktop applications.
  3. Check (or add) the redirect URI http://localhost.
  4. Click Configure / Save.
You do not need to create a client secret for the standard flow.

Step 3 — Paste the Client ID into GAIA

  1. Launch the Agent UI: gaia chat --ui.
  2. Click Settings (gear) → Connections.
  3. Click the Microsoft Personal or Microsoft Work or School tile to expand it, matching the account type you registered in Step 1.
  4. Paste the Application (client) ID. Leave Client Secret blank. On Microsoft Work or School, optionally paste the Directory (tenant) ID into the field of the same name if you registered a single-tenant app — this narrows sign-in to that one organization and is what lets a background daemon (with no environment variables set) refresh correctly without depending on the multi-tenant organizations default.
  5. Click Save & Connect.
Already past first-time setup (client came from env vars, or you need to rotate it)? Expand the tile’s collapsible OAuth client section — it shows which client GAIA currently resolves (saved / environment / none) and accepts a replacement at any time. Save client persists to the OS keyring without starting a sign-in; saved credentials take precedence over the environment variable, exactly like gaia connectors configure <id>. GAIA will:
  1. Store the Client ID (and Directory tenant ID, if set) in your OS keyring (macOS Keychain on Mac, gnome-keyring/kwallet on Linux, Credential Locker on Windows).
  2. Open Microsoft’s consent screen in your default browser.
  3. Receive the callback on a temporary loopback server.
  4. Exchange the auth code for a refresh token (also stored in the keyring). The refresh token is issued because GAIA requests the offline_access scope.
The tile flips to Connected as [email protected] (or your work/school address) once the flow completes. Connecting one connector never affects the other — you can have both a personal and a work/school mailbox connected at the same time.

Step 4 — Per-agent grants

The connect panel shows “Grant access to these agents when you connect” — a default-on checkbox for every installed agent that declares Microsoft access. Checked agents are granted their declared Graph scopes automatically the moment the OAuth flow completes, so a fresh connect needs no follow-up command. Uncheck an agent before connecting to withhold its grant. You can adjust or revoke grants at any time from the same tile’s Per-agent grants section, or via the CLI:
The scopes a connection can request are identical for both connectors (they share one scope list in the catalog spec) and are listed at src/gaia/connectors/catalog/microsoft.py:

Device-code sign-in

The device-code flow skips the Azure app registration and the loopback redirect entirely — useful for headless machines, or when a public client ID is already available (e.g. an org-published GAIA app registration). In the Agent UI: with a client ID configured (env or the OAuth-client form), each Microsoft tile in Settings → Connections shows a Sign in with a code button next to Connect. Click it, then enter the displayed code at the Microsoft URL — the tile flips to Connected automatically when you finish. No browser redirect, no app registration. From the CLI:
GAIA prints a short code and a URL (https://microsoft.com/devicelogin). Open the URL on any device, enter the code, and approve. GAIA polls until sign-in completes, then stores the refresh token in your OS keyring — identical to the browser flow from that point on. Grant an agent afterward:
The client ID used for device code must be a public client with the audience matching the connector (personal-only for microsoft, an organizational directory for microsoft_work) and device-code flow allowed. GAIA does not ship a client ID — supply your own via GAIA_MICROSOFT_CLIENT_ID / GAIA_MICROSOFT_WORK_CLIENT_ID, or use the browser flow with your own app registration.

Common issues

AADSTS50011: redirect URI mismatch

The redirect URI in your app registration doesn’t include http://localhost, or you added it under the wrong platform. Re-check Step 2 — it must be a Mobile and desktop applications platform redirect, not Web.

AADSTS700016 / unauthorized_client

The Client ID is wrong, or the app’s audience doesn’t match the connector you used it with. Confirm you copied the Application (client) ID from the Overview page and registered the audience described in Step 1 — a personal-only app for microsoft, an organizational-directory app for microsoft_work.

AADSTS9002346 (device code)

The app registration is personal-account-only, but you connected via microsoft_work. Reconnect using microsoft instead — see Device-code sign-in. You declined consent, or the agent is requesting a scope you didn’t approve. Reconnect from the UI and accept the consent prompt; then grant the agent the scope (Step 4).

Token endpoint returned no refresh_token

GAIA always requests offline_access, which is what makes Microsoft issue a refresh token. If you see this, disconnect and reconnect from the UI to restart the flow with the full default scope set.

Revoking access

Two places — both work, per connector:
  • From GAIA: Settings → Connections → the connector tile → Disconnect. Removes that connector’s refresh token from the keyring; the next API call for it errors with NOT_CONNECTED. The other Microsoft connector (if connected) is unaffected.
  • From Microsoft: personal accounts at account.live.com/consent/Manage; work/school accounts at myapps.microsoft.com → find your app → Remove these permissions.

See also