Skip to main content
This guide covers everything you need to install and configure the Microsoft 365 Terraform Provider, including setting up authentication and API permissions.

Prerequisites

Terraform version

The Microsoft 365 provider requires:
  • Terraform >= 1.14.x
You can download Terraform from the official website. To check your Terraform version:
terraform version

Microsoft 365 requirements

You’ll need:
  • A Microsoft 365 tenant with appropriate licenses
  • Global Administrator or sufficient permissions to create Entra ID app registrations
  • Access to the Azure Portal or Entra ID Admin Center

Step 1: Add the provider to your configuration

Create or update your Terraform configuration to include the provider:
terraform {
  required_version = ">= 1.14.0"
  
  required_providers {
    microsoft365 = {
      source  = "deploymenttheory/microsoft365"
      version = "~> 0.40.0"
    }
  }
}
Replace ~> 0.40.0 with the latest version from the Terraform Registry. The provider follows Semantic Versioning.

Step 2: Initialize Terraform

Run the following command to download and install the provider:
terraform init
You should see output confirming the provider installation:
Initializing provider plugins...
- Finding deploymenttheory/microsoft365 versions matching "~> 0.40.0"...
- Installing deploymenttheory/microsoft365 v0.40.x...
- Installed deploymenttheory/microsoft365 v0.40.x

Step 3: Create an Entra ID application

The provider uses an Entra ID (formerly Azure AD) application registration for authentication.
# Create the application
az ad app create --display-name "Terraform Microsoft 365 Provider"

# Get the application details
az ad app list --display-name "Terraform Microsoft 365 Provider" \
  --query "[].{appId:appId, displayName:displayName}"

# Get your tenant ID
az account show --query tenantId -o tsv
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Application.ReadWrite.All"

# Create the application
$app = New-MgApplication -DisplayName "Terraform Microsoft 365 Provider"

# Display the application details
$app | Select-Object AppId, DisplayName

# Get your tenant ID
(Get-MgContext).TenantId

Step 4: Create a client secret or certificate

You need to create credentials for authentication. You can use either a client secret (easier) or a certificate (more secure).

Create a client secret

Via Azure Portal

  1. In your application’s page, select Certificates & secrets
  2. Under Client secrets, click + New client secret
  3. Add a description (e.g., “Terraform Provider Secret”)
  4. Select an expiration period:
    • 180 days (6 months) - Recommended for testing
    • 365 days (12 months) - For development
    • 730 days (24 months) - For production (with rotation plan)
  5. Click Add
  6. Important: Copy the secret Value immediately - it will only be shown once
The client secret value is only displayed once after creation. If you lose it, you’ll need to create a new secret.

Via Azure CLI

# Create a client secret (valid for 1 year)
az ad app credential reset --id <app-id> --append \
  --display-name "Terraform Provider Secret" \
  --years 1

Via PowerShell

# Create a client secret (valid for 6 months)
$passwordCred = @{
    displayName = 'Terraform Provider Secret'
    endDateTime = (Get-Date).AddMonths(6)
}

Add-MgApplicationPassword -ApplicationId <app-id> -PasswordCredential $passwordCred

Step 5: Grant API permissions

Your application needs Microsoft Graph API permissions to manage Microsoft 365 resources.

Required permissions

The specific permissions depend on which resources you’ll manage. Here are common permission sets:
Application permissions (recommended for automation):
  • User.ReadWrite.All - Create, read, update, and delete users
  • Group.ReadWrite.All - Create, read, update, and delete groups
  • GroupMember.ReadWrite.All - Manage group memberships
  • Directory.ReadWrite.All - Read and write directory data
Application permissions:
  • Policy.ReadWrite.ConditionalAccess - Manage conditional access policies
  • Policy.ReadWrite.AuthenticationMethod - Manage authentication methods
  • RoleManagement.ReadWrite.Directory - Manage directory roles
  • Application.ReadWrite.All - Manage applications and service principals
Application permissions:
  • DeviceManagementConfiguration.ReadWrite.All - Manage device configurations
  • DeviceManagementManagedDevices.ReadWrite.All - Manage devices
  • DeviceManagementApps.ReadWrite.All - Manage mobile apps
  • DeviceManagementServiceConfig.ReadWrite.All - Manage service configuration
Application permissions:
  • TeamSettings.ReadWrite.All - Manage team settings
  • TeamsApp.ReadWrite.All - Manage Teams apps

Add permissions via Azure Portal

  1. In your application’s page, select API permissions
  2. Click + Add a permission
  3. Select Microsoft Graph
  4. Choose Application permissions (for service-to-service authentication)
  5. Search for and select the permissions you need
  6. Click Add permissions
  7. Important: Click Grant admin consent for [Your Organization]
Application permissions require admin consent. Without admin consent, the provider will fail with permission errors.

Add permissions via Azure CLI

# Example: Add user and group management permissions
az ad app permission add --id <app-id> \
  --api 00000003-0000-0000-c000-000000000000 \
  --api-permissions \
    df021288-bdef-4463-88db-98f22de89214=Role \
    62a82d76-70ea-41e2-9197-370581804d09=Role \
    dbaae8cf-10b5-4b86-a4a1-f871c94c6695=Role

# Grant admin consent
az ad app permission admin-consent --id <app-id>

Add permissions via PowerShell

# Get the Microsoft Graph service principal
$graphSP = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'"

# Define required permissions
$permissions = @(
    "User.ReadWrite.All",
    "Group.ReadWrite.All",
    "GroupMember.ReadWrite.All"
)

# Add permissions
foreach ($permission in $permissions) {
    $role = $graphSP.AppRoles | Where-Object { $_.Value -eq $permission }
    New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId <app-object-id> `
        -PrincipalId <app-object-id> `
        -ResourceId $graphSP.Id `
        -AppRoleId $role.Id
}

Step 6: Configure the provider

Now you can configure the provider with your credentials. The provider supports 11 authentication methods.

Method 1: Client Secret (most common)

provider "microsoft365" {
  cloud       = "public"
  tenant_id   = var.tenant_id
  auth_method = "client_secret"

  entra_id_options = {
    client_id     = var.client_id
    client_secret = var.client_secret
  }

  telemetry_optout = true
}

Method 2: Client Certificate

provider "microsoft365" {
  cloud       = "public"
  tenant_id   = var.tenant_id
  auth_method = "client_certificate"

  entra_id_options = {
    client_id                   = var.client_id
    client_certificate          = "/path/to/certificate.pfx"
    client_certificate_password = var.cert_password
    send_certificate_chain      = false
  }
}

Method 3: Managed Identity (for Azure VMs)

provider "microsoft365" {
  cloud       = "public"
  tenant_id   = var.tenant_id
  auth_method = "managed_identity"

  entra_id_options = {
    # Optional: Specify a user-assigned managed identity
    managed_identity_id = var.managed_identity_id
  }
}

Method 4: Azure Developer CLI

Ideal for local development:
provider "microsoft365" {
  cloud       = "public"
  tenant_id   = var.tenant_id
  auth_method = "azure_developer_cli"
}
First authenticate with:
azd auth login

Method 5: GitHub Actions OIDC

For CI/CD pipelines:
provider "microsoft365" {
  cloud       = "public"
  tenant_id   = var.tenant_id
  auth_method = "oidc_github"

  entra_id_options = {
    client_id = var.client_id
  }
}
The provider supports these authentication methods:
  1. azure_developer_cli - Uses Azure Developer CLI identity
  2. azure_cli - Uses Azure CLI identity
  3. client_secret - Client ID and secret
  4. client_certificate - Client certificate (.pfx)
  5. device_code - Device code flow (interactive)
  6. interactive_browser - Opens browser for login
  7. managed_identity - Azure managed identity
  8. workload_identity - Kubernetes workload identity
  9. oidc - Generic OpenID Connect
  10. oidc_github - GitHub Actions OIDC
  11. oidc_azure_devops - Azure DevOps OIDC
See the Terraform Registry documentation for detailed configuration of each method.

Environment variables reference

All provider configuration can be set via environment variables:
Environment VariableDescriptionExample
M365_TENANT_IDMicrosoft 365 tenant ID00000000-0000-0000-0000-000000000000
M365_CLIENT_IDApplication (client) ID11111111-1111-1111-1111-111111111111
M365_CLIENT_SECRETClient secret valueyour-secret-value
M365_AUTH_METHODAuthentication methodclient_secret, client_certificate, etc.
M365_CLOUDCloud environmentpublic, gcc, gcchigh, dod, china
M365_CLIENT_CERTIFICATE_FILE_PATHPath to certificate file/path/to/cert.pfx
M365_CLIENT_CERTIFICATE_PASSWORDCertificate passwordcert-password
M365_TELEMETRY_OPTOUTDisable telemetrytrue or false
M365_DEBUG_MODEEnable debug loggingtrue or false
M365_USE_PROXYEnable HTTP proxytrue or false
M365_PROXY_URLProxy server URLhttp://proxy.example.com:8080
Environment variables override values set in the provider configuration block.

Advanced configuration

Client options

Configure HTTP client behavior:
provider "microsoft365" {
  # ... authentication config ...

  client_options = {
    enable_retry       = true
    max_retries        = 3
    retry_delay_seconds = 5
    
    enable_redirect    = true
    max_redirects      = 5
    
    enable_compression = true
    timeout_seconds    = 300
    
    custom_user_agent  = "MyTerraform/1.0"
  }
}

Proxy configuration

For environments requiring HTTP proxy:
provider "microsoft365" {
  # ... authentication config ...

  client_options = {
    use_proxy      = true
    proxy_url      = "http://proxy.example.com:8080"
    proxy_username = var.proxy_username
    proxy_password = var.proxy_password
  }
}

Multi-cloud support

For US Government or other clouds:
provider "microsoft365" {
  cloud     = "gcchigh"  # US Government High
  tenant_id = var.tenant_id
  # ... rest of config ...
}
Supported cloud values:
  • public - Microsoft Azure Public Cloud (default)
  • gcc - US Government Cloud
  • gcchigh - US Government High Cloud
  • dod - US Department of Defense Cloud
  • china - Microsoft Cloud China
  • ex - EagleX Cloud
  • rx - Secure Cloud (RX)

Troubleshooting

Provider not found

If you see “provider not found” errors:
  1. Verify the source is deploymenttheory/microsoft365
  2. Run terraform init to download the provider
  3. Check the version constraint is valid

Authentication failures

Error: Invalid client secret
  • Verify the client secret value is correct
  • Check if the secret has expired
  • Create a new secret if needed
Error: Insufficient privileges
  • Verify API permissions are granted
  • Ensure admin consent has been granted
  • Check the application has the required roles

Permission errors

Error: Forbidden (403)
  • The application lacks required API permissions
  • Add the necessary permissions and grant admin consent
  • Wait a few minutes for permission changes to propagate

Enable debug logging

For detailed troubleshooting:
provider "microsoft365" {
  # ... other config ...
  debug_mode = true
}
Or via environment variable:
export M365_DEBUG_MODE=true

Security best practices

Never commit secrets to version controlAlways use one of these methods for secrets:
  • Environment variables
  • Terraform variables with .tfvars (add to .gitignore)
  • Secret management tools (HashiCorp Vault, Azure Key Vault, etc.)
  • CI/CD secret stores (GitHub Secrets, Azure DevOps Variables, etc.)
  1. Use certificate-based authentication instead of client secrets for production
  2. Rotate secrets regularly - Set short expiration periods and automate rotation
  3. Grant least privilege - Only assign required API permissions
  4. Use managed identity when running on Azure infrastructure
  5. Enable debug mode only for troubleshooting - It logs sensitive information
  6. Monitor application usage - Review sign-in logs in Entra ID

Secret rotation

Plan for credential rotation:
# Create a second secret before the first expires
az ad app credential reset --id <app-id> --append

# Update your Terraform configuration with the new secret
# After validating, delete the old secret
az ad app credential delete --id <app-id> --key-id <old-key-id>

Next steps

1

Test your configuration

Run terraform plan to verify authentication works
2

Try the quick start

Deploy your first resources with the Quick start guide
3

Explore resources

Browse available resources in the Terraform Registry

Get help

Discord community

Ask questions and get help from other users

GitHub issues

Report bugs or request features

Build docs developers (and LLMs) love