Skip to content

feat: Microsoft Dynamics 365 CRM / Dataverse Integration #6

Description

@jrosskopf

Summary

Add native support for connecting to Microsoft Dynamics 365 CRM (Customer Engagement / Sales) and Dataverse from DuckDB, enabling users to authenticate and query CRM data using SQL.

Relationship to Business Central Integration (#5)

This issue shares significant implementation overlap with #5 (Business Central Integration). Both use:

  • Microsoft Entra ID OAuth2 authentication (identical token endpoint and flow)
  • OData v4 API compliance (same query capabilities)
  • Same scope pattern for tokens ({resource_url}/.default)

Recommended approach: Implement a shared microsoft_entra or azure_ad authentication provider that both Business Central and CRM/Dataverse integrations can use. This avoids code duplication and ensures consistent authentication behavior.

Background

Microsoft Dynamics 365 CRM (also known as Customer Engagement, Sales, or Dataverse) is a cloud-based CRM platform widely used for sales, marketing, customer service, and field service operations. It exposes data through:

  • Dataverse Web API (OData v4 compliant)
  • Standard entities (accounts, contacts, leads, opportunities, etc.)
  • Custom entities (user-defined tables)

User Stories

1. Service-to-Service Authentication (Primary)

As a data engineer, I want to configure automated access to Dynamics 365 CRM using client credentials, so that I can build ETL pipelines without user interaction.

Acceptance Criteria:

  • Create a secret with client_id, client_secret, tenant_id, and environment_url
  • Authenticate using OAuth2 client credentials flow against Microsoft Entra ID
  • Automatically obtain and refresh tokens as needed

2. Interactive User Authentication

As an analyst, I want to authenticate to Dynamics 365 CRM using my Microsoft account, so that I can query data with my user permissions.

3. Entity Discovery

As a user, I want to discover all available entities in my Dataverse environment, so that I can explore the data model.

4. Entity Schema Discovery

As a user, I want to describe the schema of a specific entity, so that I understand the available fields.

5. Data Reading with Pushdown

As an analyst, I want to query Dynamics 365 CRM data using SQL with filter pushdown, so that I can efficiently retrieve only the data I need.

Technical Context

Dataverse Web API Structure

Base URL Pattern:

https://{organization}.crm.dynamics.com/api/data/v9.2/

Authentication (Same as Business Central #5)

Microsoft Entra ID OAuth2:

  • Token endpoint: https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
  • Scope: {environment_url}/.default
  • Client credentials flow for S2S automation

Core CRM Entities

Sales: accounts, contacts, leads, opportunities, quotes, orders, invoices
Marketing: campaigns, lists, campaignresponses
Customer Service: incidents (cases), knowledgearticles, queues
Common: systemusers, teams, businessunits, annotations, activities

Query Capabilities (Same as Business Central)

  • $filter, $select, $expand, $top, $skip, $count, $orderby

Example Usage (Conceptual)

-- Create secret for S2S authentication
CREATE SECRET crm_secret (
    TYPE dataverse,
    PROVIDER client_credentials,
    CLIENT_ID 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    CLIENT_SECRET 'your-client-secret',
    TENANT_ID 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    ENVIRONMENT_URL 'https://myorg.crm.dynamics.com'
);

-- Discover all available entities
SELECT * FROM crm_show_entities(secret := 'crm_secret');

-- Describe entity schema
SELECT * FROM crm_describe('accounts', secret := 'crm_secret');

-- Query accounts with filter pushdown
SELECT name, emailaddress1, revenue
FROM crm_read('accounts', secret := 'crm_secret')
WHERE statecode = 0;

-- Query opportunities with expansion
SELECT * FROM crm_read('opportunities', secret := 'crm_secret', expand := 'customerid_account')
WHERE estimatedclosedate >= '2024-01-01';

Implementation Strategy

Shared Components with Business Central (#5)

Component Reuse Strategy
Microsoft Entra ID OAuth2 Create shared MicrosoftEntraAuthProvider class
Token refresh logic Shared token storage and refresh mechanism
OData v4 query building Existing odata_client infrastructure
Predicate pushdown Existing odata_predicate_pushdown_helper

CRM-Specific Components

Component Description
URL builder CRM-specific URL patterns ({org}.crm.dynamics.com/api/data/v9.x/)
Entity discovery Query EntityDefinitions metadata endpoint
Secret type TYPE dataverse with ENVIRONMENT_URL parameter

Out of Scope

  • Write operations (POST, PATCH, DELETE)
  • FetchXML query support
  • On-premises deployments

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions