Skip to main content
The Microsoft 365 provider supports authentication using GitHub Actions’ OpenID Connect (OIDC) tokens. This approach allows Terraform to authenticate to Microsoft 365 services directly from GitHub Actions workflows without storing long-lived credentials as GitHub secrets.

How GitHub OIDC Works

1

Workflow Permissions

The workflow runs with permissions: id-token: write, causing the runner to prepare an OIDC token
2

Environment Variables

GitHub injects ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN into the job environment
3

Provider Configuration

The provider automatically reads these environment variables during configuration
4

Request JWT

The provider requests a short-lived JWT from GitHub’s OIDC provider
5

Exchange Token

The JWT is exchanged for an Azure access token via workload federation
6

API Authentication

The resulting token is used to authenticate Microsoft Graph API calls

Benefits

No Secrets

Long-lived secrets don’t need to be stored in GitHub

Auto Rotation

Tokens are short-lived and automatically rotated

Conditional Access

Fine-grained control over which workflows can obtain tokens

Terraform Cloud Compatible

Works with both local and remote Terraform execution

Prerequisites

  • A GitHub repository where you’ll run Terraform
  • Permissions to create and configure app registrations in Microsoft Entra ID
  • Ability to modify GitHub Actions workflows
  • Azure CLI installed (for setup commands)

Setup

1

Create App Registration

# Set variables
export TENANT_ID="00000000-0000-0000-0000-000000000000"
export APP_NAME="terraform-provider-microsoft365"
export GITHUB_ORG="your-github-org"
export GITHUB_REPO="your-github-repo"

# Create app registration
APP_ID=$(az ad app create --display-name "$APP_NAME" --query appId -o tsv)
APP_OBJECT_ID=$(az ad app show --id "$APP_ID" --query id -o tsv)

# Create service principal
az ad sp create --id "$APP_ID"

# Grant Microsoft Graph permissions
az ad app permission add \
  --id "$APP_ID" \
  --api 00000003-0000-0000-c000-000000000000 \
  --api-permissions 78145de6-330d-4800-a6ce-494ff2d33d07=Role

# Grant admin consent
az ad app permission admin-consent --id "$APP_ID"
2

Configure Federated Credential

# For a specific branch
az ad app federated-credential create \
  --id $APP_ID \
  --parameters "{\"name\":\"github-federated-credential\",\"issuer\":\"https://token.actions.githubusercontent.com\",\"subject\":\"repo:${GITHUB_ORG}/${GITHUB_REPO}:ref:refs/heads/main\",\"audiences\":[\"api://AzureADTokenExchange\"]}"

Subject Patterns

| Scenario | Subject Format | Example | |----------|----------------|---------|| | Specific branch | repo:ORG/REPO:ref:refs/heads/BRANCH | repo:octo-org/octo-repo:ref:refs/heads/main | | Any branch | repo:ORG/REPO:* | repo:octo-org/octo-repo:* | | Pull requests | repo:ORG/REPO:pull_request | repo:octo-org/octo-repo:pull_request | | Specific tag | repo:ORG/REPO:ref:refs/tags/TAG | repo:octo-org/octo-repo:ref:refs/tags/v1.0.0 | | Specific environment | repo:ORG/REPO:environment:ENV | repo:octo-org/octo-repo:environment:production |

GitHub Actions Workflow

name: Terraform Microsoft 365

on:
  workflow_dispatch:

# Permission to request the OIDC JWT ID token
permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.13.3"

      - name: Terraform Init
        run: terraform init
        working-directory: path/to/terraform

      - name: Terraform Plan
        run: terraform plan
        working-directory: path/to/terraform
        env:
          M365_TENANT_ID: ${{ secrets.TENANT_ID }}
          M365_AUTH_METHOD: "oidc_github"
          M365_CLIENT_ID: ${{ secrets.M365_CLIENT_ID }}

Provider Configuration

Security Best Practices

Security Recommendations
  1. Narrow the scope of trust: Use specific branch, environment, or tag conditions instead of wildcard subjects
  2. Separate app registrations: Create separate apps for different repositories or workflows
  3. Conditional access policies: Configure additional conditions in Microsoft Entra ID
  4. Limit API permissions: Grant only the minimum required permissions
  5. Enable auditing: Monitor token issuance and usage in Microsoft Entra ID logs

Troubleshooting

Error: GitHub OIDC authentication requires oidc_request_url and oidc_request_tokenEnsure your workflow has the permissions: id-token: write directive properly configured.
Error: OIDC provider not availableThis happens when trying to use GitHub OIDC authentication outside a GitHub Actions workflow. The method only works within GitHub Actions.
Error: No matching federated identity record foundThe subject claim in the JWT doesn’t match any federated credential. Double-check that your subject pattern exactly matches your workflow’s context.
# List federated credentials
az ad app federated-credential list --id $APP_ID -o table
Error: Authorization_RequestDeniedThe app registration doesn’t have the necessary Microsoft Graph permissions. Grant permissions and admin consent:
az ad app permission add --id $APP_ID --api 00000003-0000-0000-c000-000000000000 --api-permissions PERMISSION_ID=Role
az ad app permission admin-consent --id $APP_ID
Enable debug logging for detailed authentication flow information:
export TF_LOG=DEBUG

Build docs developers (and LLMs) love