GitHub Copilot ChatGPT Claude Codex CLI Cursor opencode Skill Text

entra-app-registration

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID s

Ciza · 0 points · 23 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download microsoft-skills-.github_plugins_azure-skills_skills_entra-app-registration-e58528d.zip · 31 KB
Part of microsoft/skills — 195 skills

Install

skills CLI npx skills add https://github.com/microsoft/skills/tree/main/.github/plugins/azure-skills/skills/entra-app-registration
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install microsoft-skills@llmmart
Git git clone https://github.com/microsoft/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole microsoft/skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Overview

Microsoft Entra ID (formerly Azure Active Directory) is Microsoft's cloud-based identity and access management service. App registrations allow applications to authenticate users and access Azure resources securely.

Key Concepts

Concept Description
App Registration Configuration that allows an app to use Microsoft identity platform
Application (Client) ID Unique identifier for your application
Tenant ID Unique identifier for your Azure AD tenant/directory
Client Secret Password for the application (confidential clients only)
Redirect URI URL where authentication responses are sent
API Permissions Access scopes your app requests
Service Principal Identity created in your tenant when you register an app

Application Types

Type Use Case
Web Application Server-side apps, APIs
Single Page App (SPA) JavaScript/React/Angular apps
Mobile/Native App Desktop, mobile apps
Daemon/Service Background services, APIs

Core Workflow

Step 1: Register the Application

Create an app registration in the Azure portal or using Azure CLI.

Portal Method:

  1. Navigate to Azure Portal → Microsoft Entra ID → App registrations
  2. Click "New registration"
  3. Provide name, supported account types, and redirect URI
  4. Click "Register"

CLI Method: See references/cli-commands.md IaC Method: See references/BICEP-EXAMPLE.bicep

It's highly recommended to use the IaC to manage Entra app registration if you already use IaC in your project, need a scalable solution for managing lots of app registrations or need fine-grained audit history of the configuration changes.

Step 2: Configure Authentication

Set up authentication settings based on your application type.

  • Web Apps: Add redirect URIs, enable ID tokens if needed
  • SPAs: Add redirect URIs, enable implicit grant flow if necessary
  • Mobile/Desktop: Use http://localhost or custom URI scheme
  • Services: No redirect URI needed for client credentials flow

Step 3: Configure API Permissions

Grant your application permission to access Microsoft APIs or your own APIs.

Common Microsoft Graph Permissions:

  • User.Read - Read user profile
  • User.ReadWrite.All - Read and write all users
  • Directory.Read.All - Read directory data
  • Mail.Send - Send mail as a user

Details: See references/api-permissions.md

Step 4: Create Client Credentials (if needed)

For confidential client applications (web apps, services), create a client secret, certificate or federated identity credential.

Client Secret:

  • Navigate to "Certificates & secrets"
  • Create new client secret
  • Copy the value immediately (only shown once)
  • Store securely (Key Vault recommended)

Certificate: For production environments, use certificates instead of secrets for enhanced security. Upload certificate via "Certificates & secrets" section.

Federated Identity Credential: For dynamically authenticating the confidential client to Entra platform.

Step 5: Implement OAuth Flow

Integrate the OAuth flow into your application code.

See:

Common Patterns

Pattern 1: First-Time App Registration

Walk user through their first app registration step-by-step.

Required Information:

  • Application name
  • Application type (web, SPA, mobile, service)
  • Redirect URIs (if applicable)
  • Required permissions

Script: See references/first-app-registration.md

Pattern 2: Console Application with User Authentication

Create a .NET/Python/Node.js console app that authenticates users.

Required Information:

  • Programming language (C#, Python, JavaScript, etc.)
  • Authentication library (MSAL recommended)
  • Required permissions

Example: See references/console-app-example.md

Pattern 3: Service-to-Service Authentication

Set up daemon/service authentication without user interaction.

Required Information:

  • Service/app name
  • Target API/resource
  • Whether to use secret or certificate

Implementation: Use Client Credentials flow (see references/oauth-flows.md#client-credentials-flow)

MCP Tools and CLI

Azure CLI Commands

Command Purpose
az ad app create Create new app registration
az ad app list List app registrations
az ad app show Show app details
az ad app permission add Add API permission
az ad app credential reset Generate new client secret
az ad sp create Create service principal

Complete reference: See references/cli-commands.md

Microsoft Authentication Library (MSAL)

MSAL is the recommended library for integrating Microsoft identity platform.

Supported Languages:

  • .NET/C# - Microsoft.Identity.Client
  • JavaScript/TypeScript - @azure/msal-browser, @azure/msal-node
  • Python - msal

Examples: See references/console-app-example.md

Security Best Practices

Practice Recommendation
Never hardcode secrets Use environment variables, Azure Key Vault, or managed identity
Rotate secrets regularly Set expiration, automate rotation
Use certificates over secrets More secure for production
Least privilege permissions Request only required API permissions
Enable MFA Require multi-factor authentication for users
Use managed identity For Azure-hosted apps, avoid secrets entirely
Validate tokens Always validate issuer, audience, expiration
Use HTTPS only All redirect URIs must use HTTPS (except localhost)
Monitor sign-ins Use Entra ID sign-in logs for anomaly detection

SDK Quick References

References

External Resources

Files (skills)
  • references
    • sdk
      • azure-identity-dotnet.md 940 B
        # Authentication — .NET SDK Quick Reference
        
        > Condensed from **azure-identity-dotnet**. Full patterns (ASP.NET DI,
        > sovereign clouds, brokered auth, certificate credentials)
        > in the **azure-identity-dotnet** plugin skill if installed.
        
        ## Install
        dotnet add package Azure.Identity
        
        ## Quick Start
        > **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.
        
        ```csharp
        using Azure.Identity;
        var credential = new DefaultAzureCredential();
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only**. In production, use deterministic credentials (ManagedIdentityCredential) — see [auth-best-practices.md](../auth-best-practices.md)
        - Reuse credential instances — single instance shared across clients
        - Configure retry policies for credential operations
        - Enable logging with AzureEventSourceListener for debugging auth issues
        
      • azure-identity-java.md 1.2 KB
        # Authentication — Java SDK Quick Reference
        
        > Condensed from **azure-identity-java**. Full patterns (workload identity,
        > certificate auth, device code, sovereign clouds)
        > in the **azure-identity-java** plugin skill if installed.
        
        ## Install
        ```xml
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-identity</artifactId>
            <version>1.15.0</version>
        </dependency>
        ```
        
        ## Quick Start
        > **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.
        
        ```java
        import com.azure.identity.DefaultAzureCredentialBuilder;
        var credential = new DefaultAzureCredentialBuilder().build();
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only** (CLI, PowerShell, VS Code). In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
        - Managed identity in production — no secrets to manage, automatic rotation
        - Azure CLI for local dev — run `az login` before running your app
        - Least privilege — grant only required permissions to service principals
        - Token caching — enabled by default, reduces auth round-trips
        - Environment variables — use for CI/CD, not hardcoded secrets
        
      • azure-identity-py.md 1.1 KB
        # Authentication — Python SDK Quick Reference
        
        > Condensed from **azure-identity-py**. Full patterns (async,
        > ChainedTokenCredential, token caching, all credential types)
        > in the **azure-identity-py** plugin skill if installed.
        
        ## Install
        ```bash
        pip install azure-identity
        ```
        
        ## Quick Start
        > **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.
        
        ```python
        from azure.identity import DefaultAzureCredential
        credential = DefaultAzureCredential()
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only** (CLI, PowerShell, VS Code). In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
        - Never hardcode credentials — use environment variables or managed identity
        - Prefer managed identity in production Azure deployments
        - Use ChainedTokenCredential when you need a custom credential order
        - Close async credentials explicitly or use context managers
        - Set AZURE_CLIENT_ID env var for user-assigned managed identities
        - Exclude unused credentials to speed up authentication
        
      • azure-identity-rust.md 805 B
        # Authentication — Rust SDK Quick Reference
        
        > Condensed from **azure-identity-rust**. Full patterns (ClientSecret,
        > ClientCertificate, WorkloadIdentity, AzurePipelines credentials)
        > in the **azure-identity-rust** plugin skill if installed.
        
        ## Install
        cargo add azure_identity
        
        ## Quick Start
        ```rust
        use azure_identity::DeveloperToolsCredential;
        let credential = DeveloperToolsCredential::new(None)?;
        ```
        
        ## Best Practices
        - Use DeveloperToolsCredential for local dev — automatically picks up Azure CLI
        - Use ManagedIdentityCredential in production — no secrets to manage
        - Clone credentials — credentials are Arc-wrapped and cheap to clone
        - Reuse credential instances — same credential can be used with multiple clients
        - Use tokio feature — `cargo add azure_identity --features tokio`
        
      • azure-identity-ts.md 1.1 KB
        # Authentication — TypeScript SDK Quick Reference
        
        > Condensed from **azure-identity-ts**. Full patterns (sovereign clouds,
        > device code flow, custom credentials, bearer token provider)
        > in the **azure-identity-ts** plugin skill if installed.
        
        ## Install
        npm install @azure/identity
        
        ## Quick Start
        > **Auth:** `DefaultAzureCredential` is for local development. See [auth-best-practices.md](../auth-best-practices.md) for production patterns.
        
        ```typescript
        import { DefaultAzureCredential } from "@azure/identity";
        const credential = new DefaultAzureCredential();
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only** (CLI, PowerShell, VS Code). In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
        - Never hardcode credentials — use environment variables or managed identity
        - Prefer managed identity — no secrets to manage in production
        - Scope credentials appropriately — use user-assigned identity for multi-tenant scenarios
        - Handle token refresh — Azure SDK handles this automatically
        - Use ChainedTokenCredential for custom fallback scenarios
        
      • azure-keyvault-py.md 1.1 KB
        # Key Vault — Python SDK Quick Reference
        
        > Condensed from **azure-keyvault-py**. Full patterns (async clients,
        > cryptographic operations, certificate management, error handling)
        > in the **azure-keyvault-py** plugin skill if installed.
        
        ## Install
        pip install azure-keyvault-secrets azure-keyvault-keys azure-keyvault-certificates azure-identity
        
        ## Quick Start
        ```python
        from azure.identity import DefaultAzureCredential
        from azure.keyvault.secrets import SecretClient
        client = SecretClient(vault_url="https://<vault>.vault.azure.net/", credential=DefaultAzureCredential())
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
        - Use managed identity in Azure-hosted applications
        - Enable soft-delete for recovery (enabled by default)
        - Use RBAC over access policies for fine-grained control
        - Rotate secrets regularly using versioning
        - Use Key Vault references in App Service/Functions config
        - Cache secrets appropriately to reduce API calls
        - Use async clients for high-throughput scenarios
        
      • azure-keyvault-secrets-ts.md 1 KB
        # Key Vault Secrets — TypeScript SDK Quick Reference
        
        > Condensed from **azure-keyvault-secrets-ts**. Full patterns (key rotation,
        > cryptographic operations, backup/restore, wrap/unwrap)
        > in the **azure-keyvault-secrets-ts** plugin skill if installed.
        
        ## Install
        npm install @azure/keyvault-secrets @azure/identity
        
        ## Quick Start
        ```typescript
        import { DefaultAzureCredential } from "@azure/identity";
        import { SecretClient } from "@azure/keyvault-secrets";
        const client = new SecretClient("https://<vault>.vault.azure.net", new DefaultAzureCredential());
        ```
        
        ## Best Practices
        - Use DefaultAzureCredential for **local development only**. In production, use ManagedIdentityCredential — see [auth-best-practices.md](../auth-best-practices.md)
        - Enable soft-delete — required for production vaults
        - Set expiration dates on both keys and secrets
        - Use key rotation policies — automate key rotation
        - Limit key operations — only grant needed operations (encrypt, sign, etc.)
        - Browser not supported — these SDKs are Node.js only
        
      • microsoft-azure-webjobs-extensions-authentication-events-dotnet.md 1.5 KB
        # Authentication Events — .NET SDK Quick Reference
        
        > Condensed from **microsoft-azure-webjobs-extensions-authentication-events-dotnet**.
        > Full patterns (attribute collection, OTP customization, external data enrichment)
        > in the source plugin skill if installed.
        
        ## Install
        dotnet add package Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents
        
        ## Quick Start
        ```csharp
        using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
        using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.TokenIssuanceStart;
        
        [FunctionName("OnTokenIssuanceStart")]
        public static WebJobsAuthenticationEventResponse Run(
            [WebJobsAuthenticationEventsTrigger] WebJobsTokenIssuanceStartRequest request,
            ILogger log)
        {
            var response = new WebJobsTokenIssuanceStartResponse();
            response.Actions.Add(new WebJobsProvideClaimsForToken
            {
                Claims = new Dictionary<string, string> { { "claim", "value" } }
            });
            return response;
        }
        ```
        
        ## Best Practices
        - Validate all inputs — never trust request data; validate before processing
        - Handle errors gracefully — return appropriate error responses, don't throw
        - Log correlation IDs — use CorrelationId for troubleshooting
        - Keep functions fast — authentication events have timeout limits
        - Use managed identity — access Azure resources securely
        - Cache external data — avoid slow lookups on every request
        - Test locally — use Azure Functions Core Tools with sample payloads
        - Monitor with App Insights — track function execution and errors
        
    • api-permissions.md 10 KB
      # API Permissions Guide
      
      This document explains how to configure and manage API permissions for your Microsoft Entra app registration.
      
      ## Permission Types
      
      ### Delegated Permissions (User Context)
      
      **What:** Application acts on behalf of a signed-in user
      
      **When to use:**
      - User is present and can consent
      - App needs to access resources as the user
      - Interactive authentication flows
      
      **Examples:**
      - Read user's email
      - Update user's calendar
      - Access user's OneDrive files
      
      **Scope format:** User must consent (or admin pre-consents)
      
      ### Application Permissions (App Context)
      
      **What:** Application acts with its own identity (no user)
      
      **When to use:**
      - Background services, daemons
      - Scheduled jobs
      - API-to-API calls without user
      
      **Examples:**
      - Read all users in organization
      - Send mail as any user
      - Access all SharePoint sites
      
      **Requirement:** Always requires admin consent
      
      ## Permission Scopes
      
      ### Understanding Scopes
      
      **Scope:** A string that defines what access is granted
      
      **Format:**
      ```
      {resource}/{permission_name}
      
      Examples:
      https://graph.microsoft.com/User.Read
      https://graph.microsoft.com/Mail.Send
      api://myapi-id/access_as_user
      ```
      
      ### .default Scope
      
      Special scope that includes all configured permissions:
      
      ```
      https://graph.microsoft.com/.default
      api://your-api-id/.default
      ```
      
      **When to use:**
      - Client credentials flow (always)
      - Want all pre-configured permissions
      - Migrating from v1.0 endpoint
      
      ## Microsoft Graph Permissions
      
      ### Common Delegated Permissions
      
      | Permission | What it allows | Admin Consent Required |
      |------------|---------------|----------------------|
      | `User.Read` | Read signed-in user's profile | No |
      | `User.ReadWrite` | Read and update user profile | No |
      | `User.ReadBasic.All` | Read basic info of all users | No |
      | `User.Read.All` | Read all users' full profiles | Yes |
      | `Mail.Read` | Read user's mail | No |
      | `Mail.ReadWrite` | Read and write user's mail | No |
      | `Mail.Send` | Send mail as user | No |
      | `Calendars.Read` | Read user's calendars | No |
      | `Calendars.ReadWrite` | Read and write calendars | No |
      | `Files.Read.All` | Read all files user can access | No |
      | `Sites.Read.All` | Read items in all site collections | Yes |
      | `Directory.Read.All` | Read directory data | Yes |
      | `Directory.ReadWrite.All` | Read and write directory data | Yes |
      
      ### Common Application Permissions
      
      | Permission | What it allows | Admin Consent Required |
      |------------|---------------|----------------------|
      | `User.Read.All` | Read all users' full profiles | Yes (Always) |
      | `User.ReadWrite.All` | Read and write all users' profiles | Yes (Always) |
      | `Mail.Read` | Read mail in all mailboxes | Yes (Always) |
      | `Mail.Send` | Send mail as any user | Yes (Always) |
      | `Calendars.Read` | Read calendars in all mailboxes | Yes (Always) |
      | `Directory.Read.All` | Read directory data | Yes (Always) |
      | `Directory.ReadWrite.All` | Read and write directory data | Yes (Always) |
      | `Group.ReadWrite.All` | Read and write all groups | Yes (Always) |
      
      ## Adding Permissions
      
      ### Azure Portal Method
      
      1. Navigate to your app registration
      2. Click **"API permissions"** in left menu
      3. Click **"+ Add a permission"**
      4. Choose API source:
         - **Microsoft APIs** (Graph, Office 365, etc.)
         - **APIs my organization uses** (custom APIs)
         - **My APIs** (your own APIs)
      
      5. Select permission type:
         - **Delegated permissions** (user context)
         - **Application permissions** (app context)
      
      6. Search and select permissions
      7. Click **"Add permissions"**
      
      See [cli-commands.md](cli-commands.md) for az cli commands to add API permissions programmatically.
      
      ## Finding Permission IDs
      
      ### Method 1: Azure Portal
      
      1. Go to Microsoft Entra ID → Enterprise applications
      2. Search for "Microsoft Graph"
      3. Click on it → Permissions
      4. Browse available permissions and copy IDs
      
      ### Method 2: Microsoft Graph Explorer
      
      1. Visit https://developer.microsoft.com/graph/graph-explorer
      2. Click "Modify permissions"
      3. Browse and view permission details
      
      ### Method 3: Microsoft Documentation
      
      Visit: https://learn.microsoft.com/en-us/graph/permissions-reference
      
      ### Method 4: Azure CLI Query
      
      ```bash
      # List all Graph permissions (warning: long output)
      az ad sp list --filter "appId eq '00000003-0000-0000-c000-000000000000'" \
        --query "[0].{delegated:oauth2PermissionScopes,application:appRoles}" -o json
      ```
      
      ## Granting Admin Consent
      
      ### When Admin Consent is Required
      
      **Always required for:**
      - All application permissions
      - High-privilege delegated permissions
      - When organization disables user consent
      
      **Examples requiring admin consent:**
      - `User.Read.All` (read all users)
      - `Directory.Read.All` (read directory)
      - `Mail.Read` (application permission)
      - `Sites.Read.All` (read all SharePoint sites)
      
      ### How to Grant Admin Consent
      
      **Portal Method:**
      1. Go to API permissions
      2. Click **"Grant admin consent for [Your Org]"**
      3. Confirm the action
      4. Check for green checkmarks next to permissions
      
      **CLI Method:**
      ```bash
      az ad app permission admin-consent --id $APP_ID
      ```
      
      ### Verifying Consent Status
      
      **Portal:** Look for green checkmarks in "Status" column
      
      **CLI:**
      ```bash
      az ad app permission list --id $APP_ID
      ```
      
      Look for `consentType: "AllPrincipals"` (admin consented)
      
      ## Custom API Permissions
      
      ### Exposing Your API
      
      If you're building an API that other apps will call:
      
      1. In your API's app registration, go to **"Expose an API"**
      2. Set **Application ID URI**: `api://your-api-id`
      3. Click **"+ Add a scope"**
      4. Configure scope:
         - **Scope name:** `access_as_user`
         - **Who can consent:** Admins and users
         - **Display name:** "Access MyAPI as user"
         - **Description:** Clear description of what this allows
      5. Click **"Add scope"**
      
      ## Effective Permissions
      
      ### User + App Permissions
      
      **Delegated permissions:** Intersection of user's permissions and app's permissions
      
      Example:
      - User can: Read all users
      - App granted: User.Read.All
      - **Effective:** Read all users ✅
      
      - User can: Only read their own profile
      - App granted: User.Read.All
      - **Effective:** Only read own profile (limited by user's rights)
      
      **Application permissions:** Only app's permissions matter (no user context)
      
      ## Troubleshooting Permissions
      
      ### "Insufficient privileges" Error
      
      **Causes:**
      - Permission not added to app registration
      - Admin consent not granted
      - User lacks permission in directory
      - Accessing resource outside permission scope
      
      **Solutions:**
      1. Check API permissions in portal
      2. Grant admin consent if needed
      3. Verify user has access to resource
      4. Use correct permission scope
      
      ### "Consent required" Error
      
      **Causes:**
      - User hasn't consented to permissions
      - Admin consent required but not granted
      - Token obtained before permission added
      
      **Solutions:**
      1. Request user consent (interactive flow)
      2. Admin grants consent (portal or CLI)
      3. Acquire new token after adding permissions
      
      ### Permission Appears Granted but Doesn't Work
      
      **Possible issues:**
      - Using old cached token (get new one)
      - Permission is delegated but user lacks rights
      - API requires additional configuration
      - Permission deprecated (use new one)
      
      **Debug steps:**
      1. Decode access token: https://jwt.ms
      2. Check `scp` claim (delegated) or `roles` claim (application)
      3. Verify permission is present in token
      4. Check if permission is correct type (delegated vs application)
      
      ## Permission Best Practices
      
      ### Development
      
      ✅ **Do:**
      - Start with minimal permissions
      - Add incrementally as features require
      - Test with non-admin accounts
      - Document why each permission is needed
      
      ❌ **Don't:**
      - Request all permissions "just in case"
      - Use admin account for testing only
      - Forget to grant admin consent for app permissions
      
      ### Production
      
      ✅ **Do:**
      - Review permissions quarterly
      - Remove unused permissions
      - Use least privilege principle
      - Monitor permission usage
      - Document all permissions in README
      
      ❌ **Don't:**
      - Grant excessive permissions for convenience
      - Use application permissions when delegated would work
      - Forget to rotate admin consent approvals
      
      ### Security
      
      ✅ **Do:**
      - Prefer delegated over application permissions
      - Implement proper scope validation
      - Log permission usage
      - Handle consent errors gracefully
      
      ❌ **Don't:**
      - Hardcode permission scopes in multiple places
      - Skip token validation
      - Ignore scope mismatches
      - Cache permissions indefinitely
      
      ## Reference Tables
      
      ### Microsoft Graph Permission IDs
      
      **Delegated Permissions:**
      ```
      User.Read                     : e1fe6dd8-ba31-4d61-89e7-88639da4683d
      User.ReadWrite                : b4e74841-8e56-480b-be8b-910348b18b4c
      User.ReadBasic.All            : b340eb25-3456-403f-be2f-af7a0d370277
      Mail.Read                     : 570282fd-fa5c-430d-a7fd-fc8dc98a9dca
      Mail.ReadWrite                : 024d486e-b451-40bb-833d-3e66d98c5c73
      Mail.Send                     : e383f46e-2787-4529-855e-0e479a3ffac0
      Calendars.Read                : 465a38f9-76ea-45b9-9f34-9e8b0d4b0b42
      Calendars.ReadWrite           : 1ec239c2-d7c9-4623-a91a-a9775856bb36
      Files.Read.All                : df85f4d6-205c-4ac5-a5ea-6bf408dba283
      ```
      
      **Application Permissions:**
      ```
      User.Read.All                 : df021288-bdef-4463-88db-98f22de89214
      User.ReadWrite.All            : 741f803b-c850-494e-b5df-cde7c675a1ca
      Mail.Read                     : 810c84a8-4a9e-49e6-bf7d-12d183f40d01
      Mail.Send                     : b633e1c5-b582-4048-a93e-9f11b44c7e96
      Directory.Read.All            : 7ab1d382-f21e-4acd-a863-ba3e13f7da61
      Directory.ReadWrite.All       : 19dbc75e-c2e2-444c-a770-ec69d8559fc7
      ```
      
      **Note:** Permission IDs may change. Always verify against the official [Microsoft Graph Permissions Reference](https://learn.microsoft.com/en-us/graph/permissions-reference) for the most current values.
      
      ## Additional Resources
      
      - [Microsoft Graph Permissions Reference](https://learn.microsoft.com/en-us/graph/permissions-reference)
      - [Permission Types](https://learn.microsoft.com/en-us/entra/identity-platform/permissions-consent-overview)
      - [Admin Consent Workflow](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/configure-admin-consent-workflow)
      - [Consent Framework](https://learn.microsoft.com/en-us/entra/identity-platform/consent-framework)
      
    • auth-best-practices.md 6.1 KB
      # Azure Authentication Best Practices
      
      > Source: [Microsoft — Passwordless connections for Azure services](https://learn.microsoft.com/azure/developer/intro/passwordless-overview) and [Azure Identity client libraries](https://learn.microsoft.com/dotnet/azure/sdk/authentication/).
      
      ## Golden Rule
      
      Use **managed identities** and **Azure RBAC** in production. Reserve `DefaultAzureCredential` for **local development only**.
      
      ## Authentication by Environment
      
      | Environment | Recommended Credential | Why |
      |---|---|---|
      | **Production (Azure-hosted)** | `ManagedIdentityCredential` (system- or user-assigned) | No secrets to manage; auto-rotated by Azure |
      | **Production (on-premises)** | `ClientCertificateCredential` or `WorkloadIdentityCredential` | Deterministic; no fallback chain overhead |
      | **CI/CD pipelines** | `AzurePipelinesCredential` / `WorkloadIdentityCredential` | Scoped to pipeline identity |
      | **Local development** | `DefaultAzureCredential` | Chains CLI, PowerShell, and VS Code credentials for convenience |
      
      ## Why Not `DefaultAzureCredential` in Production?
      
      1. **Unpredictable fallback chain** — walks through multiple credential types, adding latency and making failures harder to diagnose.
      2. **Broad surface area** — checks environment variables, CLI tokens, and other sources that should not exist in production.
      3. **Non-deterministic** — which credential actually authenticates depends on the environment, making behavior inconsistent across deployments.
      4. **Performance** — each failed credential attempt adds network round-trips before falling back to the next.
      
      ## Production Patterns
      
      ### .NET
      
      ```csharp
      using Azure.Identity;
      
      var credential = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"
          ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials
          : new ManagedIdentityCredential();                      // production — deterministic, no fallback chain
      // For user-assigned identity: new ManagedIdentityCredential("<client-id>")
      ```
      
      ### TypeScript / JavaScript
      
      ```typescript
      import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
      
      const credential = process.env.NODE_ENV === "development"
        ? new DefaultAzureCredential()                          // local dev — uses CLI/VS credentials
        : new ManagedIdentityCredential();                      // production — deterministic, no fallback chain
      // For user-assigned identity: new ManagedIdentityCredential("<client-id>")
      ```
      
      ### Python
      
      ```python
      import os
      from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
      
      credential = (
          DefaultAzureCredential()                              # local dev — uses CLI/VS credentials
          if os.getenv("AZURE_FUNCTIONS_ENVIRONMENT") == "Development"
          else ManagedIdentityCredential()                      # production — deterministic, no fallback chain
      )
      # For user-assigned identity: ManagedIdentityCredential(client_id="<client-id>")
      ```
      
      ### Java
      
      ```java
      import com.azure.identity.DefaultAzureCredentialBuilder;
      import com.azure.identity.ManagedIdentityCredentialBuilder;
      
      var credential = "Development".equals(System.getenv("AZURE_FUNCTIONS_ENVIRONMENT"))
          ? new DefaultAzureCredentialBuilder().build()          // local dev — uses CLI/VS credentials
          : new ManagedIdentityCredentialBuilder().build();      // production — deterministic, no fallback chain
      // For user-assigned identity: new ManagedIdentityCredentialBuilder().clientId("<client-id>").build()
      ```
      
      ## Local Development Setup
      
      `DefaultAzureCredential` is ideal for local dev because it automatically picks up credentials from developer tools:
      
      1. **Azure CLI** — `az login`
      2. **Azure Developer CLI** — `azd auth login`
      3. **Azure PowerShell** — `Connect-AzAccount`
      4. **Visual Studio / VS Code** — sign in via Azure extension
      
      ```typescript
      import { DefaultAzureCredential } from "@azure/identity";
      
      // Local development only — uses CLI/PowerShell/VS Code credentials
      const credential = new DefaultAzureCredential();
      ```
      
      ## Environment-Aware Pattern
      
      Detect the runtime environment and select the appropriate credential. The key principle: use `DefaultAzureCredential` only when running locally, and a specific credential in production.
      
      > **Tip:** Azure Functions sets `AZURE_FUNCTIONS_ENVIRONMENT` to `"Development"` when running locally. For App Service or containers, use any environment variable you control (e.g. `NODE_ENV`, `ASPNETCORE_ENVIRONMENT`).
      
      ```typescript
      import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
      
      function getCredential() {
        if (process.env.NODE_ENV === "development") {
          return new DefaultAzureCredential();          // picks up az login / VS Code creds
        }
        return process.env.AZURE_CLIENT_ID
          ? new ManagedIdentityCredential(process.env.AZURE_CLIENT_ID)  // user-assigned
          : new ManagedIdentityCredential();                            // system-assigned
      }
      ```
      
      ## Security Checklist
      
      - [ ] Use managed identity for all Azure-hosted apps
      - [ ] Never hardcode credentials, connection strings, or keys
      - [ ] Apply least-privilege RBAC roles at the narrowest scope
      - [ ] Use `ManagedIdentityCredential` (not `DefaultAzureCredential`) in production
      - [ ] Store any required secrets in Azure Key Vault
      - [ ] Rotate secrets and certificates on a schedule
      - [ ] Enable Microsoft Defender for Cloud on production resources
      
      ## Further Reading
      
      - [Passwordless connections overview](https://learn.microsoft.com/azure/developer/intro/passwordless-overview)
      - [Managed identities overview](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview)
      - [Azure RBAC overview](https://learn.microsoft.com/azure/role-based-access-control/overview)
      - [.NET authentication guide](https://learn.microsoft.com/dotnet/azure/sdk/authentication/)
      - [Python identity library](https://learn.microsoft.com/python/api/overview/azure/identity-readme)
      - [JavaScript identity library](https://learn.microsoft.com/javascript/api/overview/azure/identity-readme)
      - [Java identity library](https://learn.microsoft.com/java/api/overview/azure/identity-readme)
      
    • BICEP-EXAMPLE.bicep 5.2 KB · in bundle
    • cli-commands.md 8.6 KB
      # Azure CLI Commands for App Registration
      
      This document provides a comprehensive reference for managing Microsoft Entra app registrations using Azure CLI.
      
      ## Prerequisites
      
      ```bash
      # Ensure Azure CLI is installed
      az version
      
      # Login to Azure
      az login
      
      # Set default subscription (optional)
      az account set --subscription "Your Subscription Name"
      ```
      
      ## App Registration Management
      
      ### Create App Registration
      
      **Basic app registration:**
      ```bash
      az ad app create --display-name "MyApplication"
      ```
      
      **Web application with redirect URI:**
      ```bash
      az ad app create \
        --display-name "MyWebApp" \
        --web-redirect-uris "https://myapp.com/callback" \
        --sign-in-audience "AzureADMyOrg"
      ```
      
      **Single Page Application (SPA):**
      ```bash
      az ad app create \
        --display-name "MySpaApp" \
        --spa-redirect-uris "http://localhost:3000" \
        --sign-in-audience "AzureADMyOrg"
      ```
      
      **Public client (Desktop/Mobile app):**
      ```bash
      az ad app create \
        --display-name "MyDesktopApp" \
        --public-client-redirect-uris "http://localhost" \
        --sign-in-audience "AzureADMyOrg"
      ```
      
      **Multi-tenant application:**
      ```bash
      az ad app create \
        --display-name "MyMultiTenantApp" \
        --web-redirect-uris "https://myapp.com/callback" \
        --sign-in-audience "AzureADMultipleOrgs"
      ```
      
      ### Sign-in Audience Options
      
      | Value | Description |
      |-------|-------------|
      | `AzureADMyOrg` | Single tenant (default) |
      | `AzureADMultipleOrgs` | Multi-tenant (any Azure AD) |
      | `AzureADandPersonalMicrosoftAccount` | Multi-tenant + personal Microsoft accounts |
      | `PersonalMicrosoftAccount` | Personal Microsoft accounts only |
      
      ## List and Query Apps
      
      ### List all app registrations
      
      ```bash
      az ad app list --output table
      ```
      
      ### List apps with custom query
      
      ```bash
      # Filter by display name
      az ad app list --display-name "MyApp" --output table
      
      # Get specific fields
      az ad app list --query "[].{Name:displayName, AppId:appId}" --output table
      ```
      
      ### Get app details
      
      ```bash
      # By display name
      az ad app show --id $(az ad app list --display-name "MyApp" --query "[0].appId" -o tsv)
      
      # By application ID
      az ad app show --id "YOUR_APPLICATION_ID"
      ```
      
      ### Get Application (Client) ID
      
      ```bash
      APP_ID=$(az ad app list --display-name "MyApp" --query "[0].appId" -o tsv)
      echo "Application ID: $APP_ID"
      ```
      
      ### Get Object ID
      
      ```bash
      OBJECT_ID=$(az ad app list --display-name "MyApp" --query "[0].id" -o tsv)
      echo "Object ID: $OBJECT_ID"
      ```
      
      ## Update App Registration
      
      ### Add redirect URIs
      
      **Web app:**
      ```bash
      az ad app update --id $APP_ID \
        --web-redirect-uris "https://myapp.com/callback" "https://myapp.com/auth"
      ```
      
      **SPA:**
      ```bash
      az ad app update --id $APP_ID \
        --spa-redirect-uris "http://localhost:3000" "http://localhost:5000"
      ```
      
      **Public client:**
      ```bash
      az ad app update --id $APP_ID \
        --public-client-redirect-uris "http://localhost" "myapp://auth"
      ```
      
      ## Client Credentials (Secrets & Certificates)
      
      ### Create client secret
      
      ```bash
      # Create secret with default expiration
      az ad app credential reset --id $APP_ID
      
      # Create secret with custom expiration
      az ad app credential reset --id $APP_ID --years 1
      
      # Create secret with specific end date
      az ad app credential reset --id $APP_ID --end-date "2025-12-31"
      ```
      
      **Save the output:**
      ```json
      {
        "appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "password": "your-secret-value-SAVE-THIS",
        "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
      ```
      
      **⚠️ Important:** Resetting Client credential will delete all existing credentials.
      **⚠️ Important:** The secret value is only shown once. Store it securely (e.g., Azure Key Vault).
      
      ### List client credentials
      
      ```bash
      # List all credentials (secrets and certificates)
      az ad app credential list --id $APP_ID
      ```
      
      ### Delete client secret
      
      ```bash
      # Get key ID from credential list
      az ad app credential list --id $APP_ID --query "[].{KeyId:keyId, Type:type}" -o table
      
      # Delete specific credential
      az ad app credential delete --id $APP_ID --key-id "KEY_ID_HERE"
      ```
      
      ### Upload certificate
      
      ```bash
      # Upload certificate from file
      az ad app credential reset --id $APP_ID --cert "@path/to/cert.pem"
      ```
      
      ## API Permissions
      
      ### Add API permissions
      
      **Microsoft Graph User.Read:**
      ```bash
      GRAPH_RESOURCE_ID="00000003-0000-0000-c000-000000000000"  # Microsoft Graph
      USER_READ_ID="e1fe6dd8-ba31-4d61-89e7-88639da4683d"      # User.Read permission
      
      az ad app permission add --id $APP_ID \
        --api $GRAPH_RESOURCE_ID \
        --api-permissions "$USER_READ_ID=Scope"
      ```
      
      **Microsoft Graph Mail.Read (delegated):**
      ```bash
      MAIL_READ_ID="570282fd-fa5c-430d-a7fd-fc8dc98a9dca"      # Mail.Read permission
      
      az ad app permission add --id $APP_ID \
        --api $GRAPH_RESOURCE_ID \
        --api-permissions "$MAIL_READ_ID=Scope"
      ```
      
      **Microsoft Graph User.Read.All (application):**
      ```bash
      USER_READ_ALL_ID="df021288-bdef-4463-88db-98f22de89214"  # User.Read.All application permission
      
      az ad app permission add --id $APP_ID \
        --api $GRAPH_RESOURCE_ID \
        --api-permissions "$USER_READ_ALL_ID=Role"
      ```
      
      **Note:** Use `Scope` for delegated permissions, `Role` for application permissions.
      
      ### Common Permission IDs
      
      **Microsoft Graph (00000003-0000-0000-c000-000000000000):**
      
      | Permission | ID | Type |
      |------------|-----|------|
      | User.Read | e1fe6dd8-ba31-4d61-89e7-88639da4683d | Delegated |
      | User.ReadWrite | b4e74841-8e56-480b-be8b-910348b18b4c | Delegated |
      | Mail.Read | 570282fd-fa5c-430d-a7fd-fc8dc98a9dca | Delegated |
      | Mail.Send | e383f46e-2787-4529-855e-0e479a3ffac0 | Delegated |
      | Calendars.Read | 465a38f9-76ea-45b9-9f34-9e8b0d4b0b42 | Delegated |
      | User.Read.All | df021288-bdef-4463-88db-98f22de89214 | Application |
      | Directory.Read.All | 7ab1d382-f21e-4acd-a863-ba3e13f7da61 | Application |
      
      ### Grant admin consent
      
      ```bash
      # Grant admin consent for all permissions
      az ad app permission admin-consent --id $APP_ID
      ```
      
      **Note:** Admin consent is required for application permissions and some delegated permissions.
      
      ### List permissions
      
      ```bash
      az ad app permission list --id $APP_ID
      ```
      
      ### Delete permission
      
      ```bash
      # Remove specific permission
      az ad app permission delete --id $APP_ID \
        --api $GRAPH_RESOURCE_ID \
        --permission-id $USER_READ_ID
      ```
      
      ## Service Principal Management
      
      ### Create service principal
      
      ```bash
      # Create service principal for the app
      az ad sp create --id $APP_ID
      ```
      
      ### List service principals
      
      ```bash
      az ad sp list --display-name "MyApp"
      ```
      
      ### Get service principal details
      
      ```bash
      az ad sp show --id $APP_ID
      ```
      
      ### Delete service principal
      
      ```bash
      az ad sp delete --id $APP_ID
      ```
      
      ## App Roles and Claims
      
      ### Get app roles
      
      ```bash
      az ad app show --id $APP_ID --query "appRoles"
      ```
      
      ### Get optional claims
      
      ```bash
      az ad app show --id $APP_ID --query "optionalClaims"
      ```
      
      ## Owners
      
      ### List app owners
      
      ```bash
      az ad app owner list --id $APP_ID
      ```
      
      ### Add owner
      
      ```bash
      # Add user as owner
      USER_OBJECT_ID=$(az ad user show --id "user@domain.com" --query "id" -o tsv)
      az ad app owner add --id $APP_ID --owner-object-id $USER_OBJECT_ID
      ```
      
      ### Remove owner
      
      ```bash
      az ad app owner remove --id $APP_ID --owner-object-id $USER_OBJECT_ID
      ```
      
      ## Delete App Registration
      
      ```bash
      # Delete app registration (and associated service principal)
      az ad app delete --id $APP_ID
      ```
      
      ## Tenant and Identity Information
      
      ### Get tenant ID
      
      ```bash
      az account show --query tenantId -o tsv
      ```
      
      ### Get current user information
      
      ```bash
      az ad signed-in-user show
      ```
      
      ### Get user by email
      
      ```bash
      az ad user show --id "user@domain.com"
      ```
      
      ### Get user object ID
      
      ```bash
      az ad user show --id "user@domain.com" --query "id" -o tsv
      ```
      
      ### List all users
      
      ```bash
      az ad user list --output table
      ```
      
      ## Scripting Examples
      
      ### Complete app setup script
      
      ```bash
      #!/bin/bash
      
      # Variables
      APP_NAME="MyApplication"
      REDIRECT_URI="http://localhost:3000"
      
      echo "Creating app registration..."
      APP_ID=$(az ad app create \
        --display-name "$APP_NAME" \
        --spa-redirect-uris "$REDIRECT_URI" \
        --query "appId" -o tsv)
      
      echo "App created with ID: $APP_ID"
      
      echo "Adding Microsoft Graph permissions..."
      GRAPH_RESOURCE_ID="00000003-0000-0000-c000-000000000000"
      USER_READ_ID="e1fe6dd8-ba31-4d61-89e7-88639da4683d"
      
      az ad app permission add --id $APP_ID \
        --api $GRAPH_RESOURCE_ID \
        --api-permissions "$USER_READ_ID=Scope"
      
      echo "Granting admin consent..."
      az ad app permission admin-consent --id $APP_ID
      
      echo "Creating service principal..."
      az ad sp create --id $APP_ID
      
      TENANT_ID=$(az account show --query tenantId -o tsv)
      
      echo ""
      echo "App registration complete!"
      echo "Application (Client) ID: $APP_ID"
      echo "Tenant ID: $TENANT_ID"
      echo "Redirect URI: $REDIRECT_URI"
      ```
      
      ### Cleanup script
      
      ```bash
      #!/bin/bash
      
      # Delete all apps matching pattern
      az ad app list --display-name "Test*" --query "[].appId" -o tsv | while read APP_ID; do
        echo "Deleting app: $APP_ID"
        az ad app delete --id $APP_ID
      done
      ```
      
    • console-app-example.md 10.7 KB
      # Console Application Examples
      
      This document provides complete working examples of console applications that authenticate with Microsoft Entra ID using MSAL (Microsoft Authentication Library).
      
      ## Table of Contents
      
      - [C# (.NET) Example](#c-net-example)
      - [Python Example](#python-example)
      - [JavaScript (Node.js) Example](#javascript-nodejs-example)
      
      ## C# (.NET) Example
      
      ### Prerequisites
      
      ```bash
      dotnet new console -n EntraAuthConsole
      cd EntraAuthConsole
      dotnet add package Microsoft.Identity.Client
      ```
      
      ### Complete Code
      
      ```csharp
      using Microsoft.Identity.Client;
      using System;
      using System.Linq;
      using System.Threading.Tasks;
      
      namespace EntraAuthConsole
      {
          class Program
          {
              // Configuration - replace with your values
              private const string ClientId = "YOUR_APPLICATION_CLIENT_ID";
              private const string TenantId = "YOUR_TENANT_ID";
              private static readonly string[] Scopes = new[] { "User.Read" };
      
              static async Task Main(string[] args)
              {
                  try
                  {
                      // Build the MSAL client
                      var app = PublicClientApplicationBuilder
                          .Create(ClientId)
                          .WithAuthority(AzureCloudInstance.AzurePublic, TenantId)
                          .WithRedirectUri("http://localhost")
                          .Build();
      
                      // Try to get token silently from cache first
                      var accounts = await app.GetAccountsAsync();
                      AuthenticationResult result;
      
                      try
                      {
                          result = await app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
                              .ExecuteAsync();
                          Console.WriteLine("Token acquired from cache");
                      }
                      catch (MsalUiRequiredException)
                      {
                          // Interactive authentication required
                          result = await app.AcquireTokenInteractive(Scopes)
                              .WithPrompt(Prompt.SelectAccount)
                              .ExecuteAsync();
                          Console.WriteLine("Token acquired interactively");
                      }
      
                      // Display user information
                      Console.WriteLine($"\nWelcome, {result.Account.Username}!");
                      Console.WriteLine($"Token expires: {result.ExpiresOn}");
      
                      // Call Microsoft Graph API
                      await CallGraphApiAsync(result.AccessToken);
                  }
                  catch (MsalException ex)
                  {
                      Console.WriteLine($"Error acquiring token: {ex.Message}");
                  }
              }
      
              private static async Task CallGraphApiAsync(string accessToken)
              {
                  using var httpClient = new System.Net.Http.HttpClient();
                  httpClient.DefaultRequestHeaders.Authorization = 
                      new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
      
                  var response = await httpClient.GetAsync("https://graph.microsoft.com/v1.0/me");
                  
                  if (response.IsSuccessStatusCode)
                  {
                      var content = await response.Content.ReadAsStringAsync();
                      Console.WriteLine("\nUser profile from Microsoft Graph:");
                      Console.WriteLine(content);
                  }
                  else
                  {
                      Console.WriteLine($"API call failed: {response.StatusCode}");
                  }
              }
          }
      }
      ```
      
      ### Run the Application
      
      ```bash
      dotnet run
      ```
      
      ### Device Code Flow (for headless scenarios)
      
      ```csharp
      // Use this for servers or devices without a browser
      result = await app.AcquireTokenWithDeviceCode(Scopes, deviceCodeResult =>
      {
          Console.WriteLine(deviceCodeResult.Message);
          return Task.CompletedTask;
      }).ExecuteAsync();
      ```
      
      ---
      
      ## Python Example
      
      ### Prerequisites
      
      ```bash
      pip install msal requests
      ```
      
      ### Complete Code
      
      ```python
      import msal
      import requests
      import json
      
      # Configuration - replace with your values
      CLIENT_ID = "YOUR_APPLICATION_CLIENT_ID"
      TENANT_ID = "YOUR_TENANT_ID"
      AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}"
      SCOPES = ["User.Read"]
      
      def acquire_token_interactive():
          """Acquire token using interactive flow (opens browser)"""
          app = msal.PublicClientApplication(
              CLIENT_ID,
              authority=AUTHORITY
          )
          
          # Try to get token from cache first
          accounts = app.get_accounts()
          result = None
          
          if accounts:
              # Try silent acquisition
              result = app.acquire_token_silent(SCOPES, account=accounts[0])
              if result:
                  print("Token acquired from cache")
          
          if not result:
              # Interactive authentication
              result = app.acquire_token_interactive(
                  scopes=SCOPES,
                  prompt="select_account"
              )
              print("Token acquired interactively")
          
          return result
      
      def acquire_token_device_code():
          """Acquire token using device code flow (for headless scenarios)"""
          app = msal.PublicClientApplication(
              CLIENT_ID,
              authority=AUTHORITY
          )
          
          flow = app.initiate_device_flow(scopes=SCOPES)
          
          if "user_code" not in flow:
              raise Exception(f"Failed to create device flow: {flow.get('error_description')}")
          
          # Display instructions to user
          print(flow["message"])
          
          # Wait for user to complete authentication
          result = app.acquire_token_by_device_flow(flow)
          return result
      
      def call_graph_api(access_token):
          """Call Microsoft Graph API with access token"""
          headers = {
              'Authorization': f'Bearer {access_token}',
              'Content-Type': 'application/json'
          }
          
          response = requests.get(
              'https://graph.microsoft.com/v1.0/me',
              headers=headers
          )
          
          if response.status_code == 200:
              user_data = response.json()
              print("\nUser profile from Microsoft Graph:")
              print(json.dumps(user_data, indent=2))
          else:
              print(f"API call failed: {response.status_code}")
              print(response.text)
      
      def main():
          # Choose authentication method
          print("Select authentication method:")
          print("1. Interactive (opens browser)")
          print("2. Device code (for headless scenarios)")
          choice = input("Enter choice (1 or 2): ")
          
          try:
              if choice == "1":
                  result = acquire_token_interactive()
              elif choice == "2":
                  result = acquire_token_device_code()
              else:
                  print("Invalid choice")
                  return
              
              if "access_token" in result:
                  print(f"\nWelcome, {result.get('id_token_claims', {}).get('preferred_username', 'User')}!")
                  print(f"Token expires in: {result.get('expires_in')} seconds")
                  
                  # Call Microsoft Graph API
                  call_graph_api(result["access_token"])
              else:
                  print(f"Error acquiring token: {result.get('error')}")
                  print(f"Description: {result.get('error_description')}")
          
          except Exception as e:
              print(f"Error: {e}")
      
      if __name__ == "__main__":
          main()
      ```
      
      ### Run the Application
      
      ```bash
      python console_app.py
      ```
      
      ---
      
      ## JavaScript (Node.js) Example
      
      ### Prerequisites
      
      ```bash
      npm init -y
      npm install @azure/msal-node axios
      ```
      
      ### Complete Code
      
      ```javascript
      const msal = require('@azure/msal-node');
      const axios = require('axios');
      
      // Configuration - replace with your values
      const config = {
          auth: {
              clientId: "YOUR_APPLICATION_CLIENT_ID",
              authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
          }
      };
      
      const scopes = ["User.Read"];
      
      // Interactive authentication (opens browser)
      async function acquireTokenInteractive() {
          const pca = new msal.PublicClientApplication(config);
          
          const authCodeUrlParameters = {
              scopes: scopes,
              redirectUri: "http://localhost:3000",
          };
      
          // This opens the browser for authentication
          const response = await pca.acquireTokenInteractive(authCodeUrlParameters);
          return response;
      }
      
      // Device code flow (for headless scenarios)
      async function acquireTokenDeviceCode() {
          const pca = new msal.PublicClientApplication(config);
          
          const deviceCodeRequest = {
              deviceCodeCallback: (response) => {
                  console.log("\n" + response.message);
              },
              scopes: scopes,
          };
      
          const response = await pca.acquireTokenByDeviceCode(deviceCodeRequest);
          return response;
      }
      
      // Client credentials flow (service-to-service, no user)
      async function acquireTokenClientCredentials() {
          const confidentialConfig = {
              auth: {
                  clientId: "YOUR_APPLICATION_CLIENT_ID",
                  authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
                  clientSecret: "YOUR_CLIENT_SECRET", // From app registration
              }
          };
          
          const cca = new msal.ConfidentialClientApplication(confidentialConfig);
          
          const clientCredentialRequest = {
              scopes: ["https://graph.microsoft.com/.default"],
          };
      
          const response = await cca.acquireTokenByClientCredential(clientCredentialRequest);
          return response;
      }
      
      // Call Microsoft Graph API
      async function callGraphApi(accessToken) {
          const options = {
              headers: {
                  Authorization: `Bearer ${accessToken}`
              }
          };
      
          try {
              const response = await axios.get('https://graph.microsoft.com/v1.0/me', options);
              console.log('\nUser profile from Microsoft Graph:');
              console.log(JSON.stringify(response.data, null, 2));
          } catch (error) {
              console.error('API call failed:', error.response?.status, error.message);
          }
      }
      
      // Main function
      async function main() {
          console.log("Select authentication method:");
          console.log("1. Device code flow (recommended for CLI)");
          console.log("2. Client credentials (service-to-service)");
          
          // For demonstration, using device code flow
          // In production, get user input with readline or similar
          const choice = "1";
          
          try {
              let result;
              
              if (choice === "1") {
                  result = await acquireTokenDeviceCode();
              } else if (choice === "2") {
                  result = await acquireTokenClientCredentials();
              }
              
              if (result.accessToken) {
                  console.log('\nAuthentication successful!');
                  console.log(`Token expires: ${new Date(result.expiresOn)}`);
                  
                  // Call Microsoft Graph API
                  await callGraphApi(result.accessToken);
              } else {
                  console.error('Failed to acquire token');
              }
          } catch (error) {
              console.error('Error:', error.message);
          }
      }
      
      main();
      ```
      
      ### Run the Application
      
      ```bash
      node console_app.js
      ```
      
      ## Next Steps
      
      - Review [oauth-flows.md](oauth-flows.md) for flow details
      - See [api-permissions.md](api-permissions.md) for permission setup
      - Check [troubleshooting.md](troubleshooting.md) for common issues
      
      ## Additional Resources
      
      - [MSAL Libraries](https://learn.microsoft.com/entra/msal/)
      
    • first-app-registration.md 7.2 KB
      # First App Registration - Step-by-Step Guide
      
      This guide walks you through creating your first Microsoft Entra app registration from scratch.
      
      ## Overview
      
      You'll learn how to:
      1. Create an app registration in Azure Portal
      2. Configure authentication settings
      3. Add API permissions
      4. Create client credentials
      5. Test the authentication flow
      
      ## Prerequisites
      
      - Azure subscription (free tier works)
      - Azure Portal access: https://portal.azure.com
      - Basic understanding of your application type (web, mobile, service)
      
      ## Step 1: Navigate to App Registrations
      
      1. Open [Azure Portal](https://portal.azure.com)
      2. Search for **"Microsoft Entra ID"**
      3. In the left menu, click **"App registrations"**
      4. Click **"+ New registration"** at the top
      
      ## Step 2: Register Your Application
      
      You'll see a form with several fields:
      
      ### Application Name
      - **What to enter:** A descriptive name for your app
      - **Example:** "My First Console App" or "Product Inventory API"
      - **Tip:** Use a name that clearly identifies the purpose
      
      ### Supported Account Types
      
      Choose who can use your application:
      
      | Option | When to Use |
      |--------|-------------|
      | **Accounts in this organizational directory only (Single tenant)** | Only users from the same tenant of this app registration need access |
      | **Accounts in any organizational directory (Multi-tenant)** | Users from multiple organization tenants need access |
      | **Accounts in any organizational directory + Personal Microsoft accounts** | Users from multiple organization tenants and MSA users need access |
      | **Personal Microsoft accounts only** | Only MSA users need access |
      
      **Note:** Once selected, users whose account type is not allowed will get errors when trying to get access token for the app registration.
      
      ### Redirect URI (optional)
      
      The redirect URI is where authentication responses are sent.
      
      **Platform:** Select the type:
      - **Web** - Server-side web apps
      - **Single-page application (SPA)** - React, Angular, Vue apps
      - **Public client/native** - Mobile, desktop, console apps
      
      **URI examples:**
      - Web app: `https://localhost:5001/signin-oidc`
      - SPA: `http://localhost:3000`
      - Console/Desktop: `http://localhost`
      
      **For your first app:** Select **"Public client/native"** and enter `http://localhost`
      
      ### Click "Register"
      
      After clicking, you'll be redirected to your app's overview page.
      
      ## Step 3: Save Important Information
      
      On the **Overview** page, you'll see critical information. **Copy and save these values:**
      
      ### Application (client) ID
      - **What it is:** Unique identifier for your app
      - **Format:** `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` (GUID)
      - **When you need it:** Every time your app authenticates
      - **Where to save:** Environment variables, configuration file
      
      ### Directory (tenant) ID
      - **What it is:** Unique identifier for your Azure AD tenant
      - **Format:** `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` (GUID)
      - **When you need it:** Constructing authentication URLs
      
      ### Example values to save:
      ```bash
      # Save these in a secure location
      APPLICATION_CLIENT_ID="12345678-1234-1234-1234-123456789012"
      TENANT_ID="87654321-4321-4321-4321-210987654321"
      ```
      
      ## Step 4: Configure Authentication (Optional)
      
      Click **"Authentication"** in the left menu.
      
      ### Advanced Settings
      
      **Allow public client flows:**
      - **What it is:** Enables device code flow, resource owner password flow
      - **For console apps:** Turn this **ON**
      - **For web apps:** Keep **OFF**
      
      ### Supported account types
      
      You can change this later if needed.
      
      ### Logout URL (optional)
      
      Where to redirect users after logout.
      
      **Click "Save"** at the top if you made changes.
      
      ## Step 5: Add API Permissions
      
      Click **"API permissions"** in the left menu.
      
      ### Default Permission
      
      You'll see one default permission:
      - **Microsoft Graph → User.Read (Delegated)**
      
      This allows your app to read the signed-in user's profile.
      
      ### Add More Permissions
      
      1. Click **"+ Add a permission"**
      2. Select **"Microsoft Graph"**
      3. Choose **"Delegated permissions"** (for user context)
      4. Search for and select permissions you need:
         - **User.Read** - Read user profile (already added)
         - **Mail.Read** - Read user's mail
         - **Calendars.Read** - Read user's calendar
      
      5. Click **"Add permissions"**
      
      ### Admin Consent
      
      Some permissions require admin consent:
      - If you're an admin: Click **"Grant admin consent for [Your Org]"**
      - If you're not: Ask your admin to grant consent
      
      **Status indicator:**
      - ✅ Green checkmark = Granted
      - ⚠️ Yellow warning = Not granted (may still work for user consent)
      
      ## Step 6: Create Client Secret (If Needed)
      
      **Skip this if:** You're building a desktop/mobile/console app (public client)
      
      **Do this if:** You're building a web app, API, or service (confidential client)
      
      1. Click **"Certificates & secrets"** in the left menu
      2. Click **"+ New client secret"**
      3. Enter a description: "Development Secret"
      4. Choose expiration:
         - **Recommended for development:** 6 months
         - **For production:** 12-24 months (set up rotation)
      5. Click **"Add"**
      
      **⚠️ CRITICAL:** Copy the secret **Value** immediately!
      - It's only shown once
      - You cannot retrieve it later
      - If you lose it, create a new one
      
      ```bash
      # Save this securely (example)
      CLIENT_SECRET="abc123~defGHI456jklMNO789pqrSTU"
      ```
      
      **Security tips:**
      - Never commit secrets to source control
      - Use Azure Key Vault for production
      - Use environment variables for development
      
      ## Step 7: Test Your App Registration
      
      ### Option A: Quick Test with Azure CLI
      
      ```bash
      # Set your values
      CLIENT_ID="your-client-id-here"
      TENANT_ID="your-tenant-id-here"
      
      # Interactive login
      az login --scope "https://graph.microsoft.com/.default"
      
      # Get an access token
      az account get-access-token --resource "https://graph.microsoft.com"
      ```
      
      ### Option B: Test with MSAL Library
      
      See the complete code example in [console-app-example.md](console-app-example.md)
      
      ### Expected Results
      
      **Success:**
      - Browser opens for authentication (or device code shown)
      - You authenticate with your Azure AD account
      - Access token is returned
      - You can call Microsoft Graph API
      
      **Common first-time issues:**
      - Redirect URI mismatch → Double-check URI in Authentication settings
      - Insufficient permissions → Add required API permissions
      - User consent required → Grant admin consent or user must consent
      
      **Tip:** Once you get the access token, you can use [jwt.ms](https://jwt.ms) to decode it and inspect its claims.
      
      ## Step 8: Review Configuration
      
      ### Checklist
      
      - ✅ App registered with clear name
      - ✅ Application ID and Tenant ID saved securely
      - ✅ Redirect URI configured correctly
      - ✅ API permissions added
      - ✅ Admin consent granted (if required)
      - ✅ Client secret created and saved (if needed)
      - ✅ Authentication tested successfully
      
      ## Next Steps
      
      - In your client app, implement the OAuth flow to acquire access tokens for your app registration.
      - In your server app, implement token validation to protect your resources.
      
      ## Troubleshooting
      
      ### Redirect URI mismatch"
      
      **Solution:**
      - Check Authentication → Redirect URIs
      - Ensure exact match (case-sensitive, trailing slash matters)
      - Ensure correct platform (Web vs SPA vs Public client)
      
      ### User consent required
      
      **Solution:**
      - Grant admin consent in API permissions
      - Or have user consent during first login
      
      ## Additional Resources
      
      - [Microsoft Entra ID Documentation](https://learn.microsoft.com/en-us/entra/identity-platform/)
      
    • oauth-flows.md 9.3 KB
      # OAuth 2.0 Flows
      
      This document provides an illustration of OAuth 2.0 authentication flows supported by Microsoft Entra ID.
      
      **Note:** All the following implementation steps are for illustration purposes. It's always recommended to use a library to handle the authentication flow.
      
      ## Authorization Code Flow
      
      ### Flow Steps
      
      ```
      1. User → App: Navigate to app's web UI
      2. App → User: Redirect to Microsoft login
      3. User → Entra ID: Authenticate & consent
      4. Entra ID → App: Authorization code (via redirect URI)
      5. App → Entra ID: Exchange code for tokens (with client secret)
      6. Entra ID → App: Access token + refresh token + ID token
      7. App → API: Call API with access token
      ```
      
      ### Implementation Steps
      
      #### 1. Build Authorization URL
      
      ```
      https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
        client_id={application_id}
        &response_type=code
        &redirect_uri={redirect_uri}
        &response_mode=query
        &scope={scopes}
        &state={random_state}
      ```
      
      **Parameters:**
      - `tenant`: Your tenant ID or `common` for multi-tenant
      - `client_id`: Application (client) ID from app registration
      - `redirect_uri`: Must match exactly what's registered
      - `scope`: Space-separated permissions (e.g., `openid profile User.Read`)
      - `state`: Random value to prevent CSRF attacks
      
      #### 2. User Authenticates
      
      User is redirected to Microsoft login page, authenticates, and grants consent.
      
      #### 3. Receive Authorization Code
      
      App receives callback at redirect URI:
      ```
      https://your-app.com/callback?
        code={authorization_code}
        &state={state_value}
      ```
      
      **Validation:**
      - Verify `state` matches what you sent
      - Extract `code` parameter
      
      #### 4. Exchange Code for Tokens
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &scope={scopes}
      &code={authorization_code}
      &redirect_uri={redirect_uri}
      &grant_type=authorization_code
      &client_secret={client_secret}
      ```
      
      **Response:**
      ```json
      {
        "access_token": "eyJ0eXAi...",
        "token_type": "Bearer",
        "expires_in": 3600,
        "refresh_token": "M.R3_BAY...",
        "id_token": "eyJ0eXAi..."
      }
      ```
      
      #### 5. Use Access Token
      
      ```http
      GET https://graph.microsoft.com/v1.0/me
      Authorization: Bearer {access_token}
      ```
      
      ## Authorization Code Flow with PKCE
      
      PKCE (Proof Key for Code Exchange) adds security for public clients that cannot securely store a client secret.
      
      ### Flow Steps
      
      ```
      1. App: Generate code verifier (random string)
      2. App: Generate code challenge (SHA256 hash of verifier)
      3. App → Entra ID: Authorization request with code challenge
      4. User → Entra ID: Authenticate & consent
      5. Entra ID → App: Authorization code
      6. App → Entra ID: Exchange code + code verifier for token
      7. Entra ID: Validates verifier matches challenge
      8. Entra ID → App: Access token + ID token
      ```
      
      ### Implementation Steps
      
      #### 1. Generate PKCE Values
      
      **Code Verifier:** 43-128 character random string
      ```javascript
      // JavaScript example
      const codeVerifier = generateRandomString(128);
      ```
      
      **Code Challenge:** Base64URL-encoded SHA256 hash of verifier
      ```javascript
      const codeChallenge = base64URLEncode(sha256(codeVerifier));
      ```
      
      #### 2. Build Authorization URL
      
      ```
      https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
        client_id={application_id}
        &response_type=code
        &redirect_uri={redirect_uri}
        &scope={scopes}
        &state={state}
        &code_challenge={code_challenge}
        &code_challenge_method=S256
      ```
      
      #### 3. Exchange Code for Tokens (No Secret)
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &scope={scopes}
      &code={authorization_code}
      &redirect_uri={redirect_uri}
      &grant_type=authorization_code
      &code_verifier={code_verifier}
      ```
      
      ## Client Credentials Flow
      
      ### Flow Steps
      
      ```
      1. App → Entra ID: Request token with client ID + secret
      2. Entra ID: Validate credentials
      3. Entra ID → App: Access token (application permissions)
      4. App → API: Call API with token
      ```
      
      ### Implementation Steps
      
      #### 1. Configure Application Permissions
      
      In app registration:
      1. Go to "API permissions"
      2. Add **Application** permissions (not delegated)
      3. Grant admin consent (required for app permissions)
      
      **Example permissions:**
      - `User.Read.All` (application) - Read all users
      - `Directory.Read.All` (application) - Read directory
      
      #### 2. Request Access Token
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &scope=https://graph.microsoft.com/.default
      &client_secret={client_secret}
      &grant_type=client_credentials
      ```
      
      **Parameters:**
      - `scope`: Use `{resource}/.default` format
        - For Microsoft Graph: `https://graph.microsoft.com/.default`
        - For your API: `api://{api_app_id}/.default`
      
      **Response:**
      ```json
      {
        "access_token": "eyJ0eXAi...",
        "token_type": "Bearer",
        "expires_in": 3599
      }
      ```
      
      #### 3. Use Access Token
      
      ```http
      GET https://graph.microsoft.com/v1.0/users
      Authorization: Bearer {access_token}
      ```
      
      ## Device Code Flow
      
      **Use for:** Devices without browsers (IoT, CLIs), headless environments
      
      ### Flow Steps
      
      ```
      1. App → Entra ID: Request device code
      2. Entra ID → App: Device code + user code + verification URL
      3. App → User: Display code and URL
      4. User: Opens URL on another device, enters code
      5. User → Entra ID: Authenticates & consents
      6. App → Entra ID: Poll for token
      7. Entra ID → App: Access token (after user completes auth)
      ```
      
      ### Implementation Steps
      
      #### 1. Request Device Code
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/devicecode
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &scope={scopes}
      ```
      
      **Response:**
      ```json
      {
        "user_code": "GTHK-QPMN",
        "device_code": "GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8",
        "verification_uri": "https://microsoft.com/devicelogin",
        "expires_in": 900,
        "interval": 5,
        "message": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code GTHK-QPMN to authenticate."
      }
      ```
      
      #### 2. Display Instructions to User
      
      ```
      To sign in, open https://microsoft.com/devicelogin
      and enter code: GTHK-QPMN
      ```
      
      #### 3. Poll for Token
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &grant_type=urn:ietf:params:oauth:grant-type:device_code
      &device_code={device_code}
      ```
      
      **Poll every 5 seconds (use `interval` from response)**
      
      **Pending Response (user hasn't completed auth yet):**
      ```json
      {
        "error": "authorization_pending",
        "error_description": "AADSTS70016: Pending end-user authorization..."
      }
      ```
      
      **Success Response:**
      ```json
      {
        "access_token": "eyJ0eXAi...",
        "token_type": "Bearer",
        "expires_in": 3600,
        "refresh_token": "M.R3_BAY...",
        "id_token": "eyJ0eXAi..."
      }
      ```
      
      ## Refresh Token Flow
      
      **Use for:** Refreshing expired access tokens without re-authentication
      
      ### When to Refresh
      
      - Access tokens typically expire in 1 hour
      - Refresh tokens are long-lived (14-90 days)
      - Refresh before access token expires for seamless UX
      
      ### Implementation
      
      ```http
      POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
      Content-Type: application/x-www-form-urlencoded
      
      client_id={application_id}
      &scope={scopes}
      &refresh_token={refresh_token}
      &grant_type=refresh_token
      &client_secret={client_secret}
      ```
      
      **Note:** `client_secret` only required for confidential clients
      
      **Response:**
      ```json
      {
        "access_token": "eyJ0eXAi...",
        "token_type": "Bearer",
        "expires_in": 3600,
        "refresh_token": "M.R3_BAY...",
        "id_token": "eyJ0eXAi..."
      }
      ```
      
      **Important:** New refresh token is returned; use it for next refresh
      
      ## Token Types
      
      ### Access Token
      
      - Used to call APIs
      - Contains claims (user ID, permissions, etc.)
      - Short-lived (typically 1 hour)
      - Format: JWT (JSON Web Token)
      
      **Sample claims:**
      ```json
      {
        "aud": "https://graph.microsoft.com",
        "iss": "https://sts.windows.net/{tenant}/",
        "sub": "{user_object_id}",
        "scp": "User.Read Mail.Read",
        "exp": 1680000000
      }
      ```
      
      ### Refresh Token
      
      - Used to get new access tokens
      - Long-lived (days to months)
      - Opaque string (not JWT)
      - Single-use (new one issued with each refresh)
      
      ### ID Token
      
      - Contains user identity information
      - Used by the app to authenticate user
      - Format: JWT
      
      **Sample claims:**
      ```json
      {
        "sub": "{user_object_id}",
        "name": "Jane Doe",
        "preferred_username": "jane@contoso.com",
        "email": "jane@contoso.com",
        "oid": "{object_id}"
      }
      ```
      
      ## Scopes and Permissions
      
      ### Scope Format
      
      **Microsoft Graph:**
      ```
      https://graph.microsoft.com/User.Read
      https://graph.microsoft.com/Mail.Send
      ```
      
      **Custom API:**
      ```
      api://{api_application_id}/access_as_user
      ```
      
      ## Security Considerations
      
      | Practice | Why |
      |----------|-----|
      | **Use state parameter** | Prevents CSRF attacks |
      | **Use PKCE for public clients** | Prevents authorization code interception |
      | **Validate tokens** | Verify signature, issuer, audience, expiration |
      | **Use HTTPS only** | Protect tokens in transit |
      | **Store tokens securely** | Use secure storage, never in localStorage for sensitive apps |
      | **Implement token refresh** | Seamless UX without repeated logins |
      | **Handle token expiration** | Gracefully refresh or re-authenticate |
      | **Minimal scope principle** | Request only necessary permissions |
      
      ## Additional Resources
      
      [OAuth 2.0 spec](https://www.rfc-editor.org/rfc/rfc6749)
    • troubleshooting.md 7.4 KB
      # Troubleshooting Microsoft Entra App Registration
      
      This guide helps you diagnose and fix common issues with app registrations and authentication.
      
      ## Table of Contents
      
      - [Authentication Errors](#authentication-errors)
      - [Token Issues](#token-issues)
      - [Permission Problems](#permission-problems)
      - [Redirect URI Issues](#redirect-uri-issues)
      - [Application Configuration](#application-configuration)
      - [Debugging Tools](#debugging-tools)
      
      ## Authentication Errors
      
      ### Redirect URI Mismatch
      
      **Error message:**
      ```
      AADSTS50011: The redirect URI 'http://localhost:3000' specified in the request 
      does not match the redirect URIs configured for the application.
      ```
      
      **Cause:** The redirect URI in your authentication request doesn't exactly match what's registered.
      
      **Solutions:**
      
      1. **Check exact match** (case-sensitive, trailing slash matters):
         ```
         Registered: https://myapp.com/callback
         Request:    https://myapp.com/callback/  ❌ (trailing slash)
         Request:    https://MyApp.com/callback   ❌ (case difference)
         Request:    https://myapp.com/callback   ✅
         ```
      
      2. **Add URI to app registration:**
         ```bash
         # Portal: Authentication → Add redirect URI
         # CLI:
         az ad app update --id $APP_ID \
           --web-redirect-uris "http://localhost:3000" "https://myapp.com/callback"
         ```
      
      3. **Check platform type:**
         - Web URIs go in "Web" platform
         - SPA URIs go in "Single-page application"
         - Desktop/mobile URIs go in "Public client/native"
      
      ### Invalid Client Secret
      
      **Error message:**
      ```
      AADSTS7000215: Invalid client secret provided. 
      Ensure the secret being sent in the request is the client secret value, not the client secret ID.
      ```
      
      **Causes:**
      - Client secret expired
      - Wrong secret value (copied secret ID instead of value)
      - Secret doesn't match app registration
      
      **Solutions:**
      
      1. **Check expiration:**
         ```bash
         az ad app credential list --id $APP_ID
         ```
      2. **Create new secret:**
         ```bash
         az ad app credential reset --id $APP_ID --years 1
         ```
         Copy the `password` value (not the `keyId`)
      
      ### User Consent Required
      
      **Error message:**
      ```
      AADSTS65001: The user or administrator has not consented to use the application
      ```
      
      **Causes:**
      - Application permissions require admin consent
      - User hasn't consented to delegated permissions
      - Consent was revoked
      
      **Solutions:**
      
      1. **Grant admin consent (if admin):**
         ```bash
         az ad app permission admin-consent --id $APP_ID
         ```
      
      2. **Request user consent (interactive flow):**
         This requires the client app to have access to UI such as browser, terminal window, etc. Follow the best practices of your client app to implement the interactive flow.
      
      3. **Check API permissions in portal:**
         - Ensure permissions are added
         - Look for green checkmarks (granted)
         - Yellow warning means not granted
      
      ### Grant Declined
      
      **Error message:**
      ```
      AADSTS70000: The request was denied because one or more permissions have been declined
      ```
      
      **Cause:** User or admin explicitly denied consent.
      
      **Solutions:**
      
      1. **Re-request with explanation:**
         - Explain why permissions are needed
         - Request only necessary permissions
      
      2. **Check if admin consent is required:**
         - Some organizations disable user consent
         - Contact your admin to grant consent
      
      3. **Reduce permission scope:**
         - Request minimal permissions initially
         - Use incremental consent for additional features
      
      ### Application Not Found
      
      **Error message:**
      ```
      AADSTS700016: Application with identifier '{app-id}' was not found in the directory
      ```
      
      **Causes:**
      - Wrong application ID
      - Wrong tenant ID
      - Service principal not created
      - App in different tenant
      
      **Solutions:**
      
      1. **Verify application ID:**
         ```bash
         az ad app list --display-name "MyApp" --query "[].{Name:displayName, AppId:appId}"
         ```
      
      2. **Verify tenant ID:**
         ```bash
         az account show --query tenantId -o tsv
         ```
      
      ### Application Doesn't have a Service Principal
      
      **Error message:**
      ```
      The app is trying to access a service 'your_app_id'(your_app_name) that your organization 'your_tenant_id' lacks a service principal for
      ```
      
      **Causes:**
      - Your tenant is not configured to automatically provision the service principal for app registrations in it.
      
      **Solutions:**
      
      1. **Create service principal:**
         ```bash
         az ad sp create --id $APP_ID
         ```
      
      ### Missing Required Field
      
      **Error message:**
      ```
      AADSTS90014: The required field 'client_id' is missing from the request
      ```
      
      This can happen if the client you are using isn't compatible with Entra. Consult the owner of your client app to see if it supports Entra.
      
      ## Token Issues
      
      Unless the the access token is encrypted, you can decode and view its claims securely at https://jwt.ms. **Don't** use any other website to decode an access token. Compare the claims in the token with the app registration's configuration to identify issues.
      
      ## Debugging Tools
      
      ### JWT Token Decoder
      
      **Tool:** https://jwt.ms
      
      **How to use:**
      1. Copy your access token
      2. Paste into jwt.ms
      3. Review claims:
         - `aud` - Audience (should match your API)
         - `iss` - Issuer (should be login.microsoftonline.com)
         - `scp` - Delegated permissions
         - `roles` - Application permissions
         - `exp` - Expiration timestamp
         - `oid` - User object ID
      
      ---
      
      ### Fiddler
      
      **Use for:** Inspecting HTTP requests/responses
      
      **What to check:**
      - Authorization header format: `Bearer {token}`
      - Token is being sent
      - Response status codes and error messages
      
      ### Entra Sign-in Logs
      
      **Access:** Azure Portal → Microsoft Entra ID → Sign-in logs
      
      **What to check:**
      - Failed sign-in attempts
      - Error codes and messages
      - User consent status
      - Conditional Access policy failures
      
      ## Common Error Codes Reference
      
      | Error Code | Meaning | Common Cause |
      |------------|---------|--------------|
      | AADSTS50011 | Redirect URI mismatch | URI not registered or doesn't match |
      | AADSTS50020 | Invalid tenant | Wrong tenant in authority URL |
      | AADSTS50034 | User not found | User doesn't exist in tenant |
      | AADSTS50053 | Account locked | Too many failed attempts |
      | AADSTS50055 | Password expired | User needs to reset password |
      | AADSTS50057 | Account disabled | User account disabled |
      | AADSTS50058 | Silent sign-in failed | Interactive auth required |
      | AADSTS50059 | Tenant not found | Invalid tenant ID |
      | AADSTS65001 | Consent required | User/admin hasn't consented |
      | AADSTS70000 | Grant declined | User denied consent |
      | AADSTS70001 | App disabled | App registration disabled |
      | AADSTS700016 | App not found | Invalid app ID or wrong tenant |
      | AADSTS7000215 | Invalid client secret | Wrong/expired secret |
      | AADSTS90014 | Missing field | Required parameter not sent |
      | AADSTS90072 | Consent needed | Admin consent required |
      
      ## Best Practices for Troubleshooting
      
      ### Systematic Approach
      
      1. **Collect information:**
         - Exact error message and code
         - When it started happening
         - What changed recently
         - Environment (dev/test/prod)
      
      2. **Check basics first:**
         - App ID and tenant ID correct
         - Permissions added and consented
         - Redirect URIs configured
         - Secrets/certificates valid
      
      3. **Use debugging tools:**
         - Decode tokens (jwt.ms)
         - Check sign-in logs
         - Enable MSAL logging
         - Use network inspector
      
      4. **Test incrementally:**
         - Test with minimal permissions
         - Add permissions one at a time
         - Test different flows separately
      
      ## Getting Help
      
      ### Microsoft Resources
      
      - [Microsoft Q&A](https://learn.microsoft.com/answers/)
      - [Microsoft Identity Platform Documentation](https://learn.microsoft.com/entra/identity-platform/)
      
  • SKILL.md 8 KB
    ---
    name: entra-app-registration
    description: "Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance."
    license: MIT
    metadata:
      author: Microsoft
      version: "1.2.1"
    ---
    
    ## Overview
    
    Microsoft Entra ID (formerly Azure Active Directory) is Microsoft's cloud-based identity and access management service. App registrations allow applications to authenticate users and access Azure resources securely.
    
    ### Key Concepts
    
    | Concept | Description |
    |---------|-------------|
    | **App Registration** | Configuration that allows an app to use Microsoft identity platform |
    | **Application (Client) ID** | Unique identifier for your application |
    | **Tenant ID** | Unique identifier for your Azure AD tenant/directory |
    | **Client Secret** | Password for the application (confidential clients only) |
    | **Redirect URI** | URL where authentication responses are sent |
    | **API Permissions** | Access scopes your app requests |
    | **Service Principal** | Identity created in your tenant when you register an app |
    
    ### Application Types
    
    | Type | Use Case |
    |------|----------|
    | **Web Application** | Server-side apps, APIs |
    | **Single Page App (SPA)** | JavaScript/React/Angular apps |
    | **Mobile/Native App** | Desktop, mobile apps |
    | **Daemon/Service** | Background services, APIs |
    
    ## Core Workflow
    
    ### Step 1: Register the Application
    
    Create an app registration in the Azure portal or using Azure CLI.
    
    **Portal Method:**
    1. Navigate to Azure Portal → Microsoft Entra ID → App registrations
    2. Click "New registration"
    3. Provide name, supported account types, and redirect URI
    4. Click "Register"
    
    **CLI Method:** See [references/cli-commands.md](references/cli-commands.md)
    **IaC Method:** See [references/BICEP-EXAMPLE.bicep](references/BICEP-EXAMPLE.bicep)
    
    It's highly recommended to use the IaC to manage Entra app registration if you already use IaC in your project, need a scalable solution for managing lots of app registrations or need fine-grained audit history of the configuration changes. 
    
    ### Step 2: Configure Authentication
    
    Set up authentication settings based on your application type.
    
    - **Web Apps**: Add redirect URIs, enable ID tokens if needed
    - **SPAs**: Add redirect URIs, enable implicit grant flow if necessary
    - **Mobile/Desktop**: Use `http://localhost` or custom URI scheme
    - **Services**: No redirect URI needed for client credentials flow
    
    ### Step 3: Configure API Permissions
    
    Grant your application permission to access Microsoft APIs or your own APIs.
    
    **Common Microsoft Graph Permissions:**
    - `User.Read` - Read user profile
    - `User.ReadWrite.All` - Read and write all users
    - `Directory.Read.All` - Read directory data
    - `Mail.Send` - Send mail as a user
    
    **Details:** See [references/api-permissions.md](references/api-permissions.md)
    
    ### Step 4: Create Client Credentials (if needed)
    
    For confidential client applications (web apps, services), create a client secret, certificate or federated identity credential.
    
    **Client Secret:**
    - Navigate to "Certificates & secrets"
    - Create new client secret
    - Copy the value immediately (only shown once)
    - Store securely (Key Vault recommended)
    
    **Certificate:** For production environments, use certificates instead of secrets for enhanced security. Upload certificate via "Certificates & secrets" section.
    
    **Federated Identity Credential:** For dynamically authenticating the confidential client to Entra platform.
    
    ### Step 5: Implement OAuth Flow
    
    Integrate the OAuth flow into your application code.
    
    **See:**
    - [references/oauth-flows.md](references/oauth-flows.md) - OAuth 2.0 flow details
    - [references/console-app-example.md](references/console-app-example.md) - Console app implementation
    
    ## Common Patterns
    
    ### Pattern 1: First-Time App Registration
    
    Walk user through their first app registration step-by-step.
    
    **Required Information:**
    - Application name
    - Application type (web, SPA, mobile, service)
    - Redirect URIs (if applicable)
    - Required permissions
    
    **Script:** See [references/first-app-registration.md](references/first-app-registration.md)
    
    ### Pattern 2: Console Application with User Authentication
    
    Create a .NET/Python/Node.js console app that authenticates users.
    
    **Required Information:**
    - Programming language (C#, Python, JavaScript, etc.)
    - Authentication library (MSAL recommended)
    - Required permissions
    
    **Example:** See [references/console-app-example.md](references/console-app-example.md)
    
    ### Pattern 3: Service-to-Service Authentication
    
    Set up daemon/service authentication without user interaction.
    
    **Required Information:**
    - Service/app name
    - Target API/resource
    - Whether to use secret or certificate
    
    **Implementation:** Use Client Credentials flow (see [references/oauth-flows.md#client-credentials-flow](references/oauth-flows.md#client-credentials-flow))
    
    ## MCP Tools and CLI
    
    ### Azure CLI Commands
    
    | Command | Purpose |
    |---------|---------|
    | `az ad app create` | Create new app registration |
    | `az ad app list` | List app registrations |
    | `az ad app show` | Show app details |
    | `az ad app permission add` | Add API permission |
    | `az ad app credential reset` | Generate new client secret |
    | `az ad sp create` | Create service principal |
    
    **Complete reference:** See [references/cli-commands.md](references/cli-commands.md)
    
    ### Microsoft Authentication Library (MSAL)
    
    MSAL is the recommended library for integrating Microsoft identity platform.
    
    **Supported Languages:**
    - .NET/C# - `Microsoft.Identity.Client`
    - JavaScript/TypeScript - `@azure/msal-browser`, `@azure/msal-node`
    - Python - `msal`
    
    **Examples:** See [references/console-app-example.md](references/console-app-example.md)
    
    ## Security Best Practices
    
    | Practice | Recommendation |
    |----------|---------------|
    | **Never hardcode secrets** | Use environment variables, Azure Key Vault, or managed identity |
    | **Rotate secrets regularly** | Set expiration, automate rotation |
    | **Use certificates over secrets** | More secure for production |
    | **Least privilege permissions** | Request only required API permissions |
    | **Enable MFA** | Require multi-factor authentication for users |
    | **Use managed identity** | For Azure-hosted apps, avoid secrets entirely |
    | **Validate tokens** | Always validate issuer, audience, expiration |
    | **Use HTTPS only** | All redirect URIs must use HTTPS (except localhost) |
    | **Monitor sign-ins** | Use Entra ID sign-in logs for anomaly detection |
    
    ## SDK Quick References
    
    - **Azure Identity**: [Python](references/sdk/azure-identity-py.md) | [.NET](references/sdk/azure-identity-dotnet.md) | [TypeScript](references/sdk/azure-identity-ts.md) | [Java](references/sdk/azure-identity-java.md) | [Rust](references/sdk/azure-identity-rust.md)
    - **Key Vault (secrets)**: [Python](references/sdk/azure-keyvault-py.md) | [TypeScript](references/sdk/azure-keyvault-secrets-ts.md)
    - **Auth Events**: [.NET](references/sdk/microsoft-azure-webjobs-extensions-authentication-events-dotnet.md)
    
    ## References
    
    - [OAuth Flows](references/oauth-flows.md) - Detailed OAuth 2.0 flow explanations
    - [CLI Commands](references/cli-commands.md) - Azure CLI reference for app registrations
    - [Console App Example](references/console-app-example.md) - Complete working examples
    - [First App Registration](references/first-app-registration.md) - Step-by-step guide for beginners
    - [API Permissions](references/api-permissions.md) - Understanding and configuring permissions
    - [Troubleshooting](references/troubleshooting.md) - Common issues and solutions
    
    ## External Resources
    
    - [Microsoft Identity Platform Documentation](https://learn.microsoft.com/entra/identity-platform/)
    - [OAuth 2.0 and OpenID Connect protocols](https://learn.microsoft.com/entra/identity-platform/v2-protocols)
    - [MSAL Documentation](https://learn.microsoft.com/entra/msal/)
    - [Microsoft Graph API](https://learn.microsoft.com/graph/)
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related