Configuration: environment and Keycloak client

preview

Every environment variable Agent Outlook reads, the confidential OIDC client it needs, and the manifest URL that must match both.

Configuration

For self-hosting Agent Outlook. If you are only using an instance somebody else runs, you need none of this — start at Install.

Environment variables

VariablePurpose
KEYCLOAK_URLBase URL of the Keycloak instance. The issuer is {KEYCLOAK_URL}/realms/{KEYCLOAK_REALM}.
KEYCLOAK_REALMRealm name. Default agentics.
KEYCLOAK_CLIENT_IDConfidential client id. Default agentics-outlook.
KEYCLOAK_CLIENT_SECRETThe client secret. Required — the app cannot complete a sign-in without it.
PUBLIC_BASE_URLThis app's own public HTTPS URL. Used both as the OIDC redirect base and to render manifest.xml.
USER_DATA_DIRRoot of the file-backed session store. /data in the container.
AGENTICS_BASE_URLBase URL of the main agentics.dk site — projects, stakeholders, interactions.
SHARE_BASE_URLBase URL of share.agentics.dk — Agent Share inboxes.
OUTLOOK_PROJECT_MODE"true" turns on the project step. Any other value, including unset, leaves it off.

OUTLOOK_PROJECT_MODE is compared against the exact string "true". 1, yes and True all read as off.

PUBLIC_BASE_URL has to match three things

This is the variable that breaks installs, because it appears in three places that must agree:

  1. The manifestscripts/build-manifest.js renders public/manifest.xml from it, and that is the URL Outlook loads the pane from.
  2. The OIDC redirect URI{PUBLIC_BASE_URL}/auth/callback, which must be registered on the Keycloak client verbatim.
  3. The origin the browser is actually on.

Change the deployment URL and you must regenerate the manifest, update the Keycloak client, and re-sideload. public/manifest.xml is deliberately not checked in, precisely because it is per-environment.

Persist /data

USER_DATA_DIR holds the session store: the mapping from each opaque handle to its tokens. Mount it on a volume.

If it is ephemeral, every restart silently signs everybody out — the handle in each mailbox's roamingSettings survives, but the server no longer knows what it refers to, so the pane asks people to connect again after every deploy.

The Keycloak client

Agent Outlook needs a confidential OIDC client in the realm:

  • Client id: agentics-outlook
  • Standard flow: enabled
  • Direct access grants: disabled
  • Service accounts: disabled
  • Public client: no — it has a secret
  • Redirect URI: {PUBLIC_BASE_URL}/auth/callback, exactly one

Confidential rather than public PKCE because the app has a real server. Standard flow only, because nothing else is used: there is no password grant and no service account. The add-in forwards the signed-in user's own access token to both backends, so a service account would be authorised as nobody and every call would be rejected.

Create it with kcadm.sh:

kcadm.sh create clients -r agentics \
  -s clientId=agentics-outlook \
  -s enabled=true \
  -s protocol=openid-connect \
  -s publicClient=false \
  -s standardFlowEnabled=true \
  -s directAccessGrantsEnabled=false \
  -s serviceAccountsEnabled=false \
  -s 'redirectUris=["https://outlook.example.com/auth/callback"]'

Then read the generated secret from the Credentials tab (or kcadm.sh get clients/<id>/client-secret -r agentics) and set it as KEYCLOAK_CLIENT_SECRET. Never commit it.

Hosting requirements

These are not preferences — Outlook enforces them:

  • HTTPS with a valid certificate, publicly reachable. Outlook will not load a task pane from anything else.

  • A frame-ancestors policy that covers your Outlook hosts, and no X-Frame-Options header. In Outlook on the web the pane is a cross-origin iframe; on desktop it is a WebView, which is why an add-in can appear to work on desktop while being completely broken on the web.

    Microsoft is mid-migration of Microsoft 365 onto cloud.microsoft, so the list must cover both the legacy *.office.com / *.office365.com origins and the newer *.cloud.microsoft / *.microsoft365.com ones. Append; never replace. Tenants on the old origins have not moved.

  • script-src must allow https://appsforoffice.microsoft.comoffice.js is loaded from Microsoft's CDN and is not bundled.

The shipped next.config.ts already sets all of this. It is listed here because it is what to check first if the pane goes blank behind a reverse proxy that adds its own headers.

Deployment

Production is a Coolify git-build: Coolify clones the repository and builds the Dockerfile itself. There is deliberately no registry image in the production path, so a registry outage cannot block a deploy that never reads from it.