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

token-provider-integration.mddocs/

Token Provider Integration

Token provider integration enables seamless authentication with Azure SDK clients through bearer token providers and authentication record management. These utilities simplify credential integration and provide advanced token caching capabilities.

Capabilities

Bearer Token Provider

Create bearer token providers for Azure SDK clients, enabling automatic token acquisition and refresh in HTTP pipeline policies.

/**
 * Creates a callback that can be used for the bearerTokenAuthenticationPolicy
 * @param credential - The TokenCredential implementation that can supply the token
 * @param scopes - The expected scopes for the token
 * @param options - Options to configure the token provider
 * @returns A function that can be used as a bearer token provider
 */
function getBearerTokenProvider(
  credential: TokenCredential,
  scopes: string | string[],
  options?: GetBearerTokenProviderOptions
): () => Promise<string>;

interface GetBearerTokenProviderOptions {
  /**
   * The abort signal to abort requests to get tokens
   */
  abortSignal?: AbortSignal;
  
  /**
   * The tracing options for the requests to get tokens
   */
  tracingOptions?: {
    /**
     * Tracing Context for the current request to get a token
     */
    tracingContext?: TracingContext;
  };
}

Usage Examples:

import { getBearerTokenProvider, DefaultAzureCredential } from "@azure/identity";
import { createHttpHeaders, createPipelineRequest } from "@azure/core-rest-pipeline";

// Create bearer token provider
const credential = new DefaultAzureCredential();
const getToken = getBearerTokenProvider(
  credential,
  "https://graph.microsoft.com/.default"
);

// Get token for authorization header
const token = await getToken();

// Use with HTTP request
const response = await fetch("https://graph.microsoft.com/v1.0/me", {
  headers: {
    "Authorization": `Bearer ${token}`,
    "Content-Type": "application/json"
  }
});

// With custom options
const getTokenWithOptions = getBearerTokenProvider(
  credential,
  ["https://graph.microsoft.com/User.Read"],
  {
    abortSignal: new AbortController().signal,
    tracingOptions: {
      tracingContext: {} // Custom tracing context
    }
  }
);

const tokenWithOptions = await getTokenWithOptions();

Authentication Record Management

Serialize and deserialize authentication records for token caching and session persistence.

/**
 * Serializes an AuthenticationRecord into a string
 * @param record - The AuthenticationRecord to serialize
 * @returns String representation of the authentication record
 */
function serializeAuthenticationRecord(record: AuthenticationRecord): string;

/**
 * Deserializes a string into an AuthenticationRecord
 * @param serializedRecord - String representation of an authentication record
 * @returns The deserialized AuthenticationRecord
 */
function deserializeAuthenticationRecord(serializedRecord: string): AuthenticationRecord;

interface AuthenticationRecord {
  /**
   * The authority host used for authentication
   */
  authority: string;
  
  /**
   * The home account ID
   */
  homeAccountId: string;
  
  /**
   * The environment (authority host domain)
   */
  environment: string;
  
  /**
   * The tenant ID
   */
  tenantId: string;
  
  /**
   * The username/UPN of the authenticated user
   */
  username: string;
  
  /**
   * The client ID of the application
   */
  clientId: string;
}

Usage Examples:

import { 
  serializeAuthenticationRecord, 
  deserializeAuthenticationRecord,
  InteractiveBrowserCredential 
} from "@azure/identity";

// Interactive authentication that returns an authentication record
const credential = new InteractiveBrowserCredential({
  clientId: "12345678-1234-1234-1234-123456789012"
});

// Get token and authentication record
const authResult = await credential.authenticate("https://graph.microsoft.com/.default");

if (authResult) {
  // Serialize authentication record for storage
  const serialized = serializeAuthenticationRecord(authResult);
  
  // Store in localStorage, file system, or database
  localStorage.setItem("authRecord", serialized);
  
  // Later, retrieve and deserialize
  const storedRecord = localStorage.getItem("authRecord");
  if (storedRecord) {
    const authRecord = deserializeAuthenticationRecord(storedRecord);
    
    // Use authentication record with new credential instance
    const restoredCredential = new InteractiveBrowserCredential({
      clientId: "12345678-1234-1234-1234-123456789012",
      authenticationRecord: authRecord
    });
    
    // This will use cached tokens when possible
    const token = await restoredCredential.getToken("https://graph.microsoft.com/.default");
  }
}

Authenticate Method

Some credentials support explicit authentication to obtain authentication records:

/**
 * Authenticates the user and returns an AuthenticationRecord
 * Available on credentials that support caching: InteractiveBrowserCredential, DeviceCodeCredential
 */
interface AuthenticatableCredential extends TokenCredential {
  authenticate(scopes: string | string[], options?: GetTokenOptions): Promise<AuthenticationRecord | undefined>;
}

Usage Examples:

import { InteractiveBrowserCredential, DeviceCodeCredential } from "@azure/identity";

// Interactive browser authentication
const browserCredential = new InteractiveBrowserCredential({
  clientId: "12345678-1234-1234-1234-123456789012"
});

// Explicit authentication
const authRecord = await browserCredential.authenticate("https://graph.microsoft.com/.default");

if (authRecord) {
  console.log(`Authenticated as: ${authRecord.username}`);
  console.log(`Tenant: ${authRecord.tenantId}`);
  
  // Serialize for later use
  const serialized = serializeAuthenticationRecord(authRecord);
  // Store serialized record
}

// Device code authentication
const deviceCredential = new DeviceCodeCredential({
  clientId: "12345678-1234-1234-1234-123456789012",
  userPromptCallback: (info) => {
    console.log(`Go to ${info.verificationUri} and enter code: ${info.userCode}`);
  }
});

const deviceAuthRecord = await deviceCredential.authenticate("https://graph.microsoft.com/.default");

Advanced Integration Patterns

Custom Pipeline Integration

import { 
  getBearerTokenProvider, 
  DefaultAzureCredential 
} from "@azure/identity";
import { 
  createHttpHeaders, 
  createPipelineRequest,
  bearerTokenAuthenticationPolicy 
} from "@azure/core-rest-pipeline";

// Create custom HTTP client with authentication
class AuthenticatedHttpClient {
  private getToken: () => Promise<string>;
  
  constructor(credential: TokenCredential, scopes: string | string[]) {
    this.getToken = getBearerTokenProvider(credential, scopes);
  }
  
  async makeRequest(url: string, method: string = "GET"): Promise<Response> {
    // Get fresh token
    const token = await this.getToken();
    
    // Make the request with authentication
    return fetch(url, {
      method,
      headers: {
        "Authorization": `Bearer ${token}`,
        "Content-Type": "application/json"
      }
    });
  }
}

// Usage
const client = new AuthenticatedHttpClient(
  new DefaultAzureCredential(),
  "https://graph.microsoft.com/.default"
);

const response = await client.makeRequest("https://graph.microsoft.com/v1.0/me");

Session Management

import { 
  serializeAuthenticationRecord,
  deserializeAuthenticationRecord,
  InteractiveBrowserCredential 
} from "@azure/identity";

class SessionManager {
  private static STORAGE_KEY = "azure-auth-record";
  
  static async createSession(clientId: string, scopes: string[]): Promise<InteractiveBrowserCredential> {
    // Try to restore existing session
    const existing = this.restoreSession(clientId);
    if (existing) {
      try {
        // Test if existing session works
        await existing.getToken(scopes);
        return existing;
      } catch {
        // Existing session invalid, create new one
      }
    }
    
    // Create new session
    const credential = new InteractiveBrowserCredential({ clientId });
    const authRecord = await credential.authenticate(scopes);
    
    if (authRecord) {
      // Store session
      const serialized = serializeAuthenticationRecord(authRecord);
      localStorage.setItem(this.STORAGE_KEY, serialized);
    }
    
    return credential;
  }
  
  static restoreSession(clientId: string): InteractiveBrowserCredential | null {
    const stored = localStorage.getItem(this.STORAGE_KEY);
    if (!stored) return null;
    
    try {
      const authRecord = deserializeAuthenticationRecord(stored);
      return new InteractiveBrowserCredential({
        clientId,
        authenticationRecord: authRecord
      });
    } catch {
      // Invalid stored record
      localStorage.removeItem(this.STORAGE_KEY);
      return null;
    }
  }
  
  static clearSession(): void {
    localStorage.removeItem(this.STORAGE_KEY);
  }
}

// Usage
const credential = await SessionManager.createSession(
  "12345678-1234-1234-1234-123456789012",
  ["https://graph.microsoft.com/.default"]
);

Multi-Tenant Token Management

import { getBearerTokenProvider, DefaultAzureCredential } from "@azure/identity";

class MultiTenantTokenManager {
  private tokenProviders = new Map<string, () => Promise<string>>();
  
  constructor(private credential: TokenCredential) {}
  
  getTokenProvider(tenantId: string, scopes: string | string[]): () => Promise<string> {
    const key = `${tenantId}:${Array.isArray(scopes) ? scopes.join(',') : scopes}`;
    
    if (!this.tokenProviders.has(key)) {
      // Note: Current getBearerTokenProvider doesn't support tenant-specific tokens directly
      // This would need to be implemented with a custom credential wrapper
      const provider = getBearerTokenProvider(this.credential, scopes);
      this.tokenProviders.set(key, provider);
    }
    
    return this.tokenProviders.get(key)!;
  }
  
  async getToken(tenantId: string, scopes: string | string[]): Promise<string> {
    const provider = this.getTokenProvider(tenantId, scopes);
    return await provider();
  }
}

// Usage
const tokenManager = new MultiTenantTokenManager(new DefaultAzureCredential());

// Get tokens for specific tenant and scope
const graphToken = await tokenManager.getToken(
  "tenant-1-id",
  "https://graph.microsoft.com/.default"
);

const managementToken = await tokenManager.getToken(
  "tenant-2-id", 
  "https://management.azure.com/.default"
);

Error Handling

Bearer Token Provider Errors

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

const getToken = getBearerTokenProvider(
  credential,
  scopes
);

try {
  const token = await getToken();
  // Use token in request
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error("Authentication failed:", error.message);
    // Handle re-authentication
  }
}

Authentication Record Errors

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

try {
  const authRecord = deserializeAuthenticationRecord(storedData);
} catch (error) {
  console.error("Invalid authentication record:", error.message);
  // Clear invalid data and prompt for re-authentication
  localStorage.removeItem("authRecord");
}

Best Practices

Token Caching

// Enable persistent token caching for better performance
const credential = new InteractiveBrowserCredential({
  clientId: "your-client-id",
  tokenCachePersistenceOptions: {
    enabled: true,
    name: "myapp-token-cache"
  }
});

Request Optimization

// Reuse bearer token providers for the same credential and scopes
const getToken = getBearerTokenProvider(credential, scopes);

// Use the same provider for multiple requests
const token1 = await getToken(); // Fresh token
const token2 = await getToken(); // May reuse cached token 
const token3 = await getToken(); // May reuse cached token

Session Lifecycle

// Properly handle session lifecycle
window.addEventListener('beforeunload', () => {
  // Optionally clear sensitive session data
  SessionManager.clearSession();
});

// Handle authentication errors by clearing invalid sessions
try {
  const token = await credential.getToken(scopes);
} catch (error) {
  if (error instanceof AuthenticationError) {
    SessionManager.clearSession();
    // Redirect to login
  }
}