Core authentication functionality providing login, logout, token acquisition, and user account management through Angular services and reactive patterns.
Main authentication service that wraps MSAL Browser functionality with Angular-specific implementations and Observable patterns.
/**
* Main authentication service for MSAL Angular integration
* Implements IMsalService interface and provides Angular-specific authentication operations
*/
class MsalService implements IMsalService {
/** The underlying MSAL browser instance */
instance: IPublicClientApplication;
/** Initializes the MSAL instance */
initialize(): Observable<void>;
/** Handles redirect responses from authentication flows */
handleRedirectObservable(hash?: string): Observable<AuthenticationResult>;
/** Initiates login using popup window */
loginPopup(request?: PopupRequest): Observable<AuthenticationResult>;
/** Initiates login using redirect flow */
loginRedirect(request?: RedirectRequest): Observable<void>;
/** Acquires tokens silently using cached credentials */
acquireTokenSilent(silentRequest: SilentRequest): Observable<AuthenticationResult>;
/** Acquires tokens using popup window */
acquireTokenPopup(request: PopupRequest): Observable<AuthenticationResult>;
/** Acquires tokens using redirect flow */
acquireTokenRedirect(request: RedirectRequest): Observable<void>;
/** Initiates SSO silent authentication */
ssoSilent(request: SsoSilentRequest): Observable<AuthenticationResult>;
/** Logs out user using redirect flow */
logoutRedirect(logoutRequest?: EndSessionRequest): Observable<void>;
/** Logs out user using popup window */
logoutPopup(logoutRequest?: EndSessionPopupRequest): Observable<void>;
/** @deprecated Use logoutRedirect or logoutPopup instead */
logout(logoutRequest?: EndSessionRequest): Observable<void>;
/** Gets the current logger instance */
getLogger(): Logger;
/** Sets a new logger instance */
setLogger(logger: Logger): void;
}Usage Examples:
import { Component, OnInit, Inject } from "@angular/core";
import { MsalService } from "@azure/msal-angular";
import { AuthenticationResult, PopupRequest } from "@azure/msal-browser";
@Component({
selector: 'app-login',
template: `
<button (click)="login()" *ngIf="!isLoggedIn">Login</button>
<button (click)="logout()" *ngIf="isLoggedIn">Logout</button>
<div *ngIf="isLoggedIn">Welcome, {{ username }}!</div>
`
})
export class LoginComponent implements OnInit {
isLoggedIn = false;
username = '';
constructor(private authService: MsalService) {}
ngOnInit() {
// Check if user is already logged in
this.isLoggedIn = this.authService.instance.getAllAccounts().length > 0;
if (this.isLoggedIn) {
this.username = this.authService.instance.getAllAccounts()[0].username;
}
}
login() {
const loginRequest: PopupRequest = {
scopes: ["user.read", "openid", "profile"]
};
this.authService.loginPopup(loginRequest).subscribe({
next: (result: AuthenticationResult) => {
console.log('Login successful', result);
this.isLoggedIn = true;
this.username = result.account?.username || '';
},
error: (error) => console.error('Login failed', error)
});
}
logout() {
this.authService.logoutPopup({
postLogoutRedirectUri: window.location.origin
}).subscribe({
next: () => {
this.isLoggedIn = false;
this.username = '';
}
});
}
}Interface defining the contract for MsalService, useful for testing and dependency injection.
/**
* Interface defining the contract for MsalService
* Provides type safety and enables easy mocking for testing
*/
interface IMsalService {
instance: IPublicClientApplication;
initialize(): Observable<void>;
handleRedirectObservable(): Observable<AuthenticationResult | null>;
loginPopup(request?: PopupRequest): Observable<AuthenticationResult>;
loginRedirect(request?: RedirectRequest): Observable<void>;
acquireTokenSilent(silentRequest: SilentRequest): Observable<AuthenticationResult>;
acquireTokenPopup(request: PopupRequest): Observable<AuthenticationResult>;
acquireTokenRedirect(request: RedirectRequest): Observable<void>;
ssoSilent(request: SsoSilentRequest): Observable<AuthenticationResult>;
logoutRedirect(logoutRequest?: EndSessionRequest): Observable<void>;
logoutPopup(logoutRequest?: EndSessionRequest): Observable<void>;
logout(logoutRequest?: EndSessionRequest): Observable<void>;
getLogger(): Logger;
setLogger(logger: Logger): void;
}import { Component } from "@angular/core";
import { MsalService } from "@azure/msal-angular";
import { SilentRequest, PopupRequest } from "@azure/msal-browser";
@Component({
selector: 'app-api-call',
template: '<button (click)="callApi()">Call Protected API</button>'
})
export class ApiCallComponent {
constructor(private authService: MsalService) {}
async callApi() {
const account = this.authService.instance.getAllAccounts()[0];
// Try silent token acquisition first
const silentRequest: SilentRequest = {
scopes: ["https://graph.microsoft.com/.default"],
account: account
};
try {
const result = await this.authService.acquireTokenSilent(silentRequest).toPromise();
console.log('Token acquired silently', result?.accessToken);
// Use token for API call
this.makeApiCall(result?.accessToken);
} catch (error) {
console.log('Silent token acquisition failed, falling back to popup');
// Fall back to popup if silent acquisition fails
const popupRequest: PopupRequest = {
scopes: ["https://graph.microsoft.com/.default"]
};
this.authService.acquireTokenPopup(popupRequest).subscribe({
next: (result) => {
console.log('Token acquired via popup', result.accessToken);
this.makeApiCall(result.accessToken);
},
error: (error) => console.error('Token acquisition failed', error)
});
}
}
private makeApiCall(token: string) {
// Make HTTP request with token
// This would typically be handled by MsalInterceptor automatically
}
}import { Component, OnInit } from "@angular/core";
import { MsalService } from "@azure/msal-angular";
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private authService: MsalService) {}
ngOnInit() {
// Handle redirect responses when app loads
this.authService.handleRedirectObservable().subscribe({
next: (result) => {
if (result) {
console.log('Redirect login successful', result);
// Handle successful authentication
}
},
error: (error) => {
console.error('Redirect login failed', error);
// Handle authentication error
}
});
}
}