or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authentication-flows.mdconfidential-client.mdconfiguration.mderror-handling.mdindex.mdmanaged-identity.mdpublic-client.mdtoken-cache.md
tile.json

public-client.mddocs/

Public Client Applications

Public Client Applications are designed for applications that cannot securely store client secrets, such as desktop applications, mobile apps, and single-page applications. These applications rely on user interaction for authentication and use flows like authorization code with PKCE, device code, and interactive authentication.

Capabilities

PublicClientApplication Class

Main class for creating public client applications.

/**
 * Public client application class implementing IPublicClientApplication interface
 * Suitable for applications that cannot securely store client secrets
 */
class PublicClientApplication implements IPublicClientApplication {
  constructor(configuration: Configuration);
  
  /** Creates the URL of the authorization request */
  getAuthCodeUrl(request: AuthorizationUrlRequest): Promise<string>;
  
  /** Acquires a token by exchanging the authorization code received from the first step of OAuth 2.0 Authorization Code Flow */
  acquireTokenByCode(request: AuthorizationCodeRequest): Promise<AuthenticationResult>;
  
  /** Acquires a token interactively */
  acquireTokenInteractive(request: InteractiveRequest): Promise<AuthenticationResult>;
  
  /** Acquires a token silently when a user specifies the account the token is requested for */
  acquireTokenSilent(request: SilentFlowRequest): Promise<AuthenticationResult>;
  
  /** Acquires a token by exchanging the refresh token provided for a new set of tokens */
  acquireTokenByRefreshToken(request: RefreshTokenRequest): Promise<AuthenticationResult | null>;
  
  /** Acquires a token from the authority using OAuth2.0 device code flow */
  acquireTokenByDeviceCode(request: DeviceCodeRequest): Promise<AuthenticationResult | null>;
  
  /** 
   * Acquires tokens with password grant by exchanging client applications username and password for credentials
   * @deprecated - Use a more secure flow instead
   */
  acquireTokenByUsernamePassword(request: UsernamePasswordRequest): Promise<AuthenticationResult | null>;
  
  /** Gets the token cache for the application */
  getTokenCache(): TokenCache;
  
  /** Returns the logger instance */
  getLogger(): Logger;
  
  /** Replaces the default logger set in configurations with new Logger with new configurations */
  setLogger(logger: Logger): void;
  
  /** Clear the cache */
  clearCache(): void;
  
  /** Gets all cached accounts */
  getAllAccounts(): Promise<AccountInfo[]>;
  
  /** Removes cache artifacts associated with the given account */
  signOut(request: SignOutRequest): Promise<void>;
}

Usage Example:

import { PublicClientApplication } from "@azure/msal-node";

const pca = new PublicClientApplication({
  auth: {
    clientId: "your-client-id",
    authority: "https://login.microsoftonline.com/common"
  },
  cache: {
    cachePlugin: // optional cache plugin
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message) => {
        console.log(message);
      },
      piiLoggingEnabled: false,
      logLevel: LogLevel.Info
    }
  }
});

Authorization Code Flow

Standard OAuth 2.0 authorization code flow with PKCE for secure authentication.

/**
 * Request to generate authorization URL (first step of authorization code flow)
 */
type AuthorizationUrlRequest = {
  /** Array of scopes the application is requesting access to */
  scopes: string[];
  /** URI where the authorization server will redirect after user authorization */
  redirectUri: string;
  /** Prompt behavior for user interaction */
  prompt?: PromptValue;
  /** Account to use for authentication */
  account?: AccountInfo;
  /** Login hint for pre-filling username */
  loginHint?: string;
  /** Domain hint for federated authentication */
  domainHint?: string;
  /** Additional query parameters for the authorization request */
  extraQueryParameters?: Record<string, string>;
  /** PKCE code challenge for security */
  codeChallenge?: string;
  /** PKCE code challenge method */
  codeChallengeMethod?: string;
  /** State parameter for CSRF protection */
  state?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
  /** Claims request for additional token claims */
  claims?: string;
  /** Authority URL to override default */
  authority?: string;
};

/**
 * Request to exchange authorization code for tokens (second step of authorization code flow)
 */
type AuthorizationCodeRequest = {
  /** Array of scopes the application is requesting access to */
  scopes: string[];
  /** URI where the authorization server redirected after user authorization */
  redirectUri: string;
  /** Authorization code received from authorization server */
  code: string;
  /** State parameter for CSRF protection validation */
  state?: string;
  /** Authority URL to override default */
  authority?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
  /** Claims request for additional token claims */
  claims?: string;
  /** Additional parameters for token request */
  tokenQueryParameters?: Record<string, string>;
  /** PKCE code verifier for security validation */
  codeVerifier?: string;
};

Usage Example:

// Step 1: Generate authorization URL
const authCodeUrlParameters = {
  scopes: ["user.read", "mail.read"],
  redirectUri: "http://localhost:3000/redirect",
  prompt: "select_account" as PromptValue
};

const authUrl = await pca.getAuthCodeUrl(authCodeUrlParameters);
console.log("Navigate to:", authUrl);

// Step 2: Exchange authorization code for tokens
const tokenRequest = {
  code: "authorization-code-from-callback", // Extract from callback URL
  scopes: ["user.read", "mail.read"],
  redirectUri: "http://localhost:3000/redirect"
};

try {
  const response = await pca.acquireTokenByCode(tokenRequest);
  console.log("Access token:", response.accessToken);
  console.log("Account:", response.account);
} catch (error) {
  console.error("Token acquisition failed:", error);
}

Interactive Authentication

Browser-based interactive authentication flow for desktop applications.

/**
 * Request for interactive token acquisition with browser
 */
type InteractiveRequest = {
  /** Function to open browser with authorization URL */
  openBrowser: (url: string) => Promise<void>;
  /** Array of scopes the application is requesting access to */
  scopes?: string[];
  /** HTML template for success page */
  successTemplate?: string;
  /** HTML template for error page */
  errorTemplate?: string;
  /** Window handle for desktop applications */
  windowHandle?: Buffer;
  /** Custom loopback client for handling redirects */
  loopbackClient?: ILoopbackClient;
  /** Additional query parameters for the authorization request */
  extraQueryParameters?: Record<string, string>;
  /** Prompt behavior for user interaction */
  prompt?: PromptValue;
  /** Login hint for pre-filling username */
  loginHint?: string;
  /** Domain hint for federated authentication */
  domainHint?: string;
  /** Account to use for authentication */
  account?: AccountInfo;
  /** Authority URL to override default */
  authority?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
  /** Claims request for additional token claims */
  claims?: string;
};

Usage Example:

import { open } from "open"; // For opening browser

const interactiveRequest = {
  scopes: ["user.read"],
  openBrowser: async (url: string) => {
    await open(url);
  },
  successTemplate: "<h1>Authentication successful! You can close this window.</h1>",
  errorTemplate: "<h1>Authentication failed. Please try again.</h1>"
};

try {
  const response = await pca.acquireTokenInteractive(interactiveRequest);
  console.log("Access token:", response.accessToken);
} catch (error) {
  console.error("Interactive authentication failed:", error);
}

Device Code Flow

OAuth 2.0 device code flow for devices with limited input capabilities.

/**
 * Request for device code flow authentication
 */
type DeviceCodeRequest = {
  /** Array of scopes the application is requesting access to */
  scopes: string[];
  /** Callback function to display device code to user */
  deviceCodeCallback: (response: DeviceCodeResponse) => void;
  /** Flag to cancel the device code flow polling */
  cancel?: boolean;
  /** Authority URL to override default */
  authority?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
  /** Additional query parameters for the device authorization request */
  extraQueryParameters?: Record<string, string>;
  /** Claims request for additional token claims */
  claims?: string;
};

/**
 * Response containing device code information for user
 */
type DeviceCodeResponse = {
  /** Device code for internal polling */
  deviceCode: string;
  /** User-friendly code to display to user */
  userCode: string;
  /** URL where user should navigate to enter the user code */
  verificationUri: string;
  /** Complete verification URL including user code (optional) */
  verificationUriComplete?: string;
  /** Number of seconds the device code is valid */
  expiresIn: number;
  /** Minimum number of seconds to wait between polling requests */
  interval: number;
  /** Message to display to user */
  message: string;
};

Usage Example:

const deviceCodeRequest = {
  scopes: ["user.read"],
  deviceCodeCallback: (response) => {
    console.log("Please visit:", response.verificationUri);
    console.log("And enter code:", response.userCode);
    console.log("Or visit:", response.verificationUriComplete);
  }
};

try {
  const response = await pca.acquireTokenByDeviceCode(deviceCodeRequest);
  if (response) {
    console.log("Access token:", response.accessToken);
  }
} catch (error) {
  console.error("Device code authentication failed:", error);
}

Silent Token Acquisition

Silent token acquisition from cache or using refresh tokens.

/**
 * Request for silent token acquisition from cache
 */
type SilentFlowRequest = {
  /** Account to acquire token for */
  account: AccountInfo;
  /** Array of scopes the application is requesting access to */
  scopes: string[];
  /** Force refresh from authority instead of using cache */
  forceRefresh?: boolean;
  /** Authority URL to override default */
  authority?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
  /** Claims request for additional token claims */
  claims?: string;
};

Usage Example:

// Get accounts from cache
const accounts = await pca.getAllAccounts();

if (accounts.length > 0) {
  const silentRequest = {
    account: accounts[0],
    scopes: ["user.read"],
    forceRefresh: false // Use cache if available
  };

  try {
    const response = await pca.acquireTokenSilent(silentRequest);
    console.log("Access token from cache:", response.accessToken);
  } catch (error) {
    // Silent acquisition failed, fall back to interactive
    console.log("Silent acquisition failed, using interactive flow");
  }
}

Sign Out

Sign out functionality to clear user session and cache.

/**
 * Request to sign out user
 */
type SignOutRequest = {
  /** Account to sign out */
  account: AccountInfo;
  /** Post logout redirect URI */
  postLogoutRedirectUri?: string;
  /** Correlation ID for tracking requests */
  correlationId?: string;
};

Usage Example:

const accounts = await pca.getAllAccounts();

if (accounts.length > 0) {
  const signOutRequest = {
    account: accounts[0],
    postLogoutRedirectUri: "http://localhost:3000/signedout"
  };

  try {
    await pca.signOut(signOutRequest);
    console.log("User signed out successfully");
  } catch (error) {
    console.error("Sign out failed:", error);
  }
}

Additional Features

Account Management

/** Get all cached accounts */
getAllAccounts(): Promise<AccountInfo[]>;

/** Clear all cache entries */
clearCache(): void;

Logger Configuration

/** Get current logger instance */
getLogger(): Logger;

/** Set new logger instance */
setLogger(logger: Logger): void;

Token Cache Access

/** Get token cache instance for advanced operations */
getTokenCache(): TokenCache;