Updates in Azure Web App

So yeah - same issue:

2021-11-30 09:47:06 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxxxx:16344:73569164 all the dispatchers started
The secret <...> was not found.
The secret <...> was not found.
The secret <...> was not found.
[21:47:56 FTL] Application startup exception
System.InvalidOperationException: The Negotiate Authentication handler cannot be used on a server that directly supports Windows Authentication. Enable Windows Authentication for the server and the Negotiate Authentication handler will defer to it.
   at Microsoft.AspNetCore.Authentication.Negotiate.PostConfigureNegotiateOptions.PostConfigure(String name, NegotiateOptions options)
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
   at Microsoft.Extensions.Options.OptionsMonitor`1.<>c__DisplayClass11_0.<Get>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
   at Microsoft.Extensions.Options.OptionsMonitor`1.Get(String name)
   at Microsoft.AspNetCore.Authentication.Negotiate.Internal.NegotiateOptionsValidationStartupFilter.<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder builder)
   at Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter.<>c__DisplayClass4_0.<Configure>b__0(IApplicationBuilder app)
   at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)

I’ll try redeploying from GitHub now to see if that fixes it. It has in the past. But yeah, this is something we need to nail down for sure. :frowning:

It’s back up after a redeploy. No sign of that negotiate authentication exception in the most recent log.

That might be a clue, @adam - if redeploying fixes it until the next restart, it might be something in the non-persistent part of the file system that’s getting it started.

What’s interesting is that I just dropped to a console in my Azure web app and typed “set”, and APP_POOL_ID is definitely set. So it’s almost like the “runningInIis” detection is working right after deployment, but if the app is stopped and restarted, it fails.

EDIT: I stopped and restarted the app service and am back to “an error occurred while starting the application.” When I look at the environment variables, APP_POOL_ID is still set to the same value as before the restart.

Is it possible that your IIS detection code isn’t being called when the app restarts? Only on deployment? Something like that?

It should be called every time the app starts since that’s in the start up code for the process. I wonder why it wouldn’t detect that environment variable after a restart…

Let me look into a different way to achieve the since it seems like this isn’t going to work in Azure. At the very least, we should be able to disable that auth handler completely some how.

2 Likes

Thanks adam. Yeah I can see the $env:APP_POOL_ID is populated on initial launch and after reboot too.

Now that the above is logged for 2.6.0, I’m also checking OIDC auth again, I’ve tried to add it from the PSU GUI so I don’t have to restart my web app, but in doing so (I’m coping the exact same settings from my on prem OIDC app settings), I’m getting a pop up error on save:

Here’s my settings:

And here’s the log:

[10:30:28 INF] Azure Web Sites environment detected. Using 'C:\home\ASP.NET\DataProtection-Keys' as key repository; keys will not be encrypted at rest.
2021-12-01 10:30:29 [INFO]  (Hangfire.BackgroundJobServer) Starting Hangfire Server using job storage: 'Hangfire.MemoryStorage.MemoryStorage'
2021-12-01 10:30:29 [INFO]  (Hangfire.BackgroundJobServer) Using the following options for Hangfire Server:
    Worker count: 5
    Listening queues: 'default'
    Shutdown timeout: 00:00:15
    Schedule polling interval: 00:00:15
[10:30:29 INF] Creating key {f60c1353-3200-4e7c-8f01-a50a5300598f} with creation date 2021-12-01 10:30:29Z, activation date 2021-12-01 10:30:29Z, and expiration date 2022-03-01 10:30:29Z.
[10:30:29 WRN] No XML encryptor configured. Key {f60c1353-3200-4e7c-8f01-a50a5300598f} may be persisted to storage in unencrypted form.
[10:30:29 INF] Writing data to file 'C:\home\ASP.NET\DataProtection-Keys\key-f60c1353-3200-4e7c-8f01-a50a5300598f.xml'.
2021-12-01 10:30:29 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:92a79caa successfully announced in 268.7104 ms
2021-12-01 10:30:29 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:92a79caa is starting the registered dispatchers: ServerWatchdog, ServerJobCancellationWatcher, ExpirationManager, CountersAggregator, Worker, DelayedJobScheduler, RecurringJobScheduler...
2021-12-01 10:30:29 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:92a79caa all the dispatchers started
2021-12-01 10:30:31 [INFO]  (Hangfire.BackgroundJobServer) Starting Hangfire Server using job storage: 'Hangfire.MemoryStorage.MemoryStorage'
2021-12-01 10:30:31 [INFO]  (Hangfire.BackgroundJobServer) Using the following options for Hangfire Server:
    Worker count: 5
    Listening queues: 'default'
    Shutdown timeout: 00:00:15
    Schedule polling interval: 00:00:15
2021-12-01 10:30:32 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:37522336 successfully announced in 0.0866 ms
2021-12-01 10:30:32 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:37522336 is starting the registered dispatchers: ServerWatchdog, ServerJobCancellationWatcher, ExpirationManager, CountersAggregator, Worker, DelayedJobScheduler, RecurringJobScheduler...
2021-12-01 10:30:32 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server xxxx:4424:37522336 all the dispatchers started
[10:35:16 WRN] Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {56cefb20-bcb3-4a87-897c-a51204b74e33} was not found in the key ring.
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.Session.CookieProtection.Unprotect(IDataProtector protector, String protectedText, ILogger logger)
[10:35:16 WRN] Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {56cefb20-bcb3-4a87-897c-a51204b74e33} was not found in the key ring.
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.Session.CookieProtection.Unprotect(IDataProtector protector, String protectedText, ILogger logger)

I’ve cut the log short as the the same error above repeats for a considerable amount.

@Mabster did you have any issues on this front? manage to get your OIDC working?

Yeah oidc is working fine for us. We have “code” in the scopes box add well, if that helps!

Sorry @insomniacc - I was in bed when I posted this so I didn’t have handy access to our settings. Here’s ours:

@adam I’m just now noticing the “correlation cookie” setting on that dialog, too. Could I set that to something to suppress those cookie warnings that flood our logs?

Honestly, I don’t know what correlation cookie same site setting is best to avoid the log message. We added that mainly because OIDC wasn’t working with Okta and I haven’t changed it for AAD so I’m not really sure. I can open an issue to research good guidance for that setting.

I also have hit a snag with the SecretStore support. SecretStore doesn’t let you change the path so it’s not portable. This means we can’t use it with Azure because the vault will be deleted during app restarts. I think the best bet is to support Azure Key Vault. Looking into the best way to manage that.

I originally was going to make secrets really extensible (install module, configure vault, unlock vault etc) but it’s becoming clear that I need to instead add support for particular vaults in PSU and provide options because otherwise it will be confusing and error prone to configure as an end user.

1 Like

That’s a bummer about SecretStore not being as flexible as we thought, but at least KeyVault is still an option. I agree that an “opinionated” approach will be less confusing for users.

EDIT: What do you think the workflow will look like for Azure KeyVault? Hoping we won’t need to call Connect-AzAccount with credentials in every script, since we won’t have a persistent way to store those credentials. Perhaps ClientID/ClientSecret properties in the app settings that we can override with environment variables? Similar to what you were going to do with the SecretStore password, I guess.

I think we can do something with managed service accounts (or whatever its called in Azure) and key vault so Azure takes care of the registration. We won’t have a place to call Connect-AzAccount for things like elevating to different credentials so we’ll need a way to do this outside of scripts.

1 Like

Thanks for the updates, do you think that might be the reason for the errors I was getting above regarding not being able to find the key in the key ring?
I also saw you closed out the negotiate authentication disable feature, I’ll give that a test on Monday using the nightly.

I’m using Azure key vault on my end, I made some custom functions to handle auth when we are working locally in our containers and when it’s running in azure with managed identities.

function Get-KVSecret {
    [CmdletBinding()]
    param (
        [Parameter()]
        [string]
        $Secret,
        [Parameter()]
        [string]
        $Vault = $env:AzKVName
    )
    if ($env:DEVENV -eq 'true') {
        $Results = Connect-CustomAz
        try {
            $Result = Get-Azkeyvaultsecret -VaultName $Vault -Name $Secret -AsPlainText -ErrorAction Stop
        }
        catch {
            $Result = $Error[0]
        }
    }
    else {
        $tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=https://vault.azure.net&api-version=2019-08-01"
        $tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" } -Uri $tokenAuthURI
        $Result = (Invoke-restmethod -method Get -Headers @{Authorization = $tokenResponse.token_type + " " + $tokenResponse.access_token } -uri "https://$Vault.vault.azure.net/secrets/$Secret/?api-version=7.1").value
    }
    
    return $Result
}

I think in the new version of the Az.Accounts/KeyVault module you can do Connect-AzAccount -Identity to have sign in with a managed identity, but at the time of me making this, it wasn’t an option I don’t think.

Since we don’t add or remove secrets very often, wasn’t worth the time to make a functions that did that, just GETs.

Just looping back around with this thread as I’m getting no where quick with OIDC.
I’ve been busy working on other projects and waiting on approval + changes for some networking for the last few months frustratingly, it’s taken a while but I’m finally back and ready to continue my journey with PSU in Azure.

I’ve just updated my web app to the latest 2.8.1 build.
Although still getting errors trying to enable OIDC - still not sure what I’m doing wrong here:
PSUAuthError

I’ve tried adding the OIDC config into my appsettings.json, then it shows in the Authentication page.
But after logging out of the admin account and trying to refresh, it just hangs and eventually throws a 500 error.

The OIDC settings I’ve basically replicated from an on-prem IIS version of PSU that I’d like to migrate to azure, only change I’ve made is I’ve added the new callback url to my app registration.

Here’s some snippets from my logs:

[17:32:46 INF] Azure Web Sites environment detected. Using 'C:\home\ASP.NET\DataProtection-Keys' as key repository; keys will not be encrypted at rest.
[17:32:51 ERR] Error registering vault PSUSecretStore
[17:32:51 ERR] Exception:
System.TypeInitializationException: The type initializer for 'Microsoft.PowerShell.SecretStore.SecureStoreFile' threw an exception.
 ---> System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
   at System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections)
   at System.Security.AccessControl.FileSystemSecurity.Persist(String fullPath)
   at System.IO.FileSystemAclExtensions.SetAccessControl(DirectoryInfo directoryInfo, DirectorySecurity directorySecurity)
   at Microsoft.PowerShell.SecretStore.SecureStoreFile.SetDirectoryACLs(String directoryPath)
   at Microsoft.PowerShell.SecretStore.SecureStoreFile..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.PowerShell.SecretStore.SecureStoreFile.get_ConfigRequiresPassword()
   at Microsoft.PowerShell.SecretStore.LocalSecretStore.get_PasswordRequired()
   at Microsoft.PowerShell.SecretStore.SetSecretStoreConfiguration.EndProcessing()
   at System.Management.Automation.Cmdlet.DoEndProcessing()
   at System.Management.Automation.CommandProcessorBase.Complete()
17:33:14 WRN] Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {9a7e39aa-8a9e-40b2-941e-9e6a36940eeb} was not found in the key ring.
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.Session.CookieProtection.Unprotect(IDataProtector protector, String protectedText, ILogger logger)
^^^ This one repeats ALOT


[17:34:46 ERR] An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
   at UniversalAutomation.Services.AuthenticationMethodsConfigurationScript.OnWriteBeforeAsync(AuthenticationMethod item) in D:\a\universal\universal\src\Universal.Server\Services\Configuration\AuthenticationMethods.cs:line 72
   at UniversalAutomation.Services.ConfigurationScript`1.WriteAsync(T item, Identity identity) in D:\a\universal\universal\src\Universal.Server\Services\Configuration\ConfigurationScript.cs:line 95
   at UniversalAutomation.Services.UniversalConfigurationService.WriteAsync(Object item, Identity identity) in D:\a\universal\universal\src\Universal.Server\Services\UniversalConfigurationService.cs:line 183
   at UniversalAutomation.Services.UniversalConfigurationService.WriteAndSyncAsync[T](T item, Identity identity) in D:\a\universal\universal\src\Universal.Server\Services\UniversalConfigurationService.cs:line 162
   at UniversalAutomation.SettingsController.NewAuthenticationMethod(AuthenticationMethod authenticationMethod) in D:\a\universal\universal\src\Universal.Server\Controllers\SettingsController.cs:line 157
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Universal.Server.Middleware.RoutingMiddleware.Invoke(HttpContext httpContext, IPolicyEvaluator policyEvaluator) in D:\a\universal\universal\src\Universal.Server\Middleware\RoutingMiddleware.cs:line 134
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Universal.Server.Middleware.SwaggerAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in D:\a\universal\universal\src\Universal.Server\Middleware\SwaggerAuthMiddleware.cs:line 42
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\projects\dotnet\src\MiniProfiler.AspNetCore\MiniProfilerMiddleware.cs:line 121
   at AspNetCoreRateLimit.RateLimitMiddleware`1.Invoke(HttpContext context) in D:\a\universal\universal\src\AspNetCoreRateLimit\Middleware\RateLimitMiddleware.cs:line 109
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
[17:34:46 WRN] No exception handler was found, rethrowing original exception.
[17:34:46 ERR] Connection ID "14987979561499681183", Request ID "8000e1a8-0000-d000-b63f-84710c7967bb": An unhandled exception was thrown by the application.
System.NullReferenceException: Object reference not set to an instance of an object.

@Adam - any ideas I’m stumped!

Just deleted my webapp & app serviceplan, started fresh with a clean install.
Here’s the steps I take:

Download latest 2.8.1 version
Create App service plan + web app

$EnvVars = @{
    Api__Url = "https://xxxxxxxxxxxx.azurewebsites.net"
    Data__ConnectionString = "D:\home\data\PowershellUniversal\database.db"
    Data__RepositoryPath = "D:\home\data\PowershellUniversal\Repository"
}
Set-AzWebApp -Name $AppName -ResourceGroupName $resourcegroup -NetFrameworkVersion "v5.0" -WebSocketsEnabled $true -Use32BitWorkerProcess $false -AlwaysOn $true -HttpsOnly $true -AssignIdentity $true -FtpsState "FtpsOnly" -AppSettings $EnvVars
Publish-AzWebApp -ArchivePath "localpath.zip" -Name $AppName -ResourceGroupName $resourcegroup -force

Finally I have a command that enables my VNET integration on outbound connections (already tested and working previously).

I usually restart my web app at this point for good measure.

Thats it, then I load up the admin console, upload my license file, and attempt to enable OIDC via the gui, thats when I get the popup error with no message.

I don’t know exactly why that error is happening but you might be able to work around it by setting your OIDC settings via environment variables.

$EnvVars = @{
    Api__Url = "https://xxxxxxxxxxxx.azurewebsites.net"
    Data__ConnectionString = "D:\home\data\PowershellUniversal\database.db"
    Data__RepositoryPath = "D:\home\data\PowershellUniversal\Repository"
    Authentication__OIDC__Enabled = "true"
    Authentication__OIDC__ClientID = "id"
    Authentication__OIDC__ClientSecret = "secret" 
    Authentication__OIDC__ResponseType = "code"  
}
1 Like

Don’t know if it will help any, but here’s out “authentication.ps1” (with all the sensitive stuff replaced with “…”). OIDC is working for us.

Set-PSUAuthenticationMethod -Type "Form" -ScriptBlock {
param(
        [PSCredential]$Credential
    )

    #
    #   You can call whatever cmdlets you like to conduct authentication here.
    #   Just make sure to return the $Result with the Success property set to $true
    #

    if ($Credential.UserName -eq '...' -and $Credential.GetNetworkCredential().Password -eq '...') 
    {
        New-PSUAuthenticationResult -Success -UserName '...'
    }
    else 
    {
        New-PSUAuthenticationResult -ErrorMessage 'Bad username or password'
    }
} 
Set-PSUAuthenticationMethod -Type "OpenIDConnect" -CallbackPath "/auth/signin-oidc" -ClientId "..." -ClientSecret "..." -Authority "https://login.microsoftonline.com/..." -ResponseType "code" -Scopes "openid profile groups"
2 Likes

Huh… @mabster - I copied the format you’ve shown first before I tried Adams method and it worked!
I have already tried putting similar settings into that file before… although my params and some of the values are slightly different.
I’ll play around a little more tomorrow and see if I can work out exactly what the difference was between my original version and yours and what’s killing it, hopefully might help others falling into the same trap.
Appreciate the quick response from both of you btw :slight_smile:

1 Like

Hey All! I just noticed I’m getting the same error when trying to add OIDC from the UI as well, same “Error” toast in the top corner. We’re running on-prem as a service, I tried upgrading to from 2.8.2 to 2.8.3, with the same result. I’m perfectly fine copying our test environment’s authentication.ps1 file and modify the values for prod to get it working. I just figured I’d add a second example of the error occurring if any bug-searching is warranted. If it’s worth noting, one of our test environments are still on 2.7.4, and didn’t have any issues.

Hijacking this topic for the same OIDC troubles within Azure App Services.

I’m almost there… But for some reason Universal keeps using http:\ as the reply URL in it’s request that causes the general error;

AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: ’

Is there something I’m plainly missing?

Do you have the API Url set with https in your app configuration variables?
Api__Url = “https://xxxxxxxxxxxx.azurewebsites.net

I do!
Tried with the default azurewebsites domain and afterwards with a custom domain. Both with the same result, unfortunately.