Get your dream built 10x faster

How to integrate Outlook Microsoft Graph with OpenClaw

We build custom applications 5x faster and cheaper 🚀

Book a Free Consultation
4.9
Clutch rating 🌟
600+
Happy partners
17+
Countries served
190+
Team members
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Stuck on an error? Book a 30-minute call with an engineer and get a direct fix + next steps. No pressure, no commitment.

How to integrate Outlook Microsoft Graph with OpenClaw

You can integrate Outlook (Microsoft Graph) with OpenClaw by registering an Azure AD application, choosing the right permission model (delegated vs application), implementing OAuth token exchange and secure token storage outside the agent, exposing an external webhook/receiver for Graph change notifications, and then wiring an OpenClaw skill (configured in ClawHub) to call Graph REST APIs using those credentials. Keep long‑lived state and inbound webhook endpoints outside the agent runtime, refresh tokens securely, handle subscription renewal and missed-notification reconciliation (delta queries), and debug via Graph API responses and logs.

 

High-level steps (one-sentence descriptions)

 
  • Register an app in Azure AD to get client_id and (if needed) client_secret and configure redirect URIs.
  • Choose permission model: delegated (user consent) for per-user access, or application (client credentials) for daemon/service access to many mailboxes.
  • Implement OAuth flows externally (authorization code or client credentials) and store tokens/keys in a secure secrets store or ClawHub credential fields.
  • Expose a public HTTPS endpoint (outside OpenClaw agents) to receive Graph webhook notifications and validation challenges.
  • Create and renew subscriptions via the Graph REST API; validate and handle notifications and use delta queries to reconcile missed changes.
  • Configure OpenClaw skill in ClawHub to call your external service or call Graph directly (using stored credentials) for mail/calendar operations.

 

Register an Azure AD app and set OAuth details

 
  • Register app in Azure portal > App registrations. Record client\_id and set a redirect URI that points to an external HTTPS endpoint you control (not the agent runtime).
  • Client secret or certificate: create a client secret if you will use a server-side OAuth token exchange. For daemon/service use, consider using a certificate for better security.
  • API permissions: request the minimal Graph scopes you need (examples: Mail.Read, Mail.Send, Calendars.ReadWrite, offline\_access). Decide delegated vs application permissions and ensure admin consent if required.
  • Redirect URI and CORS: ensure the redirect URI is reachable and uses HTTPS. Your external service must be able to accept OAuth callbacks.

 

Choose permission model

 
  • Delegated permissions (Authorization Code): the user signs in and the skill acts on behalf of that user. Use when acting as a specific user’s mailbox. You will get refresh tokens (offline\_access) to continue acting when user is not present.
  • Application permissions (Client Credentials): the app has privileges across mailboxes (admin consent). Use for background services or admin-level operations. There is no user context; token obtained via client credentials grant.
  • Pick based on scope and consent model: if you need cross-tenant admin consent, plan for admin workflow; if only per-user interactions, delegated is simpler for consent and security boundaries.

 

Implement OAuth and token management (external service)

 
  • Do this outside the agent runtime. Agents are transient: store client secrets and tokens in a secure vault or ClawHub credential fields (if ClawHub exposes secure fields) and never hard-code secrets in skill code.
  • Authorization code flow (server-side): redirect user to Microsoft’s authorize endpoint, handle callback at your external service, exchange code at the token endpoint for access + refresh tokens, persist tokens securely.
  • Client credentials flow: server-to-server; your external service POSTs client_id + client_secret to the token endpoint and receives an access token. This flow does not return refresh tokens.
  • Refresh / rotate tokens: implement refresh token usage and safe secret rotation. Treat refresh tokens and client secrets as highly sensitive.
  • Error handling: refresh tokens can be revoked. Detect 401/invalid\_grant, re-initiate consent flow or alert admins.

 

OAuth token exchange example (Node.js, server-side)

 
<b>//</b> Express route to handle OAuth callback and exchange code for tokens
const express = require('express');
const axios = require('axios');
const app = express();

app.get('/auth/callback', async (req, res) =&gt; {
  <b>//</b> req.query.code is the authorization code from Azure AD
  const code = req.query.code;
  try {
    const params = new URLSearchParams();
    params.append('client_id', process.env.AZURE_CLIENT_ID);
    params.append('scope', 'https://graph.microsoft.com/.default offline_access'); 
    params.append('redirect_uri', process.env.AZURE_REDIRECT_URI);
    params.append('grant_type', 'authorization_code');
    params.append('code', code);
    params.append('client_secret', process.env.AZURE_CLIENT_SECRET); <b>//</b> for confidential clients

    const tokenResp = await axios.post(
      'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token',
      params.toString(),
      { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
    );

    const { access_token, refresh_token, expires_in } = tokenResp.data;
    <b>//</b> Persist tokens in a secure store (key vault, database encrypted)
    // saveTokensForUser(userId, { access_token, refresh_token, expires_at: Date.now() + expires_in*1000 });

    res.send('Authentication successful. You can close this window.');
  } catch (err) {
    console.error('token exchange', err.response?.data || err.message);
    res.status(500).send('Token exchange failed');
  }
});

 

Create subscriptions (webhooks) and handle validation

 
  • Subscriptions must point to a public HTTPS endpoint you control (not inside the transient agent). Configure that endpoint to respond to initial subscription validation challenges.
  • Create subscription via Graph API (server-to-server call). Provide a notificationUrl, resource (e.g., me/messages or users/{id}/messages), changeType, expirationDateTime, and optional clientState value for verification.
  • Validate subscription: Graph will make a validation request to your notificationUrl; follow Graph’s validation protocol (respond with the required token) so subscription is confirmed.
  • Renew subscriptions: subscriptions have a max lifetime and must be renewed before expiry. Implement scheduled renewal in your external service.
  • Handle notifications: notifications are lightweight; they indicate something changed. Fetch the full resource with Graph (using the subscription resource data) or use delta queries to discover exact changes.

 

Create subscription example (curl)

 
<b>//</b> Example: create a webhook subscription for the signed-in user's mail
curl -X POST "https://graph.microsoft.com/v1.0/subscriptions" \
 -H "Authorization: Bearer ACCESS_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "changeType": "created,updated,deleted",
   "notificationUrl": "https://your-public-service.example.com/webhook",
   "resource": "me/messages",
   "expirationDateTime": "2026-03-10T11:23:00.000Z",
   "clientState": "expected_client_state"
 }'

 

Webhook receiver notes

 
  • Respond to validation: when Graph sends the initial validation request, return the validation token exactly as documented by Microsoft Graph. (Implement the required simple validation handshake in your receiver.)
  • Verify clientState: for subsequent notifications, check the clientState (if used) to ensure notifications are for your subscription.
  • Resilience: notifications can be missed. Implement delta queries or periodic reconciliation to ensure you catch missed events.
  • Scaling: put the receiver behind a load balancer and ensure idempotency in processing notifications so retries don’t create duplicates.

 

Calling Graph from an OpenClaw skill

 
  • Where to run Graph calls: The OpenClaw skill code (configured in ClawHub) can make outbound REST calls to Graph if given access to tokens/credentials, but credentials and any long-lived state should be stored in a secure external store.
  • Recommended pattern: Build a small external API/service that owns OAuth, webhook handling, token storage, subscription lifecycle, and delta reconciliation. The OpenClaw skill invokes that API for higher-level operations (send email, fetch calendar events) rather than owning OAuth flows itself.
  • Direct Graph calls: If the skill calls Graph directly, ensure it uses the latest access token and handles 401 by refreshing tokens via your secure service.
  • Configuration in ClawHub: store client IDs, secrets (or service account references) and environment variables via ClawHub’s secure config mechanism so skill code can access them at runtime without embedding secrets.

 

Runtime and architecture guidance

 
  • Separation of responsibilities: Keep webhooks, token refreshers, subscription renewers, and durable storage outside the agent. Agents should perform stateless execution and call your external service for stateful workflows.
  • Secure secret handling: use a secrets manager (Key Vault, HashiCorp Vault, or ClawHub secure fields) for client secrets and refresh tokens.
  • Resilience: implement retry with exponential backoff on transient Graph errors (429, 5xx), and queue work (e.g., with a message queue) if you need to throttle or reliably process notifications.
  • Least privilege: request only the Graph scopes you need and prefer delegated narrower scopes when possible.
  • Logging & monitoring: centralize logs for OAuth exchanges, Graph API responses, and webhook receipts; monitor subscription expiry and failed renewals.

 

Debugging checklist (practical steps)

 
  • Authorize flow: check Azure AD app settings (redirect URI, client_id, client_secret) and that the redirect URL your app uses matches exactly what’s registered.
  • Token errors: inspect token endpoint responses for error codes (invalid_grant, interaction_required), and check that scopes and consent were granted.
  • Webhook validation: watch the webhook endpoint logs for the validation request and ensure you return the expected validation token in the correct format and timeframe.
  • Permissions: verify that the token’s scopes/roles match the API calls you’re making (inspect access\_token with jwt.ms or decode it to check scopes/aud).
  • Subscription status: call the Graph API to list subscriptions and check expirationDateTime and resource values.
  • Network/SSL: ensure Graph can reach your notificationUrl (public HTTPS, valid certificate). Use ngrok for local testing to get a public HTTPS URL.
  • Missed notifications: use delta queries to reconcile state if you suspect missing notifications.

 

Security and production notes

 
  • Protect credentials and use certificate-based auth for app-only tokens where possible.
  • Audit and rotate client secrets periodically and handle refresh token revocation scenarios.
  • ClientState and validation are simple but important protections — use them and validate values on receipt.
  • Scale and reliability: keep webhook processing idempotent and durable (work queues) and don’t assume immediate delivery of notifications.

Book Your Free 30‑Minute Migration Call

Speak one‑on‑one with a senior engineer about your no‑code app, migration goals, and budget. In just half an hour you’ll leave with clear, actionable next steps—no strings attached.

Book a Free Consultation

Troubleshooting Outlook Microsoft Graph and OpenClaw Integration

1

Why does the OpenClaw Outlook Connector return "invalid_client" or "insufficient privileges" when acquiring app-only Microsoft Graph tokens from the OpenClaw Admin Portal?

The direct cause is either bad client credentials (wrong/rotated secret, wrong tenant, or certificate) producing invalid_client, or missing/ungranted application permissions in Azure AD producing insufficient privileges. OpenClaw’s Admin Portal only sends what you configure — it won’t auto-grant consent or fix secrets.

 

Possible causes and checks

 

Quick checks:

  • invalid_client: client_id/secret/cert mismatch, expired secret, wrong tenant or token endpoint (v2 vs v1).
  • insufficient privileges: app lacks application permissions or admin consent wasn’t granted.
  • Scope vs resource error: use https://graph.microsoft.com/.default for client_credentials.

 

Reproduce and debug

 

Run a direct token request to isolate OpenClaw config:

```bash // request app-only token curl -X POST https://login.microsoftonline.com//oauth2/v2.0/token \ -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_SECRET&grant_type=client_credentials&scope=https://graph.microsoft.com/.default" ```

 

What to fix

 
  • Verify secret/certificate in OpenClaw Admin Portal matches Azure AD app.
  • Assign required application permissions and click Grant admin consent.
  • Check Azure AD Sign-ins and audit logs for detailed error messages and conditional access blocks.

2

Why do Microsoft Graph change notifications fail the validationToken challenge and never reach the OpenClaw Webhook Receiver when created by the OpenClaw Sync Agent?

The short answer: Microsoft Graph sends a validationToken request to the subscription's public HTTPS notificationUrl and expects an immediate 200 with the token echoed as plain text. Subscriptions created by the OpenClaw Sync Agent fail because Microsoft cannot successfully reach or get the exact response from the agent's webhook receiver (URL not public, TLS/certificate issues, wrong response format, or timeout), so validation never completes and notifications are never delivered.

 

Root causes and fixes

 
  • Ensure public HTTPS reachability — the OpenClaw webhook receiver must be reachable from Microsoft Graph (use a public URL or tunnel; agent runtime endpoints are often internal).
  • Echo token exactly — reply 200 OK with the raw validationToken string in the response body (text/plain), within ~5s.
  • Fix TLS — valid certificate, no self-signed blocks Graph from posting.
  • Debug — inspect Sync Agent logs, Graph subscription creation response, and capture HTTP requests (ngrok or server logs) to confirm the validation POST and response.

3

Why does the OpenClaw Sync Agent produce duplicate or missing messages when using Microsoft Graph delta queries (deltaLink/state mismatch) for mailbox synchronization?

Direct answer: Duplicate or missing messages happen when the deltaLink (the state token Graph returns) your OpenClaw Sync Agent uses is out of sync with the mailbox state — typically from race conditions, non-atomic persistence, wrong scope (folder vs mailbox), parallel workers sharing a token, or failure to handle delta reset responses — causing replays or skipped changes.

 

Root causes

 

Common reasons:

  • Non-atomic save of deltaLink so a run can re-read an old token.
  • Multiple agents using the same token causing overlapping reads.
  • Not handling 410/412 (reset) responses from Graph, so you miss a full resync.

 

Mitigations

 
  • Persist deltaLink atomically after successful processing; use per-mailbox locks.
  • Deduplicate by message-id/Graph id before emitting events.
  • On Graph reset, perform full sync and replace token.
// fetch changes
const resp = await fetch(deltaUrl);
// process items...
// then atomically store newDeltaLink
await storeDeltaLink(mailboxId, resp['@odata.deltaLink']);

4

Why does OpenClaw Mailbox Mapping fail to access shared or delegated mailboxes even after granting Mail.Read and Mail.Read.Shared permissions in Azure AD?

Direct answer: Mailbox mapping usually fails because the OAuth token and permission type don't match how Exchange exposes shared/delegated mailboxes. Mail.Read and Mail.Read.Shared are delegated scopes (require a user present and that user's access to the shared mailbox) and won't let an app-only client access a shared mailbox. Also the shared mailbox often needs explicit Exchange-level full_access delegation or an application access policy plus admin consent.

 

Why it fails

 

Common causes:

  • Delegated vs app-only mismatch — scopes in token are delegated or app roles only.
  • No admin consent — delegated scopes require consent for all users.
  • No Exchange delegation — mailbox lacks full_access/sendAs in Exchange.
  • Wrong principal or address — using the wrong user id/alias in API calls.

 

How to fix

 
  • Use delegated flow with a user who has mailbox access, or
  • Grant application permissions (Mail.Read.All) + create an application access policy and assign Exchange full_access to the app, then give admin consent.
  • Inspect the access token (scp or roles) and Graph API error codes to confirm the cause.
Book a Free Consultation

Still stuck?
Copy this prompt into ChatGPT and get a clear, personalized explanation.

This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.

AI AI Prompt


Recognized by the best

Trusted by 600+ businesses globally

From startups to enterprises and everything in between, see for yourself our incredible impact.

RapidDev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with.

They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

Arkady
CPO, Praction
Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost.

He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Donald Muir
Co-Founder, Arc
RapidDev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space.

They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Mat Westergreen-Thorne
Co-CEO, Grantify
RapidDev is an excellent developer for custom-code solutions.

We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Emmanuel Brown
Co-Founder, Church Real Estate Marketplace
Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 

This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Samantha Fekete
Production Manager, Media Production Company
The pSEO strategy executed by RapidDev is clearly driving meaningful results.

Working with RapidDev has delivered measurable, year-over-year growth. Comparing the same period, clicks increased by 129%, impressions grew by 196%, and average position improved by 14.6%. Most importantly, qualified contact form submissions rose 350%, excluding spam.

Appreciation as well to Matt Graham for championing the collaboration!

Michael W. Hammond
Principal Owner, OCD Tech

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â