Contents
data/authors/Paul Logan.json

Creating an employee self-service mobile app Pt 1

The Brief

Create a mobile app for company employees to view holiday entitlement and book holiday requests.

Requirements:

  • Works on both Android and Apple phones.
  • Does not require user accounts to be registered in our company Acitve Directory.
  • App should provide self-service registration and authenticate with minimal interaction required from HR and/or IT.

Technologies

  • Progressive Web App
  • Azure Static Web Apps
  • Azure DevOps
  • Entra External ID (aka Microsoft Entra ID for customers)

The first requirement is covered with the use of a PWA. I can use my existing expertise in web development & web platform technologies to provide a native-app experience on both of the dominant mobile phone platforms.

Requirement two and three is covered by utilising Microsoft Entra External ID. A customer identity access management solution that allows users to register and login using their own personal email address.

Steps

Create project in Azure DevOps

  • Create project in Azure DevOps
  • Repos => Initialize main branch with a README or gitignore => Select VisualStudio .gitignore and click Initialize

Entra ID Tenant - Create SWA

  • Create SWA in main Entra ID tenant
  • Plan Type = Standard
  • Deployment details
    • Source = Azure DevOps
    • Build Details = Custom
    • App location = “/src”
    • Api location = “/api”
    • Output location = ""
    • Select Repo created in Azure DevOps above

When the cretion procedure is complete, an Azure Static Web Apps workflow YAML file is automatically created in the Repo.

Create Customer Tenant

  • Create Entra tenant in Azure Documentation Which type of users will you manage in this tenant? = Customer
Not all Tenant Creations are equal
    Ensure you are in your company's main Microsoft Entra ID tenant when performing this step. When writing this post, I selected to create a tenant whilst already in a Customer tenant I had created earlier. The options for the "Select a tenant type" had the "Azure AD B2C" option disabled, meaning there must be different permissions at play in the background.
Subscription Requirement
"If you're creating a customer tenant for the first time, you have the option to create a trial tenant that doesn't require an Azure subscription."

Register an app in the Customer Tenant

  • App registrations
    • Supported account types = Accounts in this organizational directory only (MyCompanyEmployee only - Single tenant)
    • Redirect URIs
      • Platform = Web
      • URI = https://«SWA-URL-created-above»azurestaticapps.net/.auth/login/aad/callback
    • Implicit grant and hybrid flows => ID tokens (used for implicit and hybrid flows)
    • Register
    • API Permissions => Add a permission => Microsoft Graph => Delegated Permissions
      • OpenId permissions:
        • email
        • offline_access
        • openid
        • profile
      • Click the “Grant admin consent for ” button
    • Sidebar => Manage => Certificates & secrets (you will need the “Value” of the newly created secret later on).

Create User Flow

To enable user flow creation, you first need to enable the feature.

  • External Identities => External collaboration settings => “Enable guest self-service sign up via user flows”
  • External Identities => User flows => New user flow
    • Identity Providers = Email one-time passcode
    • User attributes = Given Name, Surname, Display Name
    • Create
    • Click to access new user flow
    • Applications
    • Add application => select app created above

Configure SWA in Entra ID Tenant

  • Go to SWA resource
  • Configuration
    • Add two Application Settings, ClientSecret and ClientID, both values taken from the App Registration in the Customer Tenant.

Coding the SWA

  • Browse to your SWA project in Azure DevOps => Repos
  • Clone project to VS Code
  • Install/Enable the Azure Static Web Apps extension
  • Install/Enable the Azure Functions extension
  • Add the ./api folder
    • F1 => Azure Static Web Apps: Create HTTP Function => If prompted for a folder for your function, browse to the api folder created above.
  • Install SWA CLI
    • npm install -D @azure/static-web-apps-cli (accept helpful tip from VS Code to add node_modules folder to .gitignore file)
    • npx swa init
  • Create the config file
    • “The recommended location for the staticwebapp.config.json is in the folder set as the app_location in the workflow file”
  • Create an index.html file in the ./src folder.

Build Error
Oryx could not find a 'build' or 'build:azure' script in the package configuration. Please add one of these commands to your package configuration file (i.e. package.json).
Alternatively, you can add the app_build_command to the build/deploy section of your deployment configuration file. For example, app_build_command: 'npm run docs:build'
Solution
Add skip_app_build: true

Build Error
Failed to find a default file in the app artifacts folder (/). Valid default files: index.html,Index.html.
Solution
Change app_location from "/" to "./src", the actual folder that the index.html file is in.

The Azure Static Web Apps workflow YAML file:

name: Azure Static Web Apps CI/CD

pr:
  branches:
    include:
      - main
trigger:
  branches:
    include:
      - main

jobs:
- job: build_and_deploy_job
  displayName: Build and Deploy Job
  condition: or(eq(variables['Build.Reason'], 'Manual'),or(eq(variables['Build.Reason'], 'PullRequest'),eq(variables['Build.Reason'], 'IndividualCI')))
  pool:
    vmImage: ubuntu-latest
  variables:
  - group: Azure-Static-Web-Apps-random-words-123456789-variable-group
  steps:
  - checkout: self
    submodules: true
  - task: AzureStaticWebApp@0
    inputs:
      azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN_RANDOM_WORDS_123456789)
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
      app_location: "/src" # App source code path
      api_location: "/api" # Api source code path - optional
      output_location: "" # Built app content directory - optional
      skip_app_build: true
###### End of Repository/Build Configurations ######

Authentication

##Updated 09/02/2024 with resolution of this issue

The Static Web Apps config json file needs to be updated with the settings to implement Entra External ID authentication.

{
    "routes": [
        {
            "route": "/*",
            "allowedRoles": [
                "authenticated"
            ]
        },
        {
            "route": "/logout",
            "redirect": "/.auth/logout"
        },
        {
            "route": "/me",
            "redirect": "/.auth/me"
        }
    ],
    "responseOverrides": {
        "401": {
            "statusCode": 302,
            "redirect": "/.auth/login/aad"
        }
    },
    "trailingSlash": "auto",
    "platform": {
        "apiRuntime": "dotnet-isolated:8.0"
    },
    "auth": {
        "identityProviders": {
            "azureActiveDirectory": {
                "userDetailsClaim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
                "registration": {
                    "openIdIssuer": "https://{TenantID}.ciamlogin.com/{TenantID}/v2.0",
                    "clientIdSettingName": "ClientID",
                    "clientSecretSettingName": "ClientSecret"
                }
            }
        }
    }
}

Browsing to the SWA URL, I am presented with a basic login screen.

Entra External login screen
Entra External login screen
Entra External login screen
Entra External login screen