Deployment Guide - Azure Production Deployment
This guide explains how to deploy the Mermaid to Dataverse Converter to Azure for production use with enterprise-grade security.
Note: For local development setup, see Local Development Guide
Multi-Environment Support: This application supports deploying to multiple Dataverse environments (dev/test/prod). See Azure Multi-Environment Guide for details.
Table of Contents
- Quick Start - Azure Deployment
- Multi-Environment Support
- Prerequisites
- Security Architecture
- Deployment Process
- Authentication & Authorization
- Post-Deployment Configuration
- Troubleshooting
Quick Start - Azure Deployment
Three steps to deploy everything:
# Clone the repository
git clone https://github.com/LuiseFreese/mermaid.git
cd mermaid
# Step 1: Configure your environments (REQUIRED)
Copy-Item data/environments.example.json data/environments.json
# Edit data/environments.json with your Dataverse environment(s)
# Step 2: Create Azure infrastructure and identity setup
.\scripts\setup-secretless.ps1 -EnvironmentSuffix "prod" -Unattended
# Step 3: Deploy the application code
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "prod"
The setup script will:
- Validate that
data/environments.jsonexists (required!) - Create Backend App Registration with federated credentials (linked to managed identity)
- Create Frontend App Registration with Microsoft Entra authentication for user sign-in
- Deploy Azure infrastructure (App Service, Managed Identity, Storage Account)
- Configure secure managed identity authentication for backend and storage
- Create Azure Blob Storage for persistent deployment history (
stmermaid{suffix}) - Automatically create Application Users in ALL configured environments from
data/environments.json - Assign System Customizer security role to all Application Users (grants table access)
- Enable Azure App Service authentication for frontend protection
- Configure SPA platform for frontend authentication (MSAL integration)
The deployment script will:
- Build the React frontend locally using Vite
- Package backend files and multi-environment configuration (
data/environments.json) - Deploy to Azure App Service with proper static file serving
- Configure runtime settings for optimal performance
- Enable persistent deployment history tracking with Azure Blob Storage
- Inject Azure AD authentication configuration into frontend build
Storage Infrastructure
The application includes Azure Blob Storage for persistent deployment history:
- Storage Account:
stmermaid{suffix}(e.g.,stmermaidprod) - Container:
deployment-history(created automatically) - Authentication: Managed Identity with Storage Blob Data Contributor role
- Benefits: Deployment history persists across app restarts and redeployments
- Environment Support: Separate storage paths for each Dataverse environment
For detailed information, see Azure Storage Integration Guide.
Multi-Environment Support
The application supports deploying to multiple Dataverse environments from a single Azure deployment. Users can select the target environment at deployment time.
How It Works
- Environment Configuration:
data/environments.jsoncontains all configured environments - User Selection: Environment dropdown in the Solution Setup wizard step
- Dynamic Routing: Backend routes deployments to the selected environment
- Managed Identity: Single managed identity with application users in each environment
Quick Setup for Multiple Environments
# Configure all environments in config/environments.json
# Then run setup to create application users in each environment
.\scripts\setup-from-config.ps1
Key Features:
- Select target environment from dropdown (dev/test/prod)
- Single Azure deployment serves all environments
- No secrets needed - managed identity authenticates to all environments
- Environment-specific deployment tracking with colored badges
- Multi-environment rollback - safely undo deployments from any environment
- Easy to add new environments - just update configuration
Deployment History & Rollback:
- Persistent Storage: Azure Blob Storage ensures deployment history survives app restarts
- View deployment history filtered by environment (Dev/Test/Prod)
- Each deployment shows colored environment badge for easy identification
- Rollback feature automatically targets the correct environment
- Environment-specific deployment history with downloadable JSON records
- "All Environments" view merges history from all configured environments
- Storage Health Monitoring: Built-in health checks for Azure Storage connectivity
For complete details, see Azure Multi-Environment Guide and Usage Guide.
- Configure authentication middleware for API protection
Local Development Setup
For local development with real Dataverse authentication:
# Clone the repository
git clone https://github.com/LuiseFreese/mermaid.git
cd mermaid
# Step 1: Create App Registration and Dataverse Application User
.\scripts\setup-local-dataverse-user.ps1
# Step 2: Start development servers
.\scripts\dev-local.ps1
The local setup process will:
- Create App Registration with a client secret (if needed)
- Set up Dataverse Application User with a System Customizer role
- Generate
.env.localfile with authentication configuration - Configure local environment for development
The dev script will:
- Load environment variables from
.env.local - Start a backend server with real Dataverse authentication
- Start a frontend development server with hot reload
- Enable API proxy for seamless development =======
- Configure authentication middleware for API protection
feature/github-pages-docs
Prerequisites
- Azure subscription with permissions to create resources
- PowerShell 7+ (recommended) or Windows PowerShell 5.1
- Azure CLI installed and logged in (
az login) - Node.js 18+ (required for local frontend build)
- Access to Dataverse environment where you want to create entities
- Appropriate permissions:
- Azure: Contributor or Owner on subscription
- Microsoft Entra ID: Application Administrator (to create app registrations)
- Dataverse: System Administrator (to create application users and assign System Customizer role)
Security Architecture
The deployment implements defense-in-depth with multiple layers of security:
1. Frontend Protection - Azure App Service Authentication
User Sign-In with Microsoft Entra:
- Users must sign in with their Microsoft Entra (Azure AD) account to access the application
- Azure App Service Easy Auth provides automatic authentication
- JWT tokens are issued to authenticated users
- No anonymous access to the application
Learn more: Azure App Service Authentication and Authorization
Configuration:
{
"platform": {
"enabled": true
},
"globalValidation": {
"requireAuthentication": true,
"unauthenticatedClientAction": "RedirectToLoginPage"
},
"identityProviders": {
"azureActiveDirectory": {
"enabled": true,
"registration": {
"clientId": "your-frontend-app-id"
}
}
}
}
Key point: No client secret needed! Azure App Service Easy Auth handles authentication without storing secrets.
2. Backend Protection - JWT Token Validation
API Endpoint Security:
- All API endpoints require valid JWT tokens from authenticated users
- JWT middleware validates tokens on every request
- Token validation includes:
- Signature verification
- Expiration check
- Issuer validation
- Audience validation
Protected Endpoints:
// Authentication middleware on all API routes
app.use('/api/*', authenticateToken);
app.use('/upload', authenticateToken);
app.use('/wizard', authenticateToken);
JWT Token Flow:
- User signs in via Azure App Service authentication
- Azure issues JWT token to the user
- Frontend sends JWT token with every API request (via
X-MS-TOKEN-AAD-ACCESS-TOKENheader) - Backend validates JWT token before processing request
- Invalid or missing tokens receive 401 Unauthorized response
3. Backend-to-Dataverse - Managed Identity
Passwordless Authentication:
- Backend uses User-Assigned Managed Identity for Dataverse access
- Federated credentials enable secure token exchange with backend App Registration
- Backend App Registration linked to Dataverse Application User
- Access to tables controlled by System Customizer security role (not API permissions)
- Automatic token refresh and management
Token Flow:
- Backend requests token from Azure Managed Identity endpoint
- Managed Identity exchanges federated credential for Dataverse token
- Backend calls Dataverse API with access token
- Dataverse validates token and maps to Application User
- Security role (System Customizer) determines what tables/operations are allowed
Deployment Process
Step 1: Infrastructure Setup
The setup script creates all necessary Azure resources and configures authentication:
# Interactive mode (prompts for configuration if needed)
.\scripts\setup-secretless.ps1 -EnvironmentSuffix "prod"
# OR unattended mode (CI/CD friendly)
.\scripts\setup-secretless.ps1 -EnvironmentSuffix "prod" -Unattended
Prerequisites:
data/environments.jsonmust be configured with your Dataverse environments BEFORE running setup- The script will validate this file exists and contains valid environment configurations
- See
data/environments.example.jsonfor the required format
What gets created:
-
Frontend App Registration - For user sign-in with Microsoft Entra
- Configured for web application authentication
- Redirect URIs set for your App Service
- Integrated with Azure App Service Easy Auth (no client secret needed)
-
Backend App Registration - For Dataverse authentication
- Configured with federated credentials (passwordless)
- Linked to managed identity for token exchange
- No API permissions needed (access controlled by Dataverse Application User security role)
-
Azure Resources:
- Resource Group
- App Service + App Service Plan (Linux, Node.js 20)
- User-Assigned Managed Identity
-
Dataverse Configuration (for ALL environments in
data/environments.json):- Application Users created (one per environment, linked to backend App Registration)
- System Customizer security role assigned to each Application User
- Security role determines what tables and operations are allowed
-
App Service Authentication:
- Azure App Service Easy Auth configured
- Microsoft Entra identity provider enabled
- Requires authentication for all requests
Step 2: Application Deployment
Deploy your application code to the configured infrastructure:
# Deploy code to existing infrastructure
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "prod"
Deployment steps:
- Build Frontend: Vite builds React app for production
- Package Backend: Excludes node_modules and source files
- Package Configuration: Includes
data/environments.jsonfor multi-environment routing - Deploy to App Service: Uses Azure CLI with ZIP deploy
- Configure Settings: Updates App Service configuration
- Validate: Tests endpoints and authentication
Authentication & Authorization
Frontend Authentication Flow
Backend Authentication Flow
Authentication Middleware
The backend implements three levels of authentication:
1. Token Validation (authenticateToken)
// Validates JWT token on every request
// Extracts user information from token
// Attaches user to request object
2. Optional Authentication (optionalAuth)
// Allows both authenticated and anonymous requests
// Used for health checks and public endpoints
// Still validates token if present
3. Role-Based Authorization (requireRole)
// Requires specific roles for access
// Returns 403 Forbidden if role not present
// Supports multiple role requirements
Token Headers
The application uses standard Azure App Service authentication headers:
X-MS-TOKEN-AAD-ACCESS-TOKEN: <user-jwt-token>
X-MS-CLIENT-PRINCIPAL-ID: <user-object-id>
X-MS-CLIENT-PRINCIPAL-NAME: <user-email>
Post-Deployment Configuration
Configure Allowed Users
By default, any user in your Azure tenant can sign in. To restrict access:
Option 1: App Registration (Recommended)
- Go to Azure Portal → App Registrations
- Select your frontend App Registration
- Go to "Enterprise applications" → "Properties"
- Set "User assignment required?" to Yes
- Go to "Users and groups"
- Add specific users or groups
Option 2: App Service Access Restrictions
- Go to Azure Portal → App Service
- Navigate to "Authentication" → "Microsoft"
- Configure "Allowed token audiences"
- Add specific user groups
Enable Deployment History
💡 Only in case you did not provide the Power Platform Environment ID during deployment:
-
Find your Environment ID:
- Go to make.powerapps.com
- Click settings gear → "Session details"
- Copy the "Environment ID"
-
Add to App Service Configuration:
az webapp config appsettings set `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}" `
--settings POWER_PLATFORM_ENVIRONMENT_ID="your-environment-id"
View Deployment History & Rollback
After deploying solutions, users can:
-
View Deployment History:
- Click "View History" button in the application
- Filter by environment (All/Dev/Test/Prod)
- See colored environment badges on each deployment
- View deployment details including entities, relationships, and status
-
Rollback Deployments:
- Select a deployment with "success" or "partial" status
- Click "Rollback" button
- Rollback automatically targets the correct environment
- Monitor real-time progress as components are removed
- Deployment history updates to show rollback status
Multi-Environment Features:
- Each environment maintains separate deployment history
- Rollback operations are environment-aware
- "All Environments" view merges history from all environments
- Environment badges provide visual confirmation of target environment
For user instructions, see Usage Guide - Deployment History.
Updating the Application
Deploy Code Changes
After making code changes, deploy updates:
# Rebuild and redeploy
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "prod"
The deployment is idempotent:
- Safe to run multiple times
- Only updates application code
- Preserves configuration and environment settings
- No downtime during deployment
Update Environment Configuration
If you need to add or modify Dataverse environments after initial setup:
# Step 1: Edit data/environments.json with new environments
# Step 2: Add application users to new environments
.\scripts\add-app-user-to-all-envs.ps1 -AppRegistrationClientId "your-backend-app-id"
# Step 3: Redeploy to include updated configuration
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "prod"
Update Configuration
Update App Service settings without redeployment:
# Update environment variables
az webapp config appsettings set `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}" `
--settings LOG_LEVEL="debug"
Rotate Credentials
No secrets to rotate! This deployment is completely passwordless:
- Frontend authentication: Handled by Azure App Service Easy Auth (no client secrets)
- Backend-to-Dataverse authentication: Uses managed identity with federated credentials (no secrets)
The only credentials that exist are Azure-managed and rotate automatically.
Troubleshooting
Authentication Issues
Problem: "401 Unauthorized" when accessing the application
- Cause: Azure App Service authentication not configured correctly
- Solution:
# Check authentication configuration
az webapp auth show `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}"
# Verify App Registration exists and has correct redirect URIs
az ad app show --id "your-frontend-app-id"
Problem: "Invalid JWT token" in backend logs
- Cause: Token validation failing
- Solution: Check that the JWT token headers are being sent correctly and the token hasn't expired
Problem: Users can't sign in
- Cause: App Registration not configured for user assignment
- Solution: Go to Enterprise Application → Properties → Set "User assignment required" and add users
Deployment Issues
Problem: Build fails during deployment
- Cause: Node.js version mismatch or missing dependencies
- Solution:
# Ensure Node.js 18+ is installed locally
node --version
# Clean and reinstall dependencies
Remove-Item -Path "node_modules" -Recurse -Force
npm install
# Try deployment again
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "myapp"
Problem: "Managed Identity not found"
- Cause: Infrastructure setup didn't complete successfully
- Solution:
# Verify data/environments.json exists and is valid
Get-Content data/environments.json | ConvertFrom-Json
# Re-run infrastructure setup
.\scripts\setup-secretless.ps1 -EnvironmentSuffix "prod" -Unattended
Dataverse Issues
Problem: "Application User not found" in Dataverse calls
- Cause: Application User not created or not linked correctly
- Solution:
# Verify Application User exists in Power Platform Admin Center
# Go to Environments → Your Environment → Settings → Users + permissions → Application users
# Check which environments are configured
Get-Content data/environments.json | ConvertFrom-Json | Select-Object -ExpandProperty environments
# Add application users to all configured environments
.\scripts\add-app-user-to-all-envs.ps1 -AppRegistrationClientId "your-backend-app-id"
Problem: "Insufficient permissions" when creating tables
- Cause: Application User doesn't have System Customizer role in the target environment
- Solution: In Power Platform Admin Center, verify the Application User has System Customizer role assigned in each environment
Problem: "Environment not found in configuration"
- Cause: Selected environment isn't in
data/environments.json - Solution:
# Add the environment to data/environments.json
# Then add application user for the new environment
.\scripts\add-app-user-to-all-envs.ps1 -AppRegistrationClientId "your-backend-app-id"
# Redeploy to include updated configuration
.\scripts\deploy-secretless.ps1 -EnvironmentSuffix "prod"
Monitoring and Diagnostics
Enable detailed logging:
az webapp config appsettings set `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}" `
--settings LOG_LEVEL="debug" LOG_REQUEST_BODY="true"
View application logs:
# Stream logs in real-time
az webapp log tail `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}"
# Download logs
az webapp log download `
--name "app-mermaid-dv-we-{suffix}" `
--resource-group "rg-mermaid-dv-we-{suffix}" `
--log-file "app-logs.zip"
Security Best Practices
- No Secrets to Manage: This deployment is completely passwordless - both frontend and backend use managed authentication
- Monitor Authentication: Use Application Insights to track authentication failures
- Restrict User Access: Only assign access to users who need it
- Enable Audit Logging: Track who deploys what and when
- Keep Dependencies Updated: Regularly update npm packages for security patches
- Review Access Control: Periodically review user assignments and roles
Related Documentation
- Local Development Guide - Set up local development environment
- Architecture Guide - Understanding the system design
- Testing Guide - Running and writing tests
Getting Help
If you encounter issues not covered here:
- Check the logs: Azure App Service logs contain detailed error messages
- Verify prerequisites: Ensure all required tools and permissions are available
- Review security configuration: Check both frontend and backend authentication settings
- Test authentication flow: Use browser dev tools to inspect JWT tokens
- Consult documentation: Review related documentation for specific features