or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-authentication-flows.mddefault-authentication.mddeveloper-tool-authentication.mdindex.mdinteractive-authentication.mdmanaged-identity-authentication.mdservice-principal-authentication.mdtoken-provider-integration.md
tile.json

advanced-authentication-flows.mddocs/

Advanced Authentication Flows

Advanced authentication flows handle complex scenarios including credential chaining, on-behalf-of authentication, workload identity, and Azure Pipelines integration. These credentials enable sophisticated authentication patterns for enterprise applications and specialized deployment environments.

Capabilities

Chained Token Credential

Combine multiple credentials with fallback logic, allowing custom authentication chains beyond DefaultAzureCredential.

/**
 * Enables multiple `TokenCredential` implementations to be tried in order
 * until one of the getToken methods returns an access token
 */
class ChainedTokenCredential implements TokenCredential {
  constructor(...sources: TokenCredential[]);
  getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
}

Usage Examples:

import { 
  ChainedTokenCredential, 
  ClientSecretCredential, 
  ManagedIdentityCredential,
  AzureCliCredential 
} from "@azure/identity";

// Custom credential chain
const credential = new ChainedTokenCredential(
  new ManagedIdentityCredential(), // Try managed identity first
  new ClientSecretCredential(tenantId, clientId, clientSecret), // Then service principal
  new AzureCliCredential() // Finally try Azure CLI
);

// Different chain for different environments
const developmentChain = new ChainedTokenCredential(
  new AzureCliCredential(),
  new ClientSecretCredential(tenantId, clientId, clientSecret)
);

const productionChain = new ChainedTokenCredential(
  new ManagedIdentityCredential(),
  new ClientSecretCredential(tenantId, clientId, clientSecret)
);

// Use based on environment
const credential = process.env.NODE_ENV === 'production' 
  ? productionChain 
  : developmentChain;

// Get token - chain will try each credential until one succeeds
const token = await credential.getToken("https://graph.microsoft.com/.default");

On-Behalf-Of Authentication

Authenticate on behalf of a user using an existing user token. This enables middle-tier applications to call downstream APIs while maintaining the user's identity.

/**
 * Enables authentication to Microsoft Entra ID using the On-Behalf-Of flow
 * Exchange a user's access token for an access token for a different resource
 */
class OnBehalfOfCredential implements TokenCredential {
  constructor(options: OnBehalfOfCredentialSecretOptions);
  constructor(options: OnBehalfOfCredentialCertificateOptions);
  constructor(options: OnBehalfOfCredentialAssertionOptions);
  getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
}

interface OnBehalfOfCredentialOptions extends TokenCredentialOptions {
  /**
   * The tenant ID of the application
   */
  tenantId: string;
  
  /**
   * The client ID of the application
   */
  clientId: string;
  
  /**
   * The user assertion (access token) to exchange
   */
  userAssertionToken: string;
  
  /**
   * Allows specification of additional tenant IDs for multi-tenant authentication
   */
  additionallyAllowedTenants?: string[];
}

interface OnBehalfOfCredentialSecretOptions extends OnBehalfOfCredentialOptions {
  /**
   * The client secret of the application
   */
  clientSecret: string;
}

interface OnBehalfOfCredentialCertificateOptions extends OnBehalfOfCredentialOptions {
  /**
   * Path to the certificate file
   */
  certificatePath: string;
  
  /**
   * Password for the certificate (if encrypted)
   */
  certificatePassword?: string;
  
  /**
   * Option to include x5c header
   */
  sendCertificateChain?: boolean;
}

interface OnBehalfOfCredentialAssertionOptions extends OnBehalfOfCredentialOptions {
  /**
   * Function that returns a client assertion JWT
   */
  getAssertion: () => string;
}

Usage Examples:

import { OnBehalfOfCredential } from "@azure/identity";

// On-behalf-of with client secret
const credential = new OnBehalfOfCredential({
  tenantId: "12345678-1234-1234-1234-123456789012",
  clientId: "12345678-1234-1234-1234-123456789012",
  clientSecret: "your-client-secret",
  userAssertionToken: "user-access-token-from-request"
});

// On-behalf-of with certificate
const certificateCredential = new OnBehalfOfCredential({
  tenantId: tenantId,
  clientId: clientId,
  certificatePath: "/path/to/certificate.pem",
  userAssertionToken: userToken,
  sendCertificateChain: true
});

// On-behalf-of with custom assertion
const assertionCredential = new OnBehalfOfCredential({
  tenantId: tenantId,
  clientId: clientId,
  userAssertionToken: userToken,
  getAssertion: () => {
    // Return custom JWT assertion
    return generateClientAssertion();
  }
});

// Use in middle-tier service
async function callDownstreamApi(userToken: string) {
  const credential = new OnBehalfOfCredential({
    tenantId: process.env.AZURE_TENANT_ID!,
    clientId: process.env.AZURE_CLIENT_ID!,
    clientSecret: process.env.AZURE_CLIENT_SECRET!,
    userAssertionToken: userToken
  });
  
  const token = await credential.getToken("https://graph.microsoft.com/.default");
  // Use token to call Microsoft Graph on behalf of the user
}

Workload Identity Authentication

Authenticate using workload identity in Kubernetes environments. This provides secure, keyless authentication for applications running in Azure Kubernetes Service (AKS).

/**
 * Enables authentication to Microsoft Entra ID using workload identity for Kubernetes
 * Uses federated identity credentials configured in Azure AD
 */
class WorkloadIdentityCredential implements TokenCredential {
  constructor(options?: WorkloadIdentityCredentialOptions);
  getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
}

interface WorkloadIdentityCredentialOptions extends TokenCredentialOptions {
  /**
   * The tenant ID of the application
   */
  tenantId?: string;
  
  /**
   * The client ID of the application (user-assigned managed identity or app registration)
   */
  clientId?: string;
  
  /**
   * Path to the projected service account token file
   */
  tokenFilePath?: string;
}

Usage Examples:

import { WorkloadIdentityCredential } from "@azure/identity";

// Basic workload identity (uses environment variables)
const credential = new WorkloadIdentityCredential();

// With explicit configuration
const explicitCredential = new WorkloadIdentityCredential({
  tenantId: "12345678-1234-1234-1234-123456789012",
  clientId: "12345678-1234-1234-1234-123456789012",
  tokenFilePath: "/var/run/secrets/azure/tokens/azure-identity-token"
});

// Get token
const token = await credential.getToken("https://graph.microsoft.com/.default");

Kubernetes Configuration:

# Kubernetes ServiceAccount configuration
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: "12345678-1234-1234-1234-123456789012"
  name: workload-identity-sa
  namespace: default

Environment Variables:

  • AZURE_TENANT_ID - The tenant ID
  • AZURE_CLIENT_ID - The client ID
  • AZURE_FEDERATED_TOKEN_FILE - Path to the projected token file

Azure Pipelines Authentication

Authenticate using Azure Pipelines service connections for CI/CD scenarios.

/**
 * Enables authentication to Microsoft Entra ID using an Azure Pipelines service connection
 * Uses the SYSTEM_ACCESSTOKEN and service connection configuration
 */
class AzurePipelinesCredential implements TokenCredential {
  constructor(
    tenantId: string,
    clientId: string,
    serviceConnectionId: string,
    systemAccessToken: string,
    options?: AzurePipelinesCredentialOptions
  );
  getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
}

interface AzurePipelinesCredentialOptions extends TokenCredentialOptions {
  /**
   * The Azure DevOps organization URL
   */
  organizationUrl?: string;
}

Usage Examples:

import { AzurePipelinesCredential } from "@azure/identity";

// Azure Pipelines authentication
const credential = new AzurePipelinesCredential(
  "12345678-1234-1234-1234-123456789012", // tenant ID
  "12345678-1234-1234-1234-123456789012", // client ID
  "service-connection-id",                 // service connection ID
  process.env.SYSTEM_ACCESSTOKEN!,        // system access token
  {
    organizationUrl: "https://dev.azure.com/your-org"
  }
);

// Get token for Azure resource access
const token = await credential.getToken("https://management.azure.com/.default");

Pipeline Configuration:

# Azure Pipelines YAML
variables:
- name: azureServiceConnection
  value: 'your-service-connection-name'

steps:
- task: AzureCLI@2
  displayName: 'Run Azure CLI with Workload Identity'
  inputs:
    azureSubscription: $(azureServiceConnection)
    scriptType: 'bash'
    scriptLocation: 'inlineScript'
    inlineScript: |
      # Your application will use AzurePipelinesCredential automatically
      node your-app.js

Environment Credential

Authenticate using environment variables. This credential is typically used as part of DefaultAzureCredential but can be used independently.

/**
 * Enables authentication to Microsoft Entra ID using client secret or certificate
 * details configured in environment variables
 */
class EnvironmentCredential implements TokenCredential {
  constructor(options?: EnvironmentCredentialOptions);
  getToken(scopes: string | string[], options?: GetTokenOptions): Promise<AccessToken>;
}

interface EnvironmentCredentialOptions extends TokenCredentialOptions {
  /**
   * Allows specification of additional tenant IDs for multi-tenant authentication
   */
  additionallyAllowedTenants?: string[];
}

Usage Examples:

import { EnvironmentCredential } from "@azure/identity";

// Uses environment variables for configuration
const credential = new EnvironmentCredential();

// With additional configuration
const credentialWithOptions = new EnvironmentCredential({
  additionallyAllowedTenants: ["*"]
});

// Get token
const token = await credential.getToken("https://graph.microsoft.com/.default");

Advanced Credential Patterns

Conditional Credential Selection

import { 
  ChainedTokenCredential,
  ManagedIdentityCredential,
  ClientSecretCredential,
  AzureCliCredential
} from "@azure/identity";

// Different credentials based on environment
function createCredential(): TokenCredential {
  if (process.env.AZURE_CLIENT_SECRET) {
    // Production with service principal
    return new ClientSecretCredential(
      process.env.AZURE_TENANT_ID!,
      process.env.AZURE_CLIENT_ID!,
      process.env.AZURE_CLIENT_SECRET
    );
  } else if (process.env.KUBERNETES_SERVICE_HOST) {
    // Kubernetes with workload identity
    return new WorkloadIdentityCredential();
  } else {
    // Development with fallback chain
    return new ChainedTokenCredential(
      new AzureCliCredential(),
      new ManagedIdentityCredential()
    );
  }
}

Multi-Resource Token Management

// Different credentials for different resources
const graphCredential = new ChainedTokenCredential(
  new ManagedIdentityCredential(),
  new ClientSecretCredential(tenantId, clientId, clientSecret)
);

const keyVaultCredential = new ChainedTokenCredential(
  new ManagedIdentityCredential({ clientId: keyVaultClientId }),
  new ClientCertificateCredential(tenantId, clientId, certificatePath)
);

// Use appropriate credential for each service
const graphToken = await graphCredential.getToken("https://graph.microsoft.com/.default");
const kvToken = await keyVaultCredential.getToken("https://vault.azure.net/.default");

Error Resilience

import { 
  ChainedTokenCredential,
  AuthenticationError,
  CredentialUnavailableError 
} from "@azure/identity";

const resilientCredential = new ChainedTokenCredential(
  new ManagedIdentityCredential(),
  new ClientSecretCredential(tenantId, clientId, clientSecret),
  new AzureCliCredential()
);

try {
  const token = await resilientCredential.getToken(scopes);
} catch (error) {
  if (error instanceof AuthenticationError) {
    // All credentials failed with authentication errors
    console.error("Authentication failed:", error.message);
  } else if (error instanceof CredentialUnavailableError) {
    // All credentials were unavailable
    console.error("No credentials available:", error.message);
  }
}