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.
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
}
}
});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);
}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);
}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 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 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);
}
}/** Get all cached accounts */
getAllAccounts(): Promise<AccountInfo[]>;
/** Clear all cache entries */
clearCache(): void;/** Get current logger instance */
getLogger(): Logger;
/** Set new logger instance */
setLogger(logger: Logger): void;/** Get token cache instance for advanced operations */
getTokenCache(): TokenCache;