authentication_troubleshooting - mamoorkhan/glasslewis GitHub Wiki

Authentication Troubleshooting Guide

This guide helps you diagnose and fix common authentication issues with Azure Entra External ID integration.

🔍 Quick Diagnosis

Use this decision tree to quickly identify your issue:

flowchart TD
    A[Authentication Issue] --> B{Where does it fail?}
    B -->|Login redirect| C[Redirect Issues]
    B -->|After login| D[Token Issues]
    B -->|API calls| E[CORS/Authorization Issues]
    B -->|Local development| F[Configuration Issues]
    
    C --> C1[Check redirect URIs]
    D --> D1[Check token configuration]
    E --> E1[Check CORS policy]
    F --> F1[Check environment setup]
Loading

🚨 Common Error Messages & Solutions

AADSTS50011: Reply URL Mismatch

Error Message:

AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application

Causes & Solutions:

  1. Redirect URI not registered

    # Check current redirect URIs
    az ad app show --id "your-client-id" --query "spa.redirectUris"

    Fix: Add missing URI in Azure Portal:

    • App Registration → Authentication → Add URI
    • Ensure exact match (including HTTP/HTTPS and trailing slashes)
  2. Case sensitivity issues

    ❌ Wrong: http://localhost:4200/
    ✅ Correct: http://localhost:4200
    
  3. Development vs Production URLs

    // Check your environment.ts file
    export const environment = {
      msalConfig: {
        auth: {
          redirectUri: 'http://localhost:4200' // Must match Azure registration
        }
      }
    };

AADSTS65001: User or Administrator Not Consented

Error Message:

AADSTS65001: The user or administrator has not consented to use the application

Solutions:

  1. Grant Admin Consent

    • Azure Portal → App Registration → API permissions
    • Click "Grant admin consent for [Organization]"
    • Verify green checkmarks appear
  2. Check API Permissions

    Required permissions for client app:
    ✅ API://your-api-id/Company.Read
    ✅ API://your-api-id/Company.ReadWrite
    
  3. Verify Scopes in Code

    // Angular: Check your MSAL configuration
    export const environment = {
      apiConfig: {
        scopes: ['api://your-api-id/Company.Read'],
        uri: 'https://localhost:5001/api/v1/'
      }
    };

AADSTS700016: Application Not Found

Error Message:

AADSTS700016: Application with identifier 'xxx' was not found in the directory

Solutions:

  1. Verify Client ID

    # Check if app exists
    az ad app show --id "your-client-id"
  2. Check Tenant Context

    • Ensure you're in the correct Azure tenant
    • Verify tenant ID in configuration matches app registration tenant
  3. Verify Environment Configuration

    // Check environment.ts
    export const environment = {
      msalConfig: {
        auth: {
          clientId: 'correct-client-id-here',
          authority: 'https://your-tenant.ciamlogin.com/'
        }
      }
    };

🌐 CORS Issues

Symptoms

  • Authentication works but API calls fail
  • Browser console shows CORS errors
  • Access-Control-Allow-Origin errors

Solutions

  1. Update API CORS Configuration

    // Program.cs or Startup.cs
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("AllowedOrigins", policy =>
        {
            policy.WithOrigins(
                "http://localhost:4200",        // Local development
                "https://your-app.azurestaticapps.net" // Production
            )
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
        });
    });
    
    app.UseCors("AllowedOrigins");
  2. Check appsettings.json

    {
      "AllowedOrigins": [
        "http://localhost:4200",
        "https://your-production-domain.com"
      ]
    }
  3. Verify Angular HTTP Interceptor

    // Check if Authorization header is being sent
    export class AuthInterceptor implements HttpInterceptor {
      intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Ensure Bearer token is added
        const authReq = req.clone({
          setHeaders: {
            Authorization: `Bearer ${this.getToken()}`
          }
        });
        return next.handle(authReq);
      }
    }

🔐 Token Issues

Invalid or Expired Tokens

Symptoms:

  • 401 Unauthorized responses
  • "Token has expired" errors
  • Authentication seems to work but API calls fail

Solutions:

  1. Check Token Expiration

    // Angular: Check if token is expired
    const isExpired = this.msalService.instance.getAllAccounts()[0]?.idTokenClaims?.exp 
      ? Date.now() / 1000 > this.msalService.instance.getAllAccounts()[0].idTokenClaims.exp 
      : true;
  2. Implement Token Refresh

    // Angular: Acquire token silently
    async getAccessToken(): Promise<string> {
      const account = this.msalService.instance.getAllAccounts()[0];
      const accessTokenRequest = {
        scopes: ['api://your-api-id/Company.Read'],
        account: account
      };
      
      try {
        const response = await this.msalService.instance.acquireTokenSilent(accessTokenRequest);
        return response.accessToken;
      } catch (error) {
        // If silent acquisition fails, redirect to login
        await this.msalService.instance.acquireTokenRedirect(accessTokenRequest);
        throw error;
      }
    }
  3. Check API Token Validation

    // API: Ensure proper token validation
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

Wrong Audience in Token

Symptoms:

  • Token validates but API returns 401
  • "Invalid audience" in API logs

Solutions:

  1. Verify API Configuration

    // appsettings.json
    {
      "AzureAd": {
        "ClientId": "your-api-client-id",  // Must match API app registration
        "Authority": "https://your-tenant.ciamlogin.com/"
      }
    }
  2. Check Token Audience

    # Decode JWT token to check 'aud' claim
    # Use jwt.io to decode and verify audience matches your API client ID

🏠 Local Development Issues

Environment Configuration Problems

Common Issues:

  • Wrong client IDs in environment files
  • Incorrect authority URLs
  • Missing user secrets

Solutions:

  1. Verify User Secrets

    cd src/GlassLewis.Api
    dotnet user-secrets list
    
    # Should show:
    # AzureAd:ClientId = your-api-client-id
    # AzureAd:Authority = https://your-tenant.ciamlogin.com/
    # AzureAd:TenantId = your-tenant-id
  2. Check Angular Environment

    // src/environments/environment.development.ts
    export const environment = {
      production: false,
      apiUrl: 'https://localhost:5001',
      msalConfig: {
        auth: {
          clientId: 'your-client-app-id',  // NOT the API client ID
          authority: 'https://your-tenant.ciamlogin.com/',
          redirectUri: 'http://localhost:4200'
        }
      }
    };
  3. SSL Certificate Issues

    # Trust development certificate
    dotnet dev-certs https --trust
    
    # Or run with specific ports
    dotnet run --urls="https://localhost:5001;http://localhost:5000"

Browser Issues

  1. Clear Browser Cache

    • Clear all cookies and local storage for localhost
    • Open browser in incognito/private mode
  2. Check Browser Console

    // Common console errors:
    // - "Mixed Content" warnings (HTTP calling HTTPS)
    // - CORS preflight failures
    // - Network errors to authority endpoints

🚀 Production Deployment Issues

App Registration Configuration

Before deploying to production:

  1. Update Redirect URIs

    Add production URLs to client app registration:
    ✅ https://your-app.azurestaticapps.net
    ✅ https://your-custom-domain.com
    
  2. Update CORS Origins

    // Update API CORS policy
    policy.WithOrigins(
        "https://your-production-domain.com"
    );
  3. Environment Variables

    # Verify production environment variables
    # In Azure App Service → Configuration → Application settings
    
    AzureAd__ClientId=your-api-client-id
    AzureAd__Authority=https://your-tenant.ciamlogin.com/
    AzureAd__TenantId=your-tenant-id

🛠️ Debugging Tools & Techniques

1. Network Tab Analysis

What to check:

  • Authentication requests to login.microsoftonline.com
  • Token requests to your authority endpoint
  • API calls with Authorization: Bearer headers
  • CORS preflight OPTIONS requests

2. JWT Token Inspection

Use jwt.io to decode tokens:

Check these claims:

{
  "iss": "https://your-tenant.ciamlogin.com/",
  "aud": "your-api-client-id",
  "scp": "Company.Read Company.ReadWrite",
  "sub": "user-id",
  "exp": 1234567890
}

3. Azure AD Logs

Check sign-in logs:

  • Azure Portal → Microsoft Entra ID → Sign-in logs
  • Filter by your application
  • Look for error details and correlation IDs

4. API Logging

Enable detailed logging:

// appsettings.Development.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore.Authentication": "Debug",
      "Microsoft.AspNetCore.Authorization": "Debug"
    }
  }
}

📋 Pre-Flight Checklist

Before troubleshooting, verify:

Azure Configuration

  • API app registration exists with correct scopes
  • Client app registration has correct redirect URIs
  • Admin consent granted for API permissions
  • Service principal has correct Azure RBAC permissions

Code Configuration

  • Client ID matches between Azure and code
  • Authority URL format is correct
  • API scopes match between client and API apps
  • CORS policy includes all necessary origins

Network & Security

  • HTTPS certificates valid and trusted
  • No proxy or firewall blocking auth endpoints
  • Browser allows third-party cookies
  • No browser extensions blocking authentication

🆘 Still Having Issues?

1. Enable Detailed Logging

// API: Add to Program.cs
builder.Logging.AddConsole();
builder.Logging.SetMinimumLevel(LogLevel.Debug);
// Angular: Enable MSAL logging
export const environment = {
  msalConfig: {
    system: {
      loggerOptions: {
        loggerCallback: (level: LogLevel, message: string) => {
          console.log(`MSAL [${LogLevel[level]}]: ${message}`);
        },
        logLevel: LogLevel.Verbose
      }
    }
  }
};

2. Test with Minimal Setup

Create a minimal test:

// Simple MSAL test
const msalInstance = new PublicClientApplication({
  auth: {
    clientId: 'your-client-id',
    authority: 'https://your-tenant.ciamlogin.com/'
  }
});

// Test login
msalInstance.loginRedirect();

📚 Related Documentation

⚠️ **GitHub.com Fallback** ⚠️