Tools now includes a personal Microsoft To Do integration for authenticated users.
/api/microsoft-todo/* for apps and other clients./todo (short alias) and /settings/integrations/microsoft-todoauth:webFrom this page a user can:
The shared Microsoft app is configured at host/admin level (typically through environment values). The user-facing To Do page is intentionally per-user and focuses on connecting/disconnecting each user's own Microsoft account.
If you want to reuse one Entra app across both Copilot and Microsoft To Do, the config now also accepts shared fallback aliases:
ENTRA_TENANT_ID=
ENTRA_CLIENT_ID=
ENTRA_CLIENT_SECRET=
MICROSOFT_* keys remain the preferred explicit keys for this integration, but when they are empty Tools can now fall back to ENTRA_* (and then COPILOT_*) for tenant/client credentials.
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/callbackThe 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-linkoauth.microsoft.start/oauth/microsoft/startPOSTauth:weboauth.microsoft.start_link/oauth/microsoft/start-linkGETauth:webThis 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.microsoft.callback/oauth/microsoft/callbackGETThe 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/statusReturns the generic Microsoft auth/platform-app status for the authenticated user.
Intended use:
The response can include additive fields such as:
provider="microsoft"platform="microsoft_graph"auth_readycallback_urlcallback_legacy_urlsupported_integrations[]planned_integrations[]platform_app.supports_personal_accountsplatform_app.supports_work_or_school_accountsplatform_app.account_support_hintThese endpoints accept either:
POST /api/account/login.GET /api/microsoft-todo/statusReturns 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_viaenv_managedclient_id_configuredclient_secret_configuredtenantredirect_urirecommended_callback_urlrecommended_callback_legacy_urlrecommended_start_link_urldefault_scopesaccount_support_hintsupports_personal_accountssupports_work_or_school_accountsmissing_fields[]status_messageExample 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/startBuilds one Microsoft authorization URL for the currently authenticated user.
Compatibility note:
GET /api/microsoft-todo/oauth/start path still works/oauth/microsoft/callbackIntended use:
Example response:
{
"ok": true,
"authorization_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?...",
"callback_url": "https://tools.tornevall.com/oauth/microsoft/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/syncRuns 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/listsReturns local mirrored lists. By default tasks are included.
Optional query parameters:
include_tasks=1 (default)include_tasks=0POST /api/microsoft-todo/listsCreate 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}/tasksReturns the tasks for one local mirrored list.
POST /api/microsoft-todo/lists/{listId}/tasksCreate 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.
The synchronization model is intentionally simple and predictable:
A scheduled sync also runs automatically every 15 minutes through:
php artisan microsoft-todo:sync/settings/integrations/microsoft-todo.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.GET /api/microsoft/auth/status instead of starting from the To Do-specific status endpoint.common or consumers and make sure the Azure app registration itself allows personal accounts (MSA).organizations (or a specific tenant GUID/domain). The status/auth diagnostics now also report whether the current tenant mode supports work/school accounts.