From 6bb353de89afe790776ba7e1a58d3fb964500059 Mon Sep 17 00:00:00 2001 From: nannal Date: Thu, 15 Jul 2021 22:55:57 +0300 Subject: [PATCH] Initial --- .github/CODE_OF_CONDUCT.md | 9 + .github/ISSUE_TEMPLATE.md | 33 + .github/PULL_REQUEST_TEMPLATE.md | 45 + .gitignore | 121 +++ AppCreationScripts/AppCreationScripts.md | 186 ++++ AppCreationScripts/Cleanup.ps1 | 80 ++ AppCreationScripts/Configure.ps1 | 187 ++++ AppCreationScripts/Steps.md | 224 ++++ AppCreationScripts/apps.json | 33 + AppCreationScripts/sample.json | 41 + CHANGELOG.md | 13 + CONTRIBUTING.md | 76 ++ Dockerfile | 11 + LICENSE.md | 21 + README.md | 243 +++++ index.js | 66 ++ package-lock.json | 1269 ++++++++++++++++++++++ package.json | 16 + 18 files changed, 2674 insertions(+) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitignore create mode 100644 AppCreationScripts/AppCreationScripts.md create mode 100644 AppCreationScripts/Cleanup.ps1 create mode 100644 AppCreationScripts/Configure.ps1 create mode 100644 AppCreationScripts/Steps.md create mode 100644 AppCreationScripts/apps.json create mode 100644 AppCreationScripts/sample.json create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 index.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f9ba8cf --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..15c7f60 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,33 @@ + +> Please provide us with the following information: +> --------------------------------------------------------------- + +### This issue is for a: (mark with an `x`) +``` +- [ ] bug report -> please search issues before submitting +- [ ] feature request +- [ ] documentation issue or request +- [ ] regression (a behavior that used to work and stopped in a new release) +``` + +### Minimal steps to reproduce +> + +### Any log messages given by the failure +> + +### Expected/desired behavior +> + +### OS and Version? +> Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) + +### Versions +> + +### Mention any other details that might be useful + +> --------------------------------------------------------------- +> Thanks! We'll be in touch soon. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ab05e29 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,45 @@ +## Purpose + +* ... + +## Does this introduce a breaking change? + +``` +[ ] Yes +[ ] No +``` + +## Pull Request Type +What kind of change does this Pull Request introduce? + + +``` +[ ] Bugfix +[ ] Feature +[ ] Code style update (formatting, local variables) +[ ] Refactoring (no functional changes, no api changes) +[ ] Documentation content changes +[ ] Other... Please describe: +``` + +## How to Test +* Get the code + +``` +git clone [repo-address] +cd [repo-name] +git checkout [branch-name] +npm install +``` + +* Test the code + +``` +``` + +## What to Check +Verify that the following are valid +* ... + +## Other Information + \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f139f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,121 @@ +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + + + +config.js \ No newline at end of file diff --git a/AppCreationScripts/AppCreationScripts.md b/AppCreationScripts/AppCreationScripts.md new file mode 100644 index 0000000..7512ab4 --- /dev/null +++ b/AppCreationScripts/AppCreationScripts.md @@ -0,0 +1,186 @@ +# Registering the sample apps with the Microsoft identity platform and updating the configuration files using PowerShell + +## Overview + +### Quick summary + +1. On Windows run PowerShell as **Administrator** and navigate to the root of the cloned directory +1. In PowerShell run: + + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force + ``` + +1. Run the script to create your Azure AD application and configure the code of the sample application accordingly. (Other ways of running the scripts are described below) + + ```PowerShell + cd .\AppCreationScripts\ + .\Configure.ps1 + ``` + +1. Open the Visual Studio solution and click start + +### More details + +The following paragraphs: + +- [Registering the sample apps with the Microsoft identity platform and updating the configuration files using PowerShell](#Registering-the-sample-apps-with-the-Microsoft-identity-platform-and-updating-the-configuration-files-using-PowerShell) + - [Overview](#Overview) + - [Quick summary](#Quick-summary) + - [More details](#More-details) + - [Goal of the provided scripts](#Goal-of-the-provided-scripts) + - [Presentation of the scripts](#Presentation-of-the-scripts) + - [Usage pattern for tests and DevOps scenarios](#Usage-pattern-for-tests-and-DevOps-scenarios) + - [How to use the app creation scripts?](#How-to-use-the-app-creation-scripts) + - [Pre-requisites](#Pre-requisites) + - [Run the script and start running](#Run-the-script-and-start-running) + - [Four ways to run the script](#Four-ways-to-run-the-script) + - [Option 1 (interactive)](#Option-1-interactive) + - [Option 2 (non-interactive)](#Option-2-non-interactive) + - [Option 3 (Interactive, but create apps in a specified tenant)](#Option-3-Interactive-but-create-apps-in-a-specified-tenant) + - [Option 4 (non-interactive, and create apps in a specified tenant)](#Option-4-non-interactive-and-create-apps-in-a-specified-tenant) + - [Running the script on Azure Sovereign clouds](#Running-the-script-on-Azure-Sovereign-clouds) + +## Goal of the provided scripts + +### Presentation of the scripts + +This sample comes with two PowerShell scripts, which automate the creation of the Azure Active Directory applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. + +These scripts are: + +- `Configure.ps1` which: + - creates Azure AD applications and their related objects (permissions, dependencies, secrets), + - changes the configuration files in the C# and JavaScript projects. + - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Azure AD application it created: + - the identifier of the application + - the AppId of the application + - the url of its registration in the [Azure portal](https://portal.azure.com). + +- `Cleanup.ps1` which cleans-up the Azure AD objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from Visual Studio, or from the command line using, for instance, git reset). + +### Usage pattern for tests and DevOps scenarios + +The `Configure.ps1` will stop if it tries to create an Azure AD application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. + +## How to use the app creation scripts? + +### Pre-requisites + +1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) +1. Navigate to the root directory of the project. +1. Until you change it, the default [Execution Policy](https:/go.microsoft.com/fwlink/?LinkID=135170) for scripts is usually `Restricted`. In order to run the PowerShell script you need to set the Execution Policy to `RemoteSigned`. You can set this just for the current PowerShell process by running the command: + + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process + ``` + +### (Optionally) install AzureAD PowerShell modules + +The scripts install the required PowerShell module (AzureAD) for the current user if needed. However, if you want to install if for all users on the machine, you can follow the following steps: + +1. If you have never done it already, in the PowerShell window, install the AzureAD PowerShell modules. For this: + + 1. Open PowerShell as admin (On Windows, Search Powershell in the search bar, right click on it and select Run as administrator). + 2. Type: + + ```PowerShell + Install-Module AzureAD + ``` + + or if you cannot be administrator on your machine, run: + + ```PowerShell + Install-Module AzureAD -Scope CurrentUser + ``` + +### Run the script and start running + +1. Go to the `AppCreationScripts` sub-folder. From the folder where you cloned the repo, + + ```PowerShell + cd AppCreationScripts + ``` + +1. Run the scripts. See below for the [four options](#four-ways-to-run-the-script) to do that. +1. Open the Visual Studio solution, and in the solution's context menu, choose **Set Startup Projects**. +1. select **Start** for the projects + +You're done. this just works! + +### Four ways to run the script + +We advise four ways of running the script: + +- Interactive: you will be prompted for credentials, and the scripts decide in which tenant to create the objects, +- non-interactive: you will provide credentials, and the scripts decide in which tenant to create the objects, +- Interactive in specific tenant: you will provide the tenant in which you want to create the objects and then you will be prompted for credentials, and the scripts will create the objects, +- non-interactive in specific tenant: you will provide tenant in which you want to create the objects and credentials, and the scripts will create the objects. + +Here are the details on how to do this. + +#### Option 1 (interactive) + +- Just run ``. .\Configure.ps1``, and you will be prompted to sign-in (email address, password, and if needed MFA). +- The script will be run as the signed-in user and will use the tenant in which the user is defined. + +Note that the script will choose the tenant in which to create the applications, based on the user. Also to run the `Cleanup.ps1` script, you will need to re-sign-in. + +#### Option 2 (non-interactive) + +When you know the identity and credentials of the user in the name of whom you want to create the applications, you can use the non-interactive approach. It's more adapted to DevOps. Here is an example of script you'd want to run in a PowerShell Window + +```PowerShell +$secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force +$mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) +. .\Cleanup.ps1 -Credential $mycreds +. .\Configure.ps1 -Credential $mycreds +``` + +Of course, in real life, you might already get the password as a `SecureString`. You might also want to get the password from KeyVault. + +#### Option 3 (Interactive, but create apps in a specified tenant) + + if you want to create the apps in a particular tenant, you can use the following option: + +- open the [Azure portal](https://portal.azure.com) +- Select the Azure Active directory you are interested in (in the combo-box below your name on the top right of the browser window) +- Find the "Active Directory" object in this tenant +- Go to **Properties** and copy the content of the **Directory Id** property +- Then use the full syntax to run the scripts: + +```PowerShell +$tenantId = "yourTenantIdGuid" +. .\Cleanup.ps1 -TenantId $tenantId +. .\Configure.ps1 -TenantId $tenantId +``` + +#### Option 4 (non-interactive, and create apps in a specified tenant) + +This option combines option 2 and option 3: it creates the application in a specific tenant. See option 3 for the way to get the tenant Id. Then run: + +```PowerShell +$secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force +$mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) +$tenantId = "yourTenantIdGuid" +. .\Cleanup.ps1 -Credential $mycreds -TenantId $tenantId +. .\Configure.ps1 -Credential $mycreds -TenantId $tenantId +``` + +### Running the script on Azure Sovereign clouds + +All the four options listed above, can be used on any Azure Sovereign clouds. By default, the script targets `AzureCloud`, but it can be changed using the parameter `-AzureEnvironmentName`. + +The acceptable values for this parameter are: + +- AzureCloud +- AzureChinaCloud +- AzureUSGovernment +- AzureGermanyCloud + +Example: + + ```PowerShell + . .\Cleanup.ps1 -AzureEnvironmentName "AzureGermanyCloud" + . .\Configure.ps1 -AzureEnvironmentName "AzureGermanyCloud" + ``` diff --git a/AppCreationScripts/Cleanup.ps1 b/AppCreationScripts/Cleanup.ps1 new file mode 100644 index 0000000..73c194a --- /dev/null +++ b/AppCreationScripts/Cleanup.ps1 @@ -0,0 +1,80 @@ +[CmdletBinding()] +param( + [PSCredential] $Credential, + [Parameter(Mandatory=$False, HelpMessage='Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] + [string] $tenantId, + [Parameter(Mandatory=$False, HelpMessage='Azure environment to use while running the script (it defaults to AzureCloud)')] + [string] $azureEnvironmentName +) + +#Requires -Modules AzureAD -RunAsAdministrator + + +if ($null -eq (Get-Module -ListAvailable -Name "AzureAD")) { + Install-Module "AzureAD" -Scope CurrentUser +} +Import-Module AzureAD +$ErrorActionPreference = "Stop" + +Function Cleanup +{ + if (!$azureEnvironmentName) + { + $azureEnvironmentName = "AzureCloud" + } + + <# + .Description + This function removes the Azure AD applications for the sample. These applications were created by the Configure.ps1 script + #> + + # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant + # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. + + # Login to Azure PowerShell (interactive if credentials are not already provided: + # you'll need to sign-in with creds enabling your to create apps in the tenant) + if (!$Credential -and $TenantId) + { + $creds = Connect-AzureAD -TenantId $tenantId -AzureEnvironmentName $azureEnvironmentName + } + else + { + if (!$TenantId) + { + $creds = Connect-AzureAD -Credential $Credential -AzureEnvironmentName $azureEnvironmentName + } + else + { + $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential -AzureEnvironmentName $azureEnvironmentName + } + } + + if (!$tenantId) + { + $tenantId = $creds.Tenant.Id + } + $tenant = Get-AzureADTenantDetail + $tenantName = ($tenant.VerifiedDomains | Where-Object { $_._Default -eq $True }).Name + + # Removes the applications + Write-Host "Cleaning-up applications from tenant '$tenantName'" + + Write-Host "Removing 'webApp' (ms-identity-node) if needed" + Get-AzureADApplication -Filter "DisplayName eq 'ms-identity-node'" | ForEach-Object {Remove-AzureADApplication -ObjectId $_.ObjectId } + $apps = Get-AzureADApplication -Filter "DisplayName eq 'ms-identity-node'" + if ($apps) + { + Remove-AzureADApplication -ObjectId $apps.ObjectId + } + + foreach ($app in $apps) + { + Remove-AzureADApplication -ObjectId $app.ObjectId + Write-Host "Removed ms-identity-node.." + } + # also remove service principals of this app + Get-AzureADServicePrincipal -filter "DisplayName eq 'ms-identity-node'" | ForEach-Object {Remove-AzureADServicePrincipal -ObjectId $_.Id -Confirm:$false} + +} + +Cleanup -Credential $Credential -tenantId $TenantId \ No newline at end of file diff --git a/AppCreationScripts/Configure.ps1 b/AppCreationScripts/Configure.ps1 new file mode 100644 index 0000000..03ba2e0 --- /dev/null +++ b/AppCreationScripts/Configure.ps1 @@ -0,0 +1,187 @@ +[CmdletBinding()] +param( + [PSCredential] $Credential, + [Parameter(Mandatory=$False, HelpMessage='Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] + [string] $tenantId, + [Parameter(Mandatory=$False, HelpMessage='Azure environment to use while running the script (it defaults to AzureCloud)')] + [string] $azureEnvironmentName +) + +#Requires -Modules AzureAD -RunAsAdministrator + +<# + This script creates the Azure AD applications needed for this sample and updates the configuration files + for the visual Studio projects from the data in the Azure AD applications. + + Before running this script you need to install the AzureAD cmdlets as an administrator. + For this: + 1) Run Powershell as an administrator + 2) in the PowerShell window, type: Install-Module AzureAD + + There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. +#> + +# Create a password that can be used as an application key +Function ComputePassword +{ + $aesManaged = New-Object "System.Security.Cryptography.AesManaged" + $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC + $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros + $aesManaged.BlockSize = 128 + $aesManaged.KeySize = 256 + $aesManaged.GenerateKey() + return [System.Convert]::ToBase64String($aesManaged.Key) +} + +# Create an application key +# See https://www.sabin.io/blog/adding-an-azure-active-directory-application-and-key-using-powershell/ +Function CreateAppKey([DateTime] $fromDate, [double] $durationInYears, [string]$pw) +{ + $endDate = $fromDate.AddYears($durationInYears) + $keyId = (New-Guid).ToString(); + $key = New-Object Microsoft.Open.AzureAD.Model.PasswordCredential + $key.StartDate = $fromDate + $key.EndDate = $endDate + $key.Value = $pw + $key.KeyId = $keyId + return $key +} + +Function ReplaceInLine([string] $line, [string] $key, [string] $value) +{ + $index = $line.IndexOf($key) + if ($index -ige 0) + { + $index2 = $index+$key.Length + $line = $line.Substring(0, $index) + $value + $line.Substring($index2) + } + return $line +} + +Function ReplaceInTextFile([string] $configFilePath, [System.Collections.HashTable] $dictionary) +{ + $lines = Get-Content $configFilePath + $index = 0 + while($index -lt $lines.Length) + { + $line = $lines[$index] + foreach($key in $dictionary.Keys) + { + if ($line.Contains($key)) + { + $lines[$index] = ReplaceInLine $line $key $dictionary[$key] + } + } + $index++ + } + + Set-Content -Path $configFilePath -Value $lines -Force +} + +Set-Content -Value "" -Path createdApps.html +Add-Content -Value "" -Path createdApps.html + +$ErrorActionPreference = "Stop" + +Function ConfigureApplications +{ +<#.Description + This function creates the Azure AD applications for the sample in the provided Azure AD tenant and updates the + configuration files in the client and service project of the visual studio solution (App.Config and Web.Config) + so that they are consistent with the Applications parameters +#> + $commonendpoint = "common" + + if (!$azureEnvironmentName) + { + $azureEnvironmentName = "AzureCloud" + } + + # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant + # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. + + # Login to Azure PowerShell (interactive if credentials are not already provided: + # you'll need to sign-in with creds enabling your to create apps in the tenant) + if (!$Credential -and $TenantId) + { + $creds = Connect-AzureAD -TenantId $tenantId -AzureEnvironmentName $azureEnvironmentName + } + else + { + if (!$TenantId) + { + $creds = Connect-AzureAD -Credential $Credential -AzureEnvironmentName $azureEnvironmentName + } + else + { + $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential -AzureEnvironmentName $azureEnvironmentName + } + } + + if (!$tenantId) + { + $tenantId = $creds.Tenant.Id + } + + + + $tenant = Get-AzureADTenantDetail + $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name + + # Get the user running the script to add the user as the app owner + $user = Get-AzureADUser -ObjectId $creds.Account.Id + + # Create the webApp AAD application + Write-Host "Creating the AAD application (ms-identity-node)" + # Get a 2 years application key for the webApp Application + $pw = ComputePassword + $fromDate = [DateTime]::Now; + $key = CreateAppKey -fromDate $fromDate -durationInYears 2 -pw $pw + $webAppAppKey = $pw + # create the application + $webAppAadApplication = New-AzureADApplication -DisplayName "ms-identity-node" ` + -HomePage "http://localhost:3000" ` + -ReplyUrls "http://localhost:3000/redirect" ` + -IdentifierUris "https://$tenantName/ms-identity-node" ` + -PasswordCredentials $key ` + -PublicClient $False + + # create the service principal of the newly created application + $currentAppId = $webAppAadApplication.AppId + $webAppServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} + + # add the user running the script as an app owner if needed + $owner = Get-AzureADApplicationOwner -ObjectId $webAppAadApplication.ObjectId + if ($owner -eq $null) + { + Add-AzureADApplicationOwner -ObjectId $webAppAadApplication.ObjectId -RefObjectId $user.ObjectId + Write-Host "'$($user.UserPrincipalName)' added as an application owner to app '$($webAppServicePrincipal.DisplayName)'" + } + + + Write-Host "Done creating the webApp application (ms-identity-node)" + + # URL of the AAD application in the Azure portal + # Future? $webAppPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$webAppAadApplication.AppId+"/objectId/"+$webAppAadApplication.ObjectId+"/isMSAApp/" + $webAppPortalUrl = "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/"+$webAppAadApplication.AppId+"/objectId/"+$webAppAadApplication.ObjectId+"/isMSAApp/" + Add-Content -Value "" -Path createdApps.html + + + # Update config file for 'webApp' + $configFile = $pwd.Path + "\..\index.js" + Write-Host "Updating the sample code ($configFile)" + $dictionary = @{ "Enter_the_Application_Id_Here" = $webAppAadApplication.AppId;"Enter_the_Cloud_Instance_Id_HereEnter_the_Tenant_Info_Here" = 'https://login.microsoftonline.com/common';"Enter_the_Client_Secret_Here" = $webAppAppKey }; + ReplaceInTextFile -configFilePath $configFile -dictionary $dictionary + + Add-Content -Value "
ApplicationAppIdUrl in the Azure portal
webApp$currentAppIdms-identity-node
" -Path createdApps.html +} + +# Pre-requisites +if ((Get-Module -ListAvailable -Name "AzureAD") -eq $null) { + Install-Module "AzureAD" -Scope CurrentUser +} + +Import-Module AzureAD + +# Run interactively (will ask you for the tenant ID) +ConfigureApplications -Credential $Credential -tenantId $TenantId \ No newline at end of file diff --git a/AppCreationScripts/Steps.md b/AppCreationScripts/Steps.md new file mode 100644 index 0000000..de10c68 --- /dev/null +++ b/AppCreationScripts/Steps.md @@ -0,0 +1,224 @@ +--- +page_type: sample +languages: + - csharp + - javascript + - typescript + - python + - java +products: + - node.js + - dotnet + - aspnet + - aspnet-core + - dotnet-core + - ms-graph + - azure-app-service + - azure-storage + - azure-active-directory + - azure-active-directory-b2c +name: A Node.js & Express web app authenticating users against Azure AD with MSAL Node +urlFragment: ms-identity-javascript-nodejs-tutorial +description: "This sample demonstrates a Node.js & Express web app that authenticates users against Azure AD" +azureDeploy: +extendedZipContent: +extensions: +--- +# A Node.js & Express web app authenticating users against Azure AD with MSAL Node + + 1. [Overview](#overview) + 1. [Scenario](#scenario) + 1. [Contents](#contents) + 1. [Prerequisites](#prerequisites) + 1. [Setup](#setup) + 1. [Registration](#registration) + 1. [Running the sample](#running-the-sample) + 1. [Explore the sample](#explore-the-sample) + 1. [About the code](#about-the-code) + 1. [Deployment](#deployment) + 1. [More information](#more-information) + 1. [Community Help and Support](#community-help-and-support) + 1. [Contributing](#contributing) + +![Build badge](https://identitydivision.visualstudio.com/_apis/public/build/definitions/a7934fdd-dcde-4492-a406-7fad6ac00e17//badge) + +## Overview + +This sample demonstrates a Node.js & Express web app that authenticates users against Azure AD. + +## Scenario + +1. The client Node.js & Express web app uses the Microsoft Authentication Library (MSAL) to obtain an ID Token from **Azure AD**. +2. The **ID Token** proves that the user has successfully authenticated against **Azure AD**. + +![Overview](./ReadmeFiles/topology.png) + +## Contents + +> Give a high-level folder structure of the sample. + +| File/folder | Description | +|-------------------|--------------------------------------------| +| `CHANGELOG.md` | List of changes to the sample. | +| `CONTRIBUTING.md` | Guidelines for contributing to the sample. | +| `LICENSE` | The license for the sample. | + +## Prerequisites + +- An **Azure AD** tenant. For more information see: [How to get an Azure AD tenant](https://docs.microsoft.com/azure/active-directory/develop/quickstart-create-new-tenant) +- A user account in your **Azure AD** tenant. This sample will not work with a **personal Microsoft account**. Therefore, if you signed in to the [Azure portal](https://portal.azure.com) with a personal account and have never created a user account in your directory before, you need to do that now. + +## Setup + +### Step 1: Clone or download this repository + +From your shell or command line: + +```console + git clone https://github.com/Azure-Samples/ms-identity-javascript-nodejs-tutorial.git +``` + +or download and extract the repository .zip file. + +> :warning: To avoid path length limitations on Windows, we recommend cloning into a directory near the root of your drive. + +### Register the sample application(s) with your Azure Active Directory tenant + +There is one project in this sample. To register it, you can: + +- follow the steps below for manually register your apps +- or use PowerShell scripts that: + - **automatically** creates the Azure AD applications and related objects (passwords, permissions, dependencies) for you. + - modify the projects' configuration files. + +
+ Expand this section if you want to use this automation: + +> :warning: If you have never used **Azure AD Powershell** before, we recommend you go through the [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) once to ensure that your environment is prepared correctly for this step. + +1. On Windows, run PowerShell as **Administrator** and navigate to the root of the cloned directory +1. If you have never used Azure AD Powershell before, we recommend you go through the [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) once to ensure that your environment is prepared correctly for this step. +1. In PowerShell run: + + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force + ``` + +1. Run the script to create your Azure AD application and configure the code of the sample application accordingly. +1. In PowerShell run: + + ```PowerShell + cd .\AppCreationScripts\ + .\Configure.ps1 + ``` + + > Other ways of running the scripts are described in [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) + > The scripts also provide a guide to automated application registration, configuration and removal which can help in your CI/CD scenarios. + +
+ +### Choose the Azure AD tenant where you want to create your applications + +As a first step you'll need to: + +1. Sign in to the [Azure portal](https://portal.azure.com). +1. If your account is present in more than one Azure AD tenant, select your profile at the top right corner in the menu on top of the page, and then **switch directory** to change your portal session to the desired Azure AD tenant. + +### Register the webApp app (ms-identity-node) + +1. Navigate to the [Azure portal](https://portal.azure.com) and select the **Azure AD** service. +1. Select the **App Registrations** blade on the left, then select **New registration**. +1. In the **Register an application page** that appears, enter your application's registration information: + - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `ms-identity-node`. + - Under **Supported account types**, select **Accounts in this organizational directory only**. + - In the **Redirect URI (optional)** section, select **Web** in the combo-box and enter the following redirect URI: `http://localhost:3000/redirect`. +1. Select **Register** to create the application. +1. In the app's registration screen, find and note the **Application (client) ID**. You use this value in your app's configuration file(s) later in your code. +1. Select **Save** to save your changes. +1. In the app's registration screen, select the **Certificates & secrets** blade in the left to open the page where we can generate secrets and upload certificates. +1. In the **Client secrets** section, select **New client secret**: + - Type a key description (for instance `app secret`), + - Select one of the available key durations (**In 1 year**, **In 2 years**, or **Never Expires**) as per your security posture. + - The generated key value will be displayed when you select the **Add** button. Copy the generated value for use in the steps later. + - You'll need this key later in your code's configuration files. This key value will not be displayed again, and is not retrievable by any other means, so make sure to note it from the Azure portal before navigating to any other screen or blade. + +#### Configure the webApp app (ms-identity-node) to use your app registration + +Open the project in your IDE (like Visual Studio or Visual Studio Code) to configure the code. + +> In the steps below, "ClientID" is the same as "Application ID" or "AppId". + +1. Open the `index.js` file. +1. Find the key `Enter_the_Application_Id_Here` and replace the existing value with the application ID (clientId) of `ms-identity-node` app copied from the Azure portal. +1. Find the key `Enter_the_Cloud_Instance_Id_HereEnter_the_Tenant_Info_Here` and replace the existing value with 'https://login.microsoftonline.com/common'. +1. Find the key `Enter_the_Client_Secret_Here` and replace the existing value with the key you saved during the creation of `ms-identity-node` copied from the Azure portal. + +## Running the sample + +## Explore the sample + +> Explain how to explore the sample. +> Insert a screenshot of the client application. + +> :information_source: Did the sample not work for you as expected? Then please reach out to us using the [GitHub Issues](../../../issues) page. + +## We'd love your feedback! + +Were we successful in addressing your learning objective? Consider taking a moment to [share your experience with us](Enter_Survey_Form_Link). + +## About the code + +> - Describe where the code uses auth libraries, or calls the graph +> - Describe specific aspects (e.g. caching, validation etc.) + +## Deployment + + +### Deploying web app to Azure App Services + +There is one web app in this sample. To deploy it to **Azure App Services**, you'll need to: + +- create an **Azure App Service** +- publish the projects to the **App Services**, and +- update its client(s) to call the website instead of the local environment. +#### Update the Azure AD app registration (ms-identity-node) + +1. Navigate back to to the [Azure portal](https://portal.azure.com). +In the left-hand navigation pane, select the **Azure Active Directory** service, and then select **App registrations (Preview)**. +1. In the resulting screen, select the `ms-identity-node` application. +1. In the app's registration screen, select **Authentication** in the menu. + - In the **Redirect URIs** section, update the reply URLs to match the site URL of your Azure deployment. For example: + - `https://ms-identity-node.azurewebsites.net/redirect` + +> :warning: If your app is using an *in-memory* storage, **Azure App Services** will spin down your web site if it is inactive, and any records that your app was keeping will emptied. In addition, if you increase the instance count of your website, requests will be distributed among the instances. Your app's records, therefore, will not be the same on each instance. + + +## More information + +- [Microsoft identity platform (Azure Active Directory for developers)](https://docs.microsoft.com/azure/active-directory/develop/) +- [Overview of Microsoft Authentication Library (MSAL)](https://docs.microsoft.com/azure/active-directory/develop/msal-overview) +- [Quickstart: Register an application with the Microsoft identity platform (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app) +- [Quickstart: Configure a client application to access web APIs (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis) +- [Understanding Azure AD application consent experiences](https://docs.microsoft.com/azure/active-directory/develop/application-consent-experience) +- [Understand user and admin consent](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent) +- [Application and service principal objects in Azure Active Directory](https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals) +- [National Clouds](https://docs.microsoft.com/azure/active-directory/develop/authentication-national-cloud#app-registration-endpoints) +- [MSAL code samples](https://docs.microsoft.com/azure/active-directory/develop/sample-v2-code) + +For more information about how OAuth 2.0 protocols work in this scenario and other scenarios, see [Authentication Scenarios for Azure AD](https://docs.microsoft.com/azure/active-directory/develop/authentication-flows-app-scenarios). + +## Community Help and Support + +Use [Stack Overflow](http://stackoverflow.com/questions/tagged/msal) to get support from the community. +Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before. +Make sure that your questions or comments are tagged with [`azure-active-directory` `azure-ad-b2c` `ms-identity` `adal` `msal`]. + +If you find a bug in the sample, raise the issue on [GitHub Issues](../../../issues). + +To provide feedback on or suggest features for Azure Active Directory, visit [User Voice page](https://feedback.azure.com/forums/169401-azure-active-directory). + +## Contributing + +If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. \ No newline at end of file diff --git a/AppCreationScripts/apps.json b/AppCreationScripts/apps.json new file mode 100644 index 0000000..7d25a1c --- /dev/null +++ b/AppCreationScripts/apps.json @@ -0,0 +1,33 @@ +{ + "Sample": { + "Title": "A Node.js & Express web app authenticating users against Azure AD with MSAL Node", + "Level": 100, + "Client": "Node.js & Express web app" + }, + "AppRegistrations": [ + { + "x-ms-id": "webApp", + "x-ms-name": "ms-identity-node", + "x-ms-version": "2.0", + "replyUrlsWithType": [ + { + "url": "http://localhost:3000/redirect", + "type": "Web" + } + ], + "oauth2AllowImplicitFlow": false, + "oauth2AllowIdTokenImplicitFlow": false, + "codeConfigurations": [ + { + "settingFile": "/index.js", + "replaceTokens": { + "appId": "Enter_the_Application_Id_Here", + "tenantId": "Enter_the_Tenant_Info_Here", + "clientSecret": "Enter_the_Client_Secret_Here", + "authorityEndpointHost": "Enter_the_Cloud_Instance_Id_Here" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/AppCreationScripts/sample.json b/AppCreationScripts/sample.json new file mode 100644 index 0000000..c8ebaf4 --- /dev/null +++ b/AppCreationScripts/sample.json @@ -0,0 +1,41 @@ +{ + "Sample": { + "Title": "A Node.js & Express web app authenticating users against Azure AD with MSAL Node", + "Level": 100, + "Client": "Node.js & Express web app", + "RepositoryUrl": "ms-identity-javascript-nodejs-tutorial", + "Endpoint": "AAD v2.0" + }, + "AADApps": [ + { + "Id": "webApp", + "Name": "ms-identity-node", + "Kind": "WebApp", + "Audience": "AzureADMyOrg", + "HomePage": "http://localhost:3000", + "ReplyUrls": "http://localhost:3000/redirect", + "PasswordCredentials": "Auto" + } + ], + "CodeConfiguration": [ + { + "App": "webApp", + "SettingKind": "Replace", + "SettingFile": "\\..\\index.js", + "Mappings": [ + { + "key": "Enter_the_Application_Id_Here", + "value": ".AppId" + }, + { + "key": "Enter_the_Cloud_Instance_Id_HereEnter_the_Tenant_Info_Here", + "value": "'https://login.microsoftonline.com/common'" + }, + { + "key": "Enter_the_Client_Secret_Here", + "value": ".AppKey" + } + ] + } + ] + } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9824752 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +## [project-title] Changelog + + +# x.y.z (yyyy-mm-dd) + +*Features* +* ... + +*Bug Fixes* +* ... + +*Breaking Changes* +* ... diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a9115cf --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,76 @@ +# Contributing to [project-title] + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + + - [Code of Conduct](#coc) + - [Issues and Bugs](#issue) + - [Feature Requests](#feature) + - [Submission Guidelines](#submit) + +## Code of Conduct +Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +## Found an Issue? +If you find a bug in the source code or a mistake in the documentation, you can help us by +[submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can +[submit a Pull Request](#submit-pr) with a fix. + +## Want a Feature? +You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub +Repository. If you would like to *implement* a new feature, please submit an issue with +a proposal for your work first, to be sure that we can use it. + +* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). + +## Submission Guidelines + +### Submitting an Issue +Before you submit an issue, search the archive, maybe your question was already answered. + +If your issue appears to be a bug, and hasn't been reported, open a new issue. +Help us to maximize the effort we can spend fixing issues and adding new +features, by not reporting duplicate issues. Providing the following information will increase the +chances of your issue being dealt with quickly: + +* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps +* **Version** - what version is affected (e.g. 0.1.2) +* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you +* **Browsers and Operating System** - is this a problem with all browsers? +* **Reproduce the Error** - provide a live example or a unambiguous set of steps +* **Related Issues** - has a similar issue been reported before? +* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be + causing the problem (line of code or commit) + +You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new]. + +### Submitting a Pull Request (PR) +Before you submit your Pull Request (PR) consider the following guidelines: + +* Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR + that relates to your submission. You don't want to duplicate effort. + +* Make your changes in a new git fork: + +* Commit your changes using a descriptive commit message +* Push your fork to GitHub: +* In GitHub, create a pull request +* If we suggest changes then: + * Make the required updates. + * Rebase your fork and force push to your GitHub repository (this will update your Pull Request): + + ```shell + git rebase master -i + git push -f + ``` + +That's it! Thank you for your contribution! diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..71614bb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node + +ADD ./ /auth + +WORKDIR /auth + +RUN npm i + +EXPOSE 3000 + +CMD ["npm", "start"] \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7965606 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed10521 --- /dev/null +++ b/README.md @@ -0,0 +1,243 @@ +--- +page_type: sample +languages: +- javascript +products: +- nodejs +- azure-active-directory +description: "Add authentication to a Node.js web application with the Microsoft Authentication Library for Node.js (MSAL Node)." +urlFragment: "quickstart-v2-nodejs-webapp-msal" +--- + +# Add user authentication to a Node web app with MSAL + +This sample Node.js web application uses the Microsoft Authentication Library for Node.js (MSAL Node.js) to sign in users by using the OAuth 2.0 authorization code flow. + +You can find additional information about supporting user sign-in in your web apps by using the Microsoft identity platform on docs.microsoft.com: [Scenario: Web app that signs in users](https://docs.microsoft.com/azure/active-directory/develop/scenario-web-app-sign-user-overview?tabs=aspnetcore). + +## Prerequisites + +- [Node.js](https://nodejs.org/en/) + +## Register the application + +First, complete the steps in [Register an application with the Microsoft identity platform](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app) to register the app. + +Use the following settings for your app registration: + +- Name: `MSAL Node Sample` (suggested) +- Supported account types: **Accounts in any organizational directory and personal Microsoft accounts** +- Platform type: **Web** +- Redirect URI: `http://localhost:3000/redirect` +- Client secret: `*********` (record this value after creation - it's shown only once) + +## Clone the repository + +Next, get the files included in this code sample. + +SSH: + +```bash +$ git clone git@github.com:AzureAD/ms-identity-node.git +``` + +HTTP: + +```bash +$ git clone https://github.com/AzureAD/ms-identity-node.git +``` + +You can also download the repository by selecting **Download ZIP** from the repository's dropdown menu. You can decompress it locally and explore the code. + +## Install the package + +To install the MSAL Node package: + +```bash +npm install @azure/msal-node +``` + +If you are customizing MSAL Node or building locally: + +```bash +npm run build:package +``` + +## Configure the sample code + +Open the *index.js* file and find the `config` object. Modify the `config` object with values from your [app's registration in the Azure portal](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app). + +Find your app's registration in the [Azure portal](https://portal.azure.com) and populate the `config` object with the following values: + +* `clientId`: **Application (client) ID** +* `authority`: `https://login.microsoftonline.com/common` +* `clientSecret`: `********` (recorded during app registration - see [Prerequisites](#)) + +You have finished the basic configuration! + +> TIP: You can support different account types by specifying other [authority options](https://docs.microsoft.com/azure/active-directory/develop/msal-client-application-configuration). Unless you have a need to restrict users of your app to a single organization, we suggest you use the default authority shown here. User restrictions can be placed later in the application flow if needed. + +## Run the sample app + +1. From the command line, let npm install any needed dependencies. This only needs to be done once. + + ```bash + $ npm install + ``` + +1. Once the dependencies are installed, you can run the sample application by using the following command: + + ```bash + $ npm start + ``` + +1. Navigate to http://localhost:3000 (or whatever port number specified) with the browser of your choice. + +#### Customize application start + +To customize the start script, modify the *package.json* file. + +## Add authentication to an existing application + +### Import the Configuration Object + +If you set up the sample with your app registration, you may be able to copy this object directly into your application. + +```js +const config = { + auth: { + clientId: "12d77c73-d09d-406a-3asd-3d4e576f7d9b", + authority: "https://login.microsoftonline.com/common", + clientSecret: "" + }, +    system: { +        loggerOptions: { +            loggerCallback(loglevel, message, containsPii) { +                console.log(message); +            }, +         piiLoggingEnabled: false, +         logLevel: msal.LogLevel.Verbose, +        } +    } +}; +``` + +### Configure Dependencies + +Add the dependency on MSAL Node to your Node app. + +```js +const msal = require('@azure/msal-node'); +``` + +### Initialize MSAL Node at runtime + +Initialize the app object within your web app. + +```js +const pca = new msal.ConfidentialClientApplication(config); +``` + +### Configure sign-in request + +Choose the route that requires sign-in. Within that route, set up permissions and direct the MSAL Node app object to attempt sign-in. + +In this code sample, the user is immediately signed-in. If you want all users to be logged in before they view anything, then you can use the same process. Add the sign-in code to the default route: + +```js +app.get('/', (req, res) => { +``` + +Next, pick the `scopes` related to the user. If you're logging in a user, you must at minimum request access to basic user information. The default scope of `user.read` grants that basic access. To learn more, see the [Microsoft Graph permissions reference](https://docs.microsoft.com/graph/permissions-reference). + +```js + const authCodeUrlParameters = { + scopes: ["user.read"], + redirectUri: "http://localhost:3000/redirect", + }; +``` + +The `redirectUri` is the return route. After logging in a user, they'll hit this route. Your application logic will take over here. You'll want to customize the `redirectUri` for your application. + +Next, direct the user to authenticate. The following code block directs the user based on the `authority` you set in the config and directs the user as needed. + +```js + pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => { + res.redirect(response); + }).catch((error) => console.log(JSON.stringify(error))); +``` + +Putting together the routing and all the logic for starting the sign-in yields the following code: + +```js +app.get('/', (req, res) => { + const authCodeUrlParameters = { + scopes: ["user.read"], + redirectUri: "http://localhost:3000/redirect", + }; + + pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => { + res.redirect(response); + }).catch((error) => console.log(JSON.stringify(error))); +}); +``` + +### Configure sign-in response + +The next step occurs after the redirect. Your application must first *complete* the sign-in flow by processing the code and validating the incoming request. + +First, configure the route where your app should receive the response. This must match your app registration's configuration in the Azure portal. + +```js +app.get('/redirect', (req, res) => { +``` + +Next, your app logic validates the scopes and route. The `scopes` must match the request and the `redirectUri` must match the **Redirect URI** you configured in the app registration in the Azure portal, as well the route. + +```js + const tokenRequest = { + code: req.query.code, + scopes: ["user.read"], + redirectUri: "http://localhost:3000/redirect", + }; +``` + +The above code is the *configuration* for validating the response. The following code *validates* the response and completes the sign-in. + +```js + pca.acquireTokenByCode(tokenRequest).then((response) => { + console.log("\nResponse: \n:", response); + res.sendStatus(200); + }).catch((error) => { + console.log(error); + res.status(500).send(error); + }); +``` + +Putting together the routing and all the logic for completing the sign-in yields the following code: + +```js +app.get('/redirect', (req, res) => { + const tokenRequest = { + code: req.query.code, + scopes: ["user.read"], + redirectUri: "http://localhost:3000/redirect", + }; + + pca.acquireTokenByCode(tokenRequest).then((response) => { + console.log("\nResponse: \n:", response); + res.sendStatus(200); + }).catch((error) => { + console.log(error); + res.status(500).send(error); + }); +}); +``` + +## The user experience + +What happens if the user logs in, closes the window, returns to the site, and logs in again? + +Microsoft supports several complex scenarios with several forms of authentication: certificates, hardware keys, federated experiences, and even biometrics in some cases. Let our the Microsoft Authentication Library (MSAL) handle the complexity of deciding the simplest way of logging in the user. + +> NOTE: Silent flows are not used with this scenario. See [Authentication flows](https://docs.microsoft.com/azure/active-directory/develop/msal-authentication-flows) for a discussion of the interaction between flows. diff --git a/index.js b/index.js new file mode 100644 index 0000000..0b416a0 --- /dev/null +++ b/index.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ +const express = require("express"); +const msal = require('@azure/msal-node'); + +const SERVER_PORT = process.env.PORT || 3000; +const REDIRECT_URI = "https://citrix.node4co.uk/redirect"; + +// Before running the sample, you will need to replace the values in the config, +// including the clientSecret +const config = { + auth: { + clientId: "769b81fe-3663-4034-824f-8c07f3a74138", + authority: "https://login.microsoftonline.com/common", + clientSecret: process.env.secret + }, +    system: { +        loggerOptions: { +            loggerCallback(loglevel, message, containsPii) { +                console.log(message); +            }, +         piiLoggingEnabled: false, +         logLevel: msal.LogLevel.Verbose, +        } +    } +}; + +// Create msal application object +const pca = new msal.ConfidentialClientApplication(config); + +// Create Express App and Routes +const app = express(); + +app.get('/', (req, res) => { + const authCodeUrlParameters = { + scopes: ["user.read"], + redirectUri: REDIRECT_URI, + }; + + // get url to sign user in and consent to scopes needed for application + pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => { + res.redirect(response); + }).catch((error) => console.log(JSON.stringify(error))); +}); + +app.get('/redirect', (req, res) => { + res.redirect(302, 'https://citrix.node4.co.uk'); + // const tokenRequest = { + // code: req.query.code, + // scopes: ["user.read"], + // redirectUri: REDIRECT_URI, + // }; + + // pca.acquireTokenByCode(tokenRequest).then((response) => { + // console.log("\nResponse: \n:", response); + // res.sendStatus(200); + // }).catch((error) => { + // console.log(error); + // res.status(500).send(error); + // }); +}); + + +app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!`)) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..87aed73 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1269 @@ +{ + "name": "msal-node-auth-code", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "msal-node-auth-code", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@azure/msal-node": "^1.0.0", + "express": "^4.17.1", + "uuid": "^8.3.1" + } + }, + "node_modules/@azure/msal-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-4.0.1.tgz", + "integrity": "sha512-dHdTmLnRpqGasqAUCOzDt9Os8rke1cRk6Mo6yeI0ucis+G/CwLFQ2G08SEdPfZZnvemhTRP0l70UBPax1Gwxmw==", + "dependencies": { + "debug": "^4.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.0.0.tgz", + "integrity": "sha512-uc8B9n9U6IRVsCLOn1D39GhuA8CzbxP8MUl53Sr9hyAjJG4W7139dZSCnZ6VCBlgqm7VmtDSKOaOBWvbBjcJzg==", + "dependencies": { + "@azure/msal-common": "^4.0.1", + "axios": "^0.21.1", + "jsonwebtoken": "^8.5.1", + "uuid": "^8.3.0" + }, + "engines": { + "node": "10 || 12 || 14" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "@azure/msal-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-4.0.1.tgz", + "integrity": "sha512-dHdTmLnRpqGasqAUCOzDt9Os8rke1cRk6Mo6yeI0ucis+G/CwLFQ2G08SEdPfZZnvemhTRP0l70UBPax1Gwxmw==", + "requires": { + "debug": "^4.1.1" + } + }, + "@azure/msal-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-1.0.0.tgz", + "integrity": "sha512-uc8B9n9U6IRVsCLOn1D39GhuA8CzbxP8MUl53Sr9hyAjJG4W7139dZSCnZ6VCBlgqm7VmtDSKOaOBWvbBjcJzg==", + "requires": { + "@azure/msal-common": "^4.0.1", + "axios": "^0.21.1", + "jsonwebtoken": "^8.5.1", + "uuid": "^8.3.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==" + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e3907cf --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "msal-node-auth-code", + "version": "1.0.0", + "description": "sample app for msal-node", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "author": "Microsoft", + "license": "MIT", + "dependencies": { + "@azure/msal-node": "^1.0.0", + "express": "^4.17.1", + "uuid": "^8.3.1" + } +}