Azure Functions app to export Microsoft To Do lists and tasks.
Application available at:
https://ms-todo-export.azurewebsites.net
- Go to Azure Portal → Microsoft Entra ID → App registrations
- Create a new registration:
- Name: Microsoft To Do Exporter
- Account types: Multitenant (or single tenant)
- Redirect URI:
- Local:
http://localhost:7071/api/callback - Production:
https://<your-function-app>.azurewebsites.net/api/callback
- Local:
- After creation, note the Application (client) ID
- Go to Certificates & secrets → New client secret → Note the Value
- Go to API permissions → Add permission → Microsoft Graph → Delegated:
Tasks.Read
- Install Azure Functions Core Tools
- Create or update
local.settings.jsonat the project root with the following example. Do NOT commit secrets to source control.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME_VERSION": "7.4",
"FUNCTIONS_WORKER_RUNTIME": "powershell",
"CLIENT_ID": "your-client-id",
"CLIENT_SECRET": "your-client-secret",
"REDIRECT_URI": "http://localhost:7071/api/callback",
"AUTHORIZE_URL": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
}
}- Run locally:
func start- Navigate to
http://localhost:7071
For custom domains, you may need to verify domain ownership with Microsoft.
The app includes an endpoint at /.well-known/microsoft-identity-association.json that returns the application association data.
- Built with Azure Functions PowerShell runtime
- Uses Microsoft Graph API for To Do data access
- OAuth 2.0 Authorization Code flow with Entra ID
- Base64 encoding for safe JSON embedding in HTML
- Automatic download functionality with JavaScript
- Navigate to
http://localhost:7071/ - Click "Authorize and Export"
- Sign in with Microsoft account
- Grant permissions
- Download the JSON backup file
-
LandingPage (
/): Landing page with authorization link -
Callback (
/api/callback): OAuth callback handler, exchanges code for token, redirects via POST -
Export (
/api/export): Fetches all lists and tasks, returns JSON with auto-download -
IdentityAssociation (
/.well-known/microsoft-identity-association.json): Microsoft identity association endpoint (usesCLIENT_IDenv var) -
Local vs Azure settings:
local.settings.jsonis only for local development. In Azure, set equivalent values as Function App Settings (Application Settings) — do not rely onlocal.settings.jsonin production.
- Ensure function host is running:
func host start - Check that all functions are loaded without errors
- Verify route configurations in
function.jsonfiles
- Confirm redirect URI matches exactly in App Registration
- Check that API permissions are granted (
Tasks.Read) - Verify client ID and secret are correct in app settings
{
"exportDate": "2026-02-11T00:00:00Z",
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#me/todo",
"lists": {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#me/todo/lists",
"@odata.count": 1,
"value": [
{
"@odata.etag": "W/\"etag-list-example-1\"",
"id": "example-list-id-1",
"displayName": "Example List",
"isOwner": true,
"isShared": false,
"wellknownListName": "defaultList",
"createdDateTime": "2026-02-01T00:00:00Z",
"lastModifiedDateTime": "2026-02-11T00:00:00Z"
}
]
},
"tasks": {
"example-list-id-1": {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#me/todo/lists('example-list-id-1')/tasks",
"@odata.count": 1,
"value": [
{
"@odata.etag": "W/\"etag-task-example-1\"",
"id": "example-task-id-1",
"title": "Example Task 1",
"body": {
"content": "Example task details.",
"contentType": "text"
},
"bodyLastModifiedDateTime": "2026-02-02T08:00:00Z",
"status": "notStarted",
"importance": "normal",
"createdDateTime": "2026-02-01T12:00:00Z",
"lastModifiedDateTime": "2026-02-11T12:00:00Z",
"completedDateTime": null,
"dueDateTime": {
"dateTime": "2026-02-15T17:00:00",
"timeZone": "UTC"
},
"reminderDateTime": null,
"isReminderOn": false,
"recurrence": null,
"categories": [],
"linkedResources": [],
"attachments": []
}
]
}
}
}