🎁 New User? Get 20% off your first purchase with code NEWUSER20 Register Now →
Menu

Categories

Microsoft Graph API Authentication: App Registration, Certificates, Managed Identity (2026)

Microsoft Graph API Authentication: App Registration, Certificates, Managed Identity (2026)
Microsoft Graph API authentication guide

The biggest source of pain when scripting against Microsoft Graph in 2026 is not the API — it is figuring out which authentication mode you should use, how to set up the app registration, what scope to grant, and whether the script will work in your CI runner without any plain-text secrets in the repo. This guide answers all of those, in order, with the actual portal clicks and the actual PowerShell.

You will end up with a clean app registration that authenticates with a certificate, a managed identity for Azure-hosted scripts, and a clear answer to the "which scopes" question. Free PDF cheat sheet at the end.

The six auth modes — and which to pick

ModeWhen to useSecurity
Interactive (delegated)Day-to-day admin from your workstationGood (MFA on the user)
Device code flowHeadless devices that need a one-time authGood
Client secretQuick prototypes, labWeak (secret leaks)
CertificateProduction unattended on Windows / LinuxStrong
Managed IdentityAzure-hosted apps, Azure Functions, runbooksStrongest
Workload Identity FederationGitHub Actions / GitLab CI / external IdPStrong (no static secrets)

Pick the strongest one your environment supports. In 2026, Managed Identity inside Azure and Workload Identity Federation outside it should be the defaults.

Create the app registration

  1. Sign in to entra.microsoft.com as an admin.
  2. Identity → Applications → App registrations → New registration.
  3. Name: e.g. graph-userprovisioning-prod.
  4. Supported account types: usually "Accounts in this organizational directory only".
  5. Redirect URI: leave blank for unattended app, or http://localhost for interactive.
  6. Register.

Note the Application (client) ID and Directory (tenant) ID from the Overview page.

Grant API permissions

  1. Inside the app registration, API permissions → Add a permission → Microsoft Graph.
  2. Pick Application permissions for unattended scripts (or Delegated for interactive).
  3. Add only the scopes you need. User.Read.All, not Directory.ReadWrite.All, unless you genuinely need the broader one.
  4. Click Grant admin consent for <tenant> at the top — without this step the permissions are listed but inactive.

Client secret

Quick to set up, weak in production. Acceptable for an isolated lab tenant.

  1. App registration → Certificates & secrets → New client secret.
  2. Pick the shortest reasonable expiration (max 24 months).
  3. Copy the Value immediately — you will never see it again.
$secret = ConvertTo-SecureString $env:GRAPH_SECRET -AsPlainText -Force
$cred   = [pscredential]::new($clientId, $secret)
Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $cred

Certificate (recommended)

The certificate's private key never leaves the machine. The portal stores only the public key. Compromise of the key requires compromise of the host. This is the right answer for any unattended workload outside Azure.

Generate a self-signed cert (for non-public app):

$cert = New-SelfSignedCertificate `
    -Subject "CN=graph-userprovisioning-prod" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeyExportPolicy Exportable `
    -KeySpec Signature -KeyLength 2048 -HashAlgorithm SHA256 `
    -NotAfter (Get-Date).AddYears(2)

$thumb = $cert.Thumbprint

# Export the public part for upload
Export-Certificate -Cert $cert -FilePath .\graph-app.cer

Upload graph-app.cer to the app registration: Certificates & secrets → Certificates → Upload. Then connect with the thumbprint:

Connect-MgGraph -TenantId $tenantId -ClientId $clientId -CertificateThumbprint $thumb

Managed Identity (Azure-hosted)

If your script runs in Azure (App Service, Function, VM, Automation), enable a Managed Identity on the resource and skip secrets entirely:

# Inside an Azure resource with a system-assigned identity
Connect-MgGraph -Identity

# Or with a user-assigned identity by client id
Connect-MgGraph -Identity -ClientId ""

Grant the managed identity Graph application permissions via PowerShell or via the portal (Enterprise applications → All applications → find your MI → Permissions). Microsoft Graph permissions for Managed Identities cannot be granted through the regular App registration UI — you must use a script to add them.

Workload Identity Federation (GitHub Actions, etc.)

Use this when your CI runner sits outside Azure but you do not want to store a secret. The runner's OIDC token is exchanged for an Entra ID token federated to your app registration.

  1. App registration → Certificates & secrets → Federated credentials → Add credential.
  2. Pick the scenario (GitHub Actions, Kubernetes, generic OIDC).
  3. Enter the issuer (e.g. https://token.actions.githubusercontent.com) and the subject (repo:org/repo:ref:refs/heads/main).

From the GitHub workflow:

jobs:
  provision:
    runs-on: ubuntu-latest
    permissions: { id-token: write, contents: read }
    steps:
      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - run: |
          pwsh -c "Import-Module Microsoft.Graph; Connect-MgGraph -AccessToken (Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).Token; Get-MgUser -Top 5"

Zero secrets in the repo, full Graph access, every login attributable.

Application permissions always require admin consent. Either click "Grant admin consent" in the portal, or send an admin a tenant-wide consent URL:

https://login.microsoftonline.com/<tenantId>/adminconsent?client_id=<clientId>

For delegated permissions, the user can consent for themselves on first login unless your tenant is configured to require admin consent for all apps.

Common errors

"Insufficient privileges to complete the operation"

The required scope is granted but admin consent has not been clicked, or the consent was for a different scope than the call needs.

"AADSTS7000215: Invalid client secret"

The secret value is wrong, or you copied the secret ID instead of the value. They look similar in the portal.

"AADSTS70021: No matching federated identity record found"

The GitHub subject on the federated credential does not match the workflow's actual iss/sub claim. Re-check the branch name in the subject.

"The certificate is not valid"

Either the cert expired, or PowerShell is loading a cert from the wrong store. Verify with Get-ChildItem Cert:\CurrentUser\My\$thumb.

Cheat sheet

The whole auth matrix + the connect commands on a single PDF: Graph API Authentication Cheat Sheet.

FAQ

Can I share one app registration across multiple tenants?

Yes — set "Supported account types" to multitenant when you register. Each customer admin then consents once for their tenant.

What is the difference between Application and Delegated permissions?

Application permissions = the app acts as itself, with no signed-in user (use for unattended scripts). Delegated permissions = the app acts on behalf of a signed-in user (use for interactive). Both are configured separately on the same app registration.

Should I rotate client secrets?

Yes — every 6 to 12 months, ideally automated. Better: skip secrets entirely with certificates or Managed Identity.

How do I see who consented to my app and what they granted?

Entra portal → Enterprise applications → your app → Permissions. Shows the consented scopes and (for delegated) the per-user consent.

Can a Managed Identity have delegated permissions?

No — Managed Identities only support Application permissions. There is no signed-in user.

Can I use Microsoft Graph from a script that signs in with my personal Microsoft account?

Only against the consumer Graph endpoints (your own profile, OneDrive Personal). Tenant-level operations require an Entra ID work account.

Where should I store the certificate thumbprint in CI?

The thumbprint is not secret — only the private key is. Store the thumbprint as a regular CI variable. The cert itself goes in the runner's certificate store or a vault.

Related reading

Share this article:
Dargslan Editorial Team (Dargslan)
About the Author

Dargslan Editorial Team (Dargslan)

Collective of Software Developers, System Administrators, DevOps Engineers, and IT Authors

Dargslan is an independent technology publishing collective formed by experienced software developers, system administrators, and IT specialists.

The Dargslan editorial team works collaboratively to create practical, hands-on technology books focused on real-world use cases. Each publication is developed, reviewed, and...

Programming Languages Linux Administration Web Development Cybersecurity Networking

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.