
A service principal is the identity an app, script or CI pipeline uses to sign in to Azure. You create one by registering an application in Microsoft Entra ID (the new name for Azure Active Directory), giving it a credential, and assigning it a role on the resources it needs.
This guide shows three ways to create one (the portal, the Azure CLI and PowerShell), how to grant it access, and the secret-free option you should use for GitHub Actions. If your code runs on an Azure resource like a VM or App Service, skip ahead to managed identities: you may not need a service principal at all.
Using it from the command line? See using the Azure CLI with a service principal to list storage files.
Option 1: Create a Service Principal in the Azure Portal
Step 1: Open Microsoft Entra ID
- Log in to the Azure Portal.
- Search for Microsoft Entra ID (formerly Azure Active Directory) and open it. You can also use the Entra admin center at entra.microsoft.com.

Step 2: Access App Registrations
- Under “Manage,” click on App registrations.

Step 3: Register a New Application
- Click on New registration to create a new application.

Step 4: Fill in Application Details
- Enter a meaningful name for your application.
- Choose the appropriate account type (e.g., “Accounts in this organizational directory only”).
- Leave the “Redirect URI” blank for now.
- Click Register to create the application.

Step 5: Note Application (Client) ID and Directory (Tenant) ID
- After registration, note the Application (Client) ID and Directory (Tenant) ID from the overview page.

Step 6: Create a New Client Secret
- In the left-hand menu, go to Certificates & secrets.
- Click on New client secret.
- Provide a description, set an expiration, and click Add.
- Copy the secret Value (not the Secret ID) immediately. Azure shows it only once.

Step 7: Assign a role
A new service principal has no access to anything until you give it a role:
- Open the subscription, resource group or resource it should manage.
- Go to Access control (IAM) → Add → Add role assignment.
- Pick a role. Use the narrowest one that works, such as Reader, Storage Blob Data Contributor or a specific service role, rather than Contributor on the whole subscription.
- On the Members tab choose User, group, or service principal, search for your app’s name, select it, then Review + assign.
Role assignments can take a few minutes to take effect.
Option 2: Create a Service Principal with the Azure CLI
az login
az ad sp create-for-rbac \
--name "my-app-sp" \
--role "Reader" \
--scopes "/subscriptions/<subscription-id>/resourceGroups/<resource-group>"
This registers the app, creates the service principal, adds a client secret and assigns the role in one step. The output looks like this:
{
"appId": "<client-id>",
"displayName": "my-app-sp",
"password": "<client-secret>",
"tenant": "<tenant-id>"
}
Store password somewhere safe right away, such as Azure Key Vault or your CI system’s secret store. You cannot retrieve it later; you can only reset it. If you leave out --role and --scopes, the service principal is created with no access at all.
Sign in as the service principal to test it:
az login --service-principal -u <client-id> -p <client-secret> --tenant <tenant-id>
az group list -o table
Option 3: Create a Service Principal with PowerShell
Connect-AzAccount
$sp = New-AzADServicePrincipal `
-DisplayName "my-app-sp" `
-Role "Reader" `
-Scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>"
$sp.AppId # client ID
$sp.PasswordCredentials.SecretText # client secret, shown only here
(Get-AzContext).Tenant.Id # tenant ID
Note the parameter names: -DisplayName and -Scope (singular). Older guides use -Name and -Scopes, which the current Az module does not accept. The secret is not printed to the console; read it from PasswordCredentials.SecretText and store it immediately.
Better for GitHub Actions: No Secret at All (OIDC)
A client secret stored in GitHub is a long-lived credential that can leak and must be rotated. With workload identity federation, GitHub Actions exchanges a short-lived OIDC token for Azure access, and there is no secret to store.
1. Add a federated credential to your app registration. Save this as credential.json:
{
"name": "github-main",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:<org>/<repo>:ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}
az ad app federated-credential create --id <client-id> --parameters credential.json
The subject controls exactly which workflows can sign in: here, only runs on the main branch of one repository. Use repo:<org>/<repo>:environment:production to tie it to a GitHub environment instead.
2. Sign in from the workflow:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: azure/login@v3
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- run: az group list -o table
id-token: write is required; without it the login step fails. For more on workflow permissions, see our GitHub Actions workflow YAML guide.
Service Principal vs Managed Identity
| Service principal | Managed identity | |
|---|---|---|
| Where your code runs | Anywhere: laptop, CI, another cloud | On an Azure resource (VM, App Service, Functions, AKS, etc.) |
| Credentials | Secret, certificate or federated credential you manage | None; Azure issues and rotates tokens |
| Rotation | Your job | Automatic |
| Best for | CI/CD, external apps, scripts | Anything already running in Azure |
A managed identity is a service principal that Azure creates and manages for you. If your code runs inside Azure, prefer it: there is nothing to leak or rotate.
Security Checklist
- Assign the narrowest role at the narrowest scope. Contributor on a whole subscription is rarely needed.
- Prefer federated credentials (for CI) or managed identities (inside Azure) over client secrets.
- If you must use a secret, keep the expiry short and rotate before it expires. Expired secrets are one of the most common causes of sudden pipeline failures.
- Use a separate service principal per app or pipeline, so you can revoke one without breaking others.
- Review role assignments periodically and delete service principals you no longer use.
Common Errors
AADSTS7000215: Invalid client secret provided: you used the Secret ID instead of the secret Value, or the secret expired.AuthorizationFailed: sign-in worked but the role assignment is missing, is on the wrong scope, or has not propagated yet. Wait a few minutes and check IAM.AADSTS700213: No matching federated identity record found: the OIDCsubjectdoes not match the branch, environment or repository the workflow ran from.Insufficient privileges to complete the operationwhen creating one: your account lacks permission to register apps in Entra ID. Ask an admin for the Application Developer role.
Frequently Asked Questions
An identity that an application, script or automation tool uses to authenticate to Azure and access resources, with permissions scoped by role assignments.
A managed identity is a service principal that Azure creates and rotates for you and attaches to an Azure resource, so you never handle its credentials.
Run az ad sp create-for-rbac with a name, role and scope. It returns the appId, password and tenant.
Client secrets expire, one year by default via the CLI. Rotate them before expiry, or use a certificate credential or a managed identity instead.
Commands verified against Microsoft Learn and the azure/login README on September 25, 2026.
Related guides
- Using Azure CLI and Service Principal to List Files in a Storage Account
- Authenticate Azure Portal with Azure DevOps
- Creating a GCP Service Account and Key: Step-by-Step Guide
- Azure Kubernetes Service (AKS) vs. Azure Red Hat OpenShift (ARO)
- Azure Service Endpoints vs Private Endpoints vs Private Links
- Creating an AWS S3 Bucket with Pulumi in Python