← Back to docs

Microsoft To Do

Language: EN | EN | SV

Microsoft To Do

Tools now includes a personal Microsoft To Do integration for authenticated users.

What it does

  • Connects your Microsoft account to Tools through Microsoft OAuth.
  • Mirrors your Microsoft To Do lists into Tools.
  • Mirrors your Microsoft To Do tasks into Tools.
  • Pushes changes made in Tools back to Microsoft To Do.
  • Pulls remote changes from Microsoft To Do back into Tools.
  • Reuses one shared Microsoft / Microsoft Graph auth app that is meant to stay reusable for broader Microsoft / Entra-backed integrations later too.
  • Exposes authenticated JSON endpoints under /api/microsoft-todo/* for apps and other clients.

Web UI

  • Path: /settings/integrations/microsoft-todo
  • Auth: auth:web

From this page a user can:

  • connect their Microsoft account,
  • run a manual sync,
  • create, rename, and delete lists,
  • create, edit, complete, and delete tasks,
  • disconnect the local Microsoft To Do connection.

Configuration

The shared platform Azure app can now be handled in two ways:

  1. Environment-managed through MICROSOFT_TODO_* values, or
  2. database-backed platform app settings saved directly from /settings/integrations/microsoft-todo by an acknowledged admin.

Environment values still take precedence when they are present.

The page now shows a configuration diagnostics panel with:

  • whether the platform app is currently available,
  • whether it is managed via environment or database,
  • which required fields are still missing,
  • the effective redirect URI,
  • the recommended callback URL for the current host,
  • and a proper direct browser auth-start link from the current Tools host once the platform app is complete.

It now also shows an explicit tenant/account-type hint. This is especially important when Microsoft returns unauthorized_client: that usually means the Azure app registration exists, but its supported account types do not match the selected tenant mode.

When the platform app is not environment-managed, acknowledged admins can save/update the shared Microsoft To Do platform app directly from that page through an AJAX form. The client secret is never echoed back; the page only reports whether a secret is already stored.

Preferred shared Microsoft environment values:

MICROSOFT_TENANT=common
MICROSOFT_CLIENT_ID=
MICROSOFT_CLIENT_SECRET=
MICROSOFT_REDIRECT_URI=
MICROSOFT_DEFAULT_SCOPES="offline_access openid profile User.Read Tasks.ReadWrite"

Legacy Microsoft To Do-specific aliases are still accepted too:

MICROSOFT_TODO_TENANT=common
MICROSOFT_TODO_CLIENT_ID=
MICROSOFT_TODO_CLIENT_SECRET=
MICROSOFT_TODO_REDIRECT_URI=
MICROSOFT_TODO_DEFAULT_SCOPES="offline_access openid profile User.Read Tasks.ReadWrite"

The callback URL for the current environment is shown on the web page and is also available via the route:

  • /oauth/microsoft/callback
  • /oauth/microsoft-todo/callback

The web page now also shows a direct clickable auth-start link for browser testing/copying when the platform app is complete. That link uses:

  • /oauth/microsoft/start-link
  • /oauth/microsoft-todo/start-link

OAuth routes

Start OAuth flow

  • Route name: oauth.microsoft_todo.start
  • Path: /oauth/microsoft-todo/start
  • Method: POST
  • Auth: auth:web

Direct auth-start link

  • Preferred route name: oauth.microsoft.start_link
  • Preferred path: /oauth/microsoft/start-link
  • Legacy compatibility route name: oauth.microsoft_todo.start_link
  • Legacy compatibility path: /oauth/microsoft-todo/start-link
  • Method: GET
  • Auth: auth:web

This route exists so the Microsoft To Do integration page can show one normal clickable shared Microsoft auth link in addition to the POST form button. Each visit creates a fresh signed OAuth state and then redirects directly to Microsoft.

OAuth callback

  • Preferred route name: oauth.microsoft.callback
  • Preferred path: /oauth/microsoft/callback
  • Legacy compatibility route name: oauth.microsoft_todo.callback
  • Legacy compatibility path: /oauth/microsoft-todo/callback
  • Method: GET
  • Auth: public callback URL (the original signed OAuth state is still required)

The callback can now still finish the connection even if the browser no longer has an active Tools web session, as long as the signed Microsoft state matches the original user/transaction. When that happens, Tools now recreates the matching web session from the signed state before it redirects back to the Microsoft To Do integration page, so the user does not land on a fresh login wall after a successful callback.

GET /api/microsoft/auth/status

Returns the generic Microsoft auth/platform-app status for the authenticated user.

Intended use:

  • clients that want one shared Microsoft auth readiness/status surface,
  • native/mobile callers that need callback/start URLs and tenant/account-type diagnostics,
  • future Microsoft / Graph integrations that should not start from a To Do-specific status contract.

The response can include additive fields such as:

  • provider="microsoft"
  • platform="microsoft_graph"
  • auth_ready
  • callback_url
  • callback_legacy_url
  • supported_integrations[]
  • planned_integrations[]
  • platform_app.supports_personal_accounts
  • platform_app.supports_work_or_school_accounts
  • platform_app.account_support_hint

API endpoints

These endpoints accept either:

  • a normal logged-in web session, or
  • a JWT bearer token from POST /api/account/login.

GET /api/microsoft-todo/status

Returns connection state, account display name, local counts, and whether the platform app is available.

The response now also includes additive platform_app diagnostics with non-secret configuration metadata such as:

  • managed_via
  • env_managed
  • client_id_configured
  • client_secret_configured
  • tenant
  • redirect_uri
  • recommended_callback_url
  • recommended_callback_legacy_url
  • recommended_start_link_url
  • default_scopes
  • account_support_hint
  • supports_personal_accounts
  • supports_work_or_school_accounts
  • missing_fields[]
  • status_message

Example response:

{
  "ok": true,
  "connected": true,
  "app_available": true,
  "connect_web_url": "/settings/integrations/microsoft-todo",
  "connect_api_url": "/api/microsoft/oauth/start",
  "connect_api_legacy_url": "/api/microsoft-todo/oauth/start",
  "connection": {
    "status": "connected",
    "status_label": "Connected",
    "status_description": "Connected to Microsoft account \"user@example.com\".",
    "provider_account_name": "user@example.com",
    "expires_at": "2026-03-30T13:15:00+00:00",
    "last_connected_at": "2026-03-30T12:58:00+00:00"
  },
  "counts": {
    "lists": 4,
    "tasks": 22,
    "dirty_lists": 0,
    "dirty_tasks": 1
  }
}

GET /api/microsoft/oauth/start

Builds one Microsoft authorization URL for the currently authenticated user.

Compatibility note:

  • the older GET /api/microsoft-todo/oauth/start path still works
  • the new generic path is now the recommended API entrypoint when the same Microsoft app registration is intended to serve the wider Tools platform and not only the To Do UI wording
  • the returned callback now points at the preferred generic browser callback alias /oauth/microsoft/callback, while /oauth/microsoft-todo/callback remains available as a legacy alias

Intended use:

  • native/mobile clients that authenticate against Tools first,
  • browser-based helpers that need the current OAuth start URL from the API,
  • clients that want to open the Microsoft consent page in a WebView/Custom Tab instead of relying only on the Tools web form.

Example response:

{
  "ok": true,
  "authorization_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?...",
  "callback_url": "https://tools.tornevall.com/oauth/microsoft-todo/callback",
  "connect_web_url": "/settings/integrations/microsoft-todo",
  "connect_api_url": "/api/microsoft/oauth/start",
  "connect_api_legacy_url": "/api/microsoft-todo/oauth/start"
}

POST /api/microsoft-todo/sync

Runs an immediate push/pull synchronization.

Example response:

{
  "ok": true,
  "message": "Microsoft To Do sync complete.",
  "sync": {
    "ok": true,
    "lists_pushed": 1,
    "tasks_pushed": 2,
    "lists_pulled": 4,
    "tasks_pulled": 22,
    "errors": []
  }
}

GET /api/microsoft-todo/lists

Returns local mirrored lists. By default tasks are included.

Optional query parameters:

  • include_tasks=1 (default)
  • include_tasks=0

POST /api/microsoft-todo/lists

Create a list and sync it to Microsoft To Do.

Request body:

{
  "display_name": "Work"
}

PATCH /api/microsoft-todo/lists/{listId}

Rename a synced list.

Request body:

{
  "display_name": "Work Projects"
}

DELETE /api/microsoft-todo/lists/{listId}

Delete the list both locally and remotely.

GET /api/microsoft-todo/lists/{listId}/tasks

Returns the tasks for one local mirrored list.

POST /api/microsoft-todo/lists/{listId}/tasks

Create a task in the given list.

Request body:

{
  "title": "Follow up with customer",
  "body_text": "Remember to attach the report.",
  "importance": "high",
  "status": "notStarted",
  "due_at": "2026-04-02 09:00:00",
  "reminder_at": "2026-04-02 08:30:00"
}

PATCH /api/microsoft-todo/tasks/{taskId}

Update a task.

Request body:

{
  "title": "Follow up with customer",
  "body_text": "Report sent, waiting for reply.",
  "importance": "normal",
  "status": "inProgress",
  "due_at": "2026-04-03 09:00:00",
  "reminder_at": null
}

DELETE /api/microsoft-todo/tasks/{taskId}

Delete a task both locally and remotely.

Sync behavior

The synchronization model is intentionally simple and predictable:

  1. Local dirty lists are pushed first.
  2. Local dirty tasks are pushed second.
  3. The remote Microsoft To Do snapshot is pulled back into Tools.
  4. Remote deletes are reflected locally when the local row is not dirty.
  5. Local dirty rows are not overwritten by the pull step.

A scheduled sync also runs automatically every 15 minutes through:

  • php artisan microsoft-todo:sync

Notes

  • Web users can still start the connect flow from /settings/integrations/microsoft-todo.
  • API/native clients can now request the current Microsoft OAuth URL through GET /api/microsoft/oauth/start and then open that URL in a browser surface. The older GET /api/microsoft-todo/oauth/start path remains available as a compatibility alias.
  • Clients that need one generic Microsoft auth readiness surface can now also call GET /api/microsoft/auth/status instead of starting from the To Do-specific status endpoint.
  • If you expect personal Microsoft accounts, use tenant common or consumers and make sure the Azure app registration itself allows personal accounts (MSA).
  • If you expect Microsoft Entra work/school accounts only, use organizations (or a specific tenant GUID/domain). The status/auth diagnostics now also report whether the current tenant mode supports work/school accounts.
  • If Microsoft token refresh fails, the user may need to reconnect.