The VirtualFront project is a production-grade Single Page Application (SPA) that integrates Microsoft Teams and Azure Communication Services (ACS) to enable video calling, PSTN integration, and secure authentication via Azure Active Directory (AAD). This article provides a comprehensive analysis of the source code, including architecture, project structure, integration steps, and deployment considerations.


Table of Contents

  1. Introduction
  2. High-Level Architecture
  3. Detailed Project Structure
  4. Key Components
  5. Integration Steps
  6. Code Snippets and Token Flow
  7. API Endpoints
  8. Technologies Used
  9. Future Enhancements
  10. Conclusion

Introduction

VirtualFront is a modern web application designed to act as a virtual receptionist system. It connects a browser-based SPA with Microsoft Teams users via ACS, making it ideal for kiosk-based solutions, front-desk automation, and remote concierge systems.

Key Features:

  • One-click video calls to Microsoft Teams users.
  • Token exchange using Azure AD and ACS.
  • PSTN calling support (dialing out to phone numbers).
  • Scalable backend built with Node.js and Express.
  • Frontend powered by Vanilla JavaScript and ACS SDK.

Image description

High-Level Architecture

The architecture of VirtualFront is modular, with a clear separation between the frontend, backend, and Azure services. Below is a high-level diagram:

Workflow:

  1. The Frontend communicates with the Backend to request ACS tokens.
  2. The Backend authenticates users via Azure AD, exchanges tokens, and provides the frontend with call credentials.
  3. The Azure Services (ACS, AAD, Graph API) handle authentication, token management, and communication.

Image description


Detailed Project Structure

The project is organized into the following directories and files:

.
├── client/                      # Frontend SPA (HTML, JS, CSS)
│   ├── assets/                  # Static assets (images, styles)
│   ├── app.js                   # Main application logic
│   └── call.js                  # ACS call logic
│
├── constants/                   # Common constants (enums, labels)
│   └── roles.js
│
├── controllers/                 # Express route controllers
│   ├── token.controller.js      # Token management (ACS, AAD)
│   ├── user.controller.js       # Teams users & endpoint APIs
│   └── pstn.controller.js       # PSTN token and phone services
│
├── public/                      # Static public directory
│   └── index.html
│
├── routes/                      # API route definitions
│   ├── token.routes.js
│   ├── user.routes.js
│   └── pstn.routes.js
│
├── services/                    # Service layer for Azure SDK calls
│   ├── acs.service.js
│   ├── auth.service.js
│   └── teams.service.js
│
├── utils/                       # Utility helpers
│   ├── logger.js
│   └── environment.js
│
├── .env                         # Environment variables
├── index.js                     # Express server entry
├── package.json                 # Node dependencies
├── webpack.config.js            # Frontend bundling
└── README.md                    # Project documentation

Key Components

1. Frontend

The frontend is implemented in Vanilla JavaScript and interacts with the Azure Communication Services SDK to manage video calls and UI interactions.

Code Snippet: Initializing the Teams Call Agent

import { CallClient } from '@azure/communication-calling';

const callClient = new CallClient();
const callAgent = await callClient.createCallAgent({ userId: '' });

callAgent.on('incomingCall', (call) => {
  console.log('Incoming call:', call);
  call.accept();
});

2. Backend

The backend is built using Node.js and Express. It provides APIs for fetching access tokens, validating tokens, and serving the SPA.

Code Snippet: Fetching Access Tokens

const { getAccessToken } = require('../services/auth.service');

exports.getAccessToken = async (req, res) => {
  const { email, token } = req.body;
  const accessToken = await getAccessToken(email, token);
  res.json({ accessToken });
};

3. Services

The services directory contains the core business logic for interacting with Azure SDKs.

Code Snippet: Fetching ACS Token for Teams User

const { CommunicationIdentityClient } = require('@azure/communication-identity');

exports.getAcsToken = async (aadToken, clientId, userId, tenantId) => {
  const client = new CommunicationIdentityClient(process.env.ACS_CONNECTION_STRING);
  const tokenResponse = await client.getTokenForTeamsUser({
    teamsUserAadToken: aadToken,
    clientId,
    userObjectId: userId,
    tenantId,
  });
  return tokenResponse.token;
};

Integration Steps

1. Provision Azure Communication Services (ACS)

  • Create a Communication Services resource in Azure.
  • Copy the connection string.
  • Enable PSTN (optional).

2. Register an Azure AD Application

  • Create App Registration in Azure AD.
  • Configure:
    • Redirect URIs (if needed)
    • Client ID, Tenant ID, Client Secret
  • Add Microsoft Graph API permissions:
    • User.Read
    • Directory.Read.All

3. Enable ACS Federation in Microsoft Teams

Install-Module MicrosoftTeams
Connect-MicrosoftTeams

$resourceId = ""
Set-CsTeamsAcsFederationConfiguration -EnableAcsUsers $true -AllowedAcsResources $resourceId

Set-CsExternalAccessPolicy -Identity Global -EnableAcsFederationAccess $true

4. Configure Environment Variables

Create a .env file in the root directory:

ACS_CONNECTION_STRING=endpoint=https://.communication.azure.com/;accesskey=
AAD_CLIENT_ID=
AAD_TENANT_ID=
AAD_SECRET=
TEAMS_USER_ID=

Image description

Code Snippets and Token Flow

Backend: Exchange AAD Token for ACS Token

const { CommunicationIdentityClient } = require('@azure/communication-identity');

const client = new CommunicationIdentityClient(process.env.ACS_CONNECTION_STRING);
const tokenResponse = await client.getTokenForTeamsUser({
  teamsUserAadToken: aadToken,
  clientId: process.env.AAD_CLIENT_ID,
  userObjectId: userId,
  tenantId: process.env.AAD_TENANT_ID,
});
return tokenResponse.token;

Frontend: Initiate Call to Teams

import { CallClient } from '@azure/communication-calling';

const callClient = new CallClient();
const tokenCredential = new AzureCommunicationTokenCredential("");
const callAgent = await callClient.createCallAgent(tokenCredential);

callAgent.startCall([
  { communicationUserId: "8:acs:..." }
], { videoOptions: { localVideoStreams: [] } });

API Endpoints

POST /get-access-token

Fetches an ACS token for Teams users.

POST /get-pstn-token

Fetches a PSTN token for phone calls.

GET /endpoint

Fetches the REST API endpoint for the current environment.


Technologies Used

  • Frontend: Vanilla JavaScript, Webpack, ACS Calling SDK
  • Backend: Node.js, Express, Azure SDK
  • Identity: Azure AD, Microsoft Graph
  • Cloud: Azure Communication Services

Future Enhancements

  • Add support for group calls and chat features.
  • Implement a CI/CD pipeline for automated deployments.
  • Enhance error handling and logging mechanisms.
  • Add an admin panel for managing Teams users.

Conclusion

VirtualFront demonstrates how to build a secure and scalable communication platform by integrating Microsoft Teams and Azure Communication Services. By leveraging Azure's robust APIs and SDKs, developers can create seamless communication experiences for various use cases, such as virtual receptionists, kiosks, and remote concierge systems.

For more information, refer to:

Curious to see it in action? Explore the complete implementation and code on GitHub:

VirtualFront: Seamless Communication with Microsoft Teams via Azure Communication Services (ACS)

VirtualFront is a production-grade Single Page Application (SPA) that integrates Microsoft Teams and Azure Communication Services (ACS) to enable video calling, PSTN integration, and secure authentication via Azure Active Directory (AAD). This repository contains the source code and setup instructions to get started.


🚀 Features

  • One-click video calls to Microsoft Teams users.
  • Token exchange using Azure AD and ACS.
  • PSTN calling support (dialing out to phone numbers).
  • Scalable backend built with Node.js and Express.
  • Frontend powered by Vanilla JavaScript and ACS SDK.

📂 Project Structure


├── client/                      # Frontend SPA (HTML, JS, CSS)
│   ├── assets/                  # Static assets (images, styles)
│   ├── app.js                   # Main application logic
│   └── call.js                  # ACS call logic
│
├── constants/                   # Common constants (enums, labels)
│   └── roles.js
│
├── controllers/                 # Express route controllers
│   ├── token.controller.js      # Token