OIDC : Appsettings.json VS authentication.ps1

Product: PowerShell Universal
Version: 5.3

Reading the manual: OpenID Connect | PowerShell Universal
I understand this text as an OR not an AND.
Meaning i can either configure it through the UI (which in turn fills in authentication.ps1) or I do it with the appsettings.json.

When i provide the following into the UI , it works:
Set-PSUAuthenticationMethod -Type "OpenIDConnect" -CallbackPath "/auth/signin-oidc" -ClientId "x" -ClientSecret "x" -Authority "https://login.microsoftonline.com/xxx -UseTokenLifetime $true -GetClaimsFromUserInfoEndpoint $true -LoadMetadata

Blockquote Important to note, if i directly paste this line into the authentication.ps1 without filling in the UI, it does not work ! You have to add the option via the UI. I assume somehow, something gets written to the database?

Now, for the second part, appsettings.json :

{
  "Kestrel": {
    "Endpoints": {
      "HTTP": {
        "Url": "http://*:5000"
      },
      "HTTPS": {
        "Url": "https://*:443",
        "Certificate": {
          "Thumbprint": "xxx",
          "Store": "My",
          "Location": "LocalMachine",
          "AllowInvalid": "true"
        }
      }    
    }
  },
  "Plugins": [
  "SQLite"
  ],
  "Data": {
    "RepositoryPath": "%ProgramData%\\UniversalAutomation\\Repository",
    "ConnectionString": "Data Source=%ProgramData%\\UniversalAutomation\\database.db"
  },
  "Mode": "Server",
  "PSUTelemetry": false,
  "OIDC": {
    "Enabled": true,
    "CallbackPath": "/auth/signin-oidc",
    "ClientID": "xxx",
    "ClientSecret": "xxx",
    "Authority": "https://login.microsoftonline.com/xxx",
    "ResponseType": "code",
    "SaveTokens": false,
    "CorrelationCookieSameSite": "",
    "UseTokenLifetime": true,
    "Scope": "openid profile groups",
    "GetUserInfo": true
  },
  "Logging": {
    "Path": "%PROGRAMDATA%/PowerShellUniversal/log.txt",
    "RetainedFileCountLimit": 31,
    "LogLevel": {
      "Default": "Debug", 
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*", 
  "CorsHosts": "https://login.microsoftonline.com" 
}

This does nothing, even though I know my values work with the UI option.

Is it supposed to work or did i misunderstand the documentation?

It should work from appsettings.json. It’s read when the server starts up. If you configure it in authentication.ps1, it will ignore the appsettings.json values.

It didn’t work.
Could it be because I had previously set it up through the GUI? Does it hold a reference in the database?

I can remove it via the GUI and from the authentication.ps1 and try again but pretty sure it was covered during my tests.

It shouldn’t be stored in the database. If you add it in appsettings.json, it should show in the UI as readonly stating that it came from appsettings.json.

I do know that it works on my end since it’s how I have my lab setup to test OIDC, SAML2 etc.

Could you share your appsettings.json ? The clue must be in there.
I can confirm, I just tested and even though my .JSON is as posted above, as soon as I remove my OIDC entry in the UI, it stops working , despite having the configuration in the JSON defined.

In the UI, the option ‘OpenID connect’ is not disabled or grayed out in any way.

{
   "Kestrel": {
       "Endpoints": {
            "HTTPS": {
                 "Url": "https://*:5001"
            }
       }  
  },
  "Authentication" : {
     "OIDC": {
         "Enabled": "true",
         "CallbackPath": "/auth/signin-oidc",
         "ClientId": "<redacted>"
         "ClientSecret": "<redacted>",
         "Authority": "https://login.microsoftonline.com/<redacted>",
         "ResponseType": "code",
         "SaveTokens": "true",
         "UseTokenLiftetime" : "true",
         "Scope": "openid profile groups offline_access"
     }
  }
}

This is driving me insane.
Knowing that it should work but can’t seem to make it work.

{
  "Kestrel": {
    "Endpoints": {
      "HTTP": {
        "Url": "http://*:5000"
      },
      "HTTPS": {
        "Url": "https://*:443",
        "Certificate": {
          "Thumbprint": "redacted",
          "Store": "My",
          "Location": "LocalMachine",
          "AllowInvalid": "true"
        }
      }
    }
  },
  "Plugins": [
    "SQLite"
  ],
  "Data": {
    "RepositoryPath": "%ProgramData%\\UniversalAutomation\\Repository",
    "ConnectionString": "Data Source=%ProgramData%\\UniversalAutomation\\database.db"
  },
  "Mode": "Server",
  "OIDC": {
    "Enabled": "true",
    "CallbackPath": "/auth/signin-oidc",
    "ClientID": "redacted",
    "ClientSecret": "redacted",
    "Resource": "",
    "Authority": "https://login.microsoftonline.com/redacted",
    "ResponseType": "code",
    "SaveTokens": "false",
    "CorrelationCookieSameSite": "",
    "UseTokenLifetime": true,
    "Scope": "openid profile groups",
    "GetUserInfo": false
  },
  "Logging": {
    "Path": "%PROGRAMDATA%/PowerShellUniversal/log.txt",
    "RetainedFileCountLimit": 31,
    "LogLevel": {
      "Default": "Debug",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "CorsHosts": "https://login.microsoftonline.com"
}

autentication.ps1 looks like:

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
#

New-PSUAuthenticationResult -ErrorMessage 'Bad username or password'
}

The logs do show an error:

2025 - 03 - 17 15:03:10.991 +01:00 [INF] RPC services being provided by PowerShellUniversal.Services.IJobInvokerService: 2
2025 - 03 - 17 15:03:11.000 +01:00 [INF] RPC services being provided by PowerShellUniversal.Interfaces.ITestExecutionService: 1
2025 - 03 - 17 15:03:11.006 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IIdentityClient: 6
2025 - 03 - 17 15:03:11.019 +01:00 [INF] RPC services being provided by PowerShellUniversal.IJobDataService: 13
2025 - 03 - 17 15:03:11.023 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.ICacheService: 5
2025 - 03 - 17 15:03:11.025 +01:00 [WRN] Type cannot be serialized; ignoring: PowerShellUniversal.AuthenticationMethod
2025 - 03 - 17 15:03:11.025 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IPublicClient.NewAuthenticationMethod; method will not be bound
2025 - 03 - 17 15:03:11.025 +01:00 [WRN] Type cannot be serialized; ignoring: PowerShellUniversal.Translation
2025 - 03 - 17 15:03:11.025 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IPublicClient.NewTranslation; method will not be bound
2025 - 03 - 17 15:03:11.025 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IPublicClient.SyncComponent; method will not be bound
2025 - 03 - 17 15:03:11.051 +01:00 [INF] RPC services being provided by PowerShellUniversal.IPublicClient: 32
2025 - 03 - 17 15:03:11.059 +01:00 [INF] RPC services being provided by PowerShellUniversal.IComputerClient: 5
2025 - 03 - 17 15:03:11.060 +01:00 [WRN] Type cannot be serialized; ignoring: PowerShellUniversal.EndpointProfile
2025 - 03 - 17 15:03:11.060 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IStatsService.TrackEndpoint; method will not be bound
2025 - 03 - 17 15:03:11.060 +01:00 [WRN] Type cannot be serialized; ignoring: PowerShellUniversal.EndpointProfile
2025 - 03 - 17 15:03:11.060 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IStatsService.EndTrackEndpoint; method will not be bound
2025 - 03 - 17 15:03:11.062 +01:00 [INF] RPC services being provided by PowerShellUniversal.IStatsService: 4
2025 - 03 - 17 15:03:11.069 +01:00 [INF] RPC services being provided by PowerShellUniversal.Clients.IDashboardGrpcClient: 7
2025 - 03 - 17 15:03:11.071 +01:00 [WRN] Type cannot be serialized; ignoring: System.IDisposable
2025 - 03 - 17 15:03:11.071 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IConfigurationSystemWatcher.Pause; method will not be bound
2025 - 03 - 17 15:03:11.071 +01:00 [WRN] Signature not recognized for PowerShellUniversal.IConfigurationSystemWatcher.CheckSum; method will not be bound
2025 - 03 - 17 15:03:11.072 +01:00 [INF] RPC services being provided by PowerShellUniversal.IConfigurationSystemWatcher: 2
2025 - 03 - 17 15:03:11.077 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IDeploymentClient: 6
2025 - 03 - 17 15:03:11.081 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.PortalComponent]: 5
2025 - 03 - 17 15:03:11.085 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.PortalPage]: 5
2025 - 03 - 17 15:03:11.091 +01:00 [INF] RPC services being provided by PowerShellUniversal.Clients.IAppTokenClient: 6
2025 - 03 - 17 15:03:11.095 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.ComputerGroup]: 5
2025 - 03 - 17 15:03:11.099 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.EndpointDocumentation]: 5
2025 - 03 - 17 15:03:11.103 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Endpoint]: 5
2025 - 03 - 17 15:03:11.107 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.ExecutionEnvironment]: 5
2025 - 03 - 17 15:03:11.111 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.EventHub]: 5
2025 - 03 - 17 15:03:11.115 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Folder]: 5
2025 - 03 - 17 15:03:11.119 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.CustomHealthCheck]: 5
2025 - 03 - 17 15:03:11.122 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Module]: 5
2025 - 03 - 17 15:03:11.126 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.PublishedFolder]: 5
2025 - 03 - 17 15:03:11.130 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Role]: 5
2025 - 03 - 17 15:03:11.134 +01:00 [INF] RPC services being provided by PowerShellUniversal.IScheduleService: 6
2025 - 03 - 17 15:03:11.138 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Script]: 5
2025 - 03 - 17 15:03:11.142 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Tag]: 5
2025 - 03 - 17 15:03:11.146 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Terminal]: 5
2025 - 03 - 17 15:03:11.150 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Trigger]: 5
2025 - 03 - 17 15:03:11.153 +01:00 [INF] RPC services being provided by PowerShellUniversal.Platform.IModelService`1[PowerShellUniversal.Variable]: 5
2025 - 03 - 17 15:03:11.156 +01:00 [INF] RPC services being provided by UniversalAutomation.IPublicSecretManagerService: 1
2025 - 03 - 17 15:03:11.163 +01:00 [INF] RPC services being provided by PowerShellUniversal.IGitSettingsService: 9
2025 - 03 - 17 15:03:11.168 +01:00 [INF] RPC services being provided by UniversalAutomation.IPublicGitService: 3
2025 - 03 - 17 15:03:11.170 +01:00 [INF] RPC services being provided by UniversalAutomation.IPublicApiService: 1
2025 - 03 - 17 15:03:11.176 +01:00 [INF] RPC services being provided by UniversalAutomation.IPublicGitSyncService: 5
2025 - 03 - 17 15:03:11.177 +01:00 [INF] Loading app tokens...
2025 - 03 - 17 15:03:11.180 +01:00 [INF] RPC services being provided by PowerShellUniversal.IBrandingService: 1
2025 - 03 - 17 15:03:11.259 +01:00 [WRN] HTTP/2 is not enabled for [::]:5000. The endpoint is configured to use HTTP/1.1 and HTTP/2, but TLS is not enabled. HTTP/2 requires TLS application protocol negotiation. Connections to this endpoint will use HTTP/1.1.
2025 - 03 - 17 15:03:11.262 +01:00 [INF] Loading app assets...
2025 - 03 - 17 15:03:11.273 +01:00 [INF] Initializing database...
2025 - 03 - 17 15:03:11.275 +01:00 [INF] Now listening on: http://[::]:5000
2025 - 03 - 17 15:03:11.275 +01:00 [INF] Now listening on: https://[::]:443
2025 - 03 - 17 15:03:11.281 +01:00 [INF] Starting Hangfire Server using job storage: 'In-Memory Storage'
2025 - 03 - 17 15:03:11.283 +01:00 [INF] Using the following options for Hangfire Server:

The UI looks like:


Any more ideas?

You don’t have your appsettings.json formatted properly.

It should be:

"Authentication" : {
 "OIDC": {
    "Enabled": "true",
    "CallbackPath": "/auth/signin-oidc",
    "ClientID": "redacted",
    "ClientSecret": "redacted",
    "Resource": "",
    "Authority": "https://login.microsoftonline.com/redacted",
    "ResponseType": "code",
    "SaveTokens": "false",
    "CorrelationCookieSameSite": "",
    "UseTokenLifetime": true,
    "Scope": "openid profile groups",
    "GetUserInfo": false
  }
},

Yes, omg, that did it, thank you.
Quick follow up question with this new burst of energy, to improve security, could i use a variable stored in PSU within my appsettings.json file? Thanks again Adam!

1 Like