I successfully configured PowerShell Universal to accept **Azure AD Bearer Tokens** for external API authentication using the `Jwt` section in `appsettings.json`. However, this seems to break**internal script invocations** using `Invoke-PSUScript` because i keep receiving internal gRPC errors since i did that. Before i had no issues using it with a APP Token.
appsettings.json
{
“Authentication”: {
"OIDC": {
"Enabled": "true",
"Authority": "https://login.microsoftonline.com/<Tenant-ID>",
"ClientID": "<Client-ID>",
"ClientSecret": "<Secret>",
"Resource": "",
"Scope": "openid profile groups"
}
},
“Jwt”: {
"SigningKey": "PleaseUseYourOwnSigningKeyHere", #kept this since i don’t need it with the use of the DiscoveryDocument
"Issuer": "https://sts.windows.net/<Tenant-ID>/",
"Audience": "<Client-ID>",
"DiscoveryDocument": "https://login.microsoftonline.com/<Tenant-ID>/.well-known/openid-configuration",
"RoleClaimType": "roles"
}
}
External API Authentication works
- External applications can call PSU endpoints using Azure AD Bearer tokens
token validation works correctly (signature, issuer, audience, roles)
Role-based authorization works e.g (`-Role @(‘PSU.Access’)`) coming from the claim
The problem is with Internal Script Invocations
When an API endpoint tries to invoke another PSU script using `Invoke-PSUScript`, it fails:
# In API endpoint
$token = 'abcdefg # PSU-native AppToken
Connect-PSUServer -ComputerName ‘http://localhost:5000’ -AppToken $token
Invoke-PSUScript -Name ‘ChildScript.ps1’ -Parameters @{ Data = $data }
It is the following error:
Bad gRPC response. Invalid content-type value: text/html; charset=utf-8
The goal of my setup:
External API endpoint receives Azure AD Bearer token
Endpoint performs initial work (e.g., creates AD groups)
Endpoint needs to invoke a child PSU script asynchronously by using the inboke-psuscript
Child script execution must appear in PSU Jobs with full logging
I am almost there! The only remaining blocker is internal script invocations from API endpoints.
I hope this helps someone in the future. It took me way too long to find this.
If you drop the Connect-PSu and use Invoke-PSUscript -integrated it works on the condition that you change theappsettings.json.
Best way I understand : Strict asks for your ID card at every door you try to use. Permissive says, I see you are already in the building, your ID card is OK, go ahead … .
I’m looking to do this tbh. I find your analogy on strict vs permissive a little inaccurate though.
I’d liken it more to permissive/integrated being like using a service account, calling internal PSU API’s uses the system context and therefore has more rights to do things, such as retrieve any secret/variable or get and execute any script. Using Strict mode on the other hand, inherits the visiting users security context and uses that instead, if the user doesn’t have permissions to execute a script or get a variable, it’ll fail, otherwise it’ll work.
Security is a big factor for me so I need to keep with Strict mode, but I’ll setup using azure bearer tokens for api auth soon and see how I get on and will update here, your post is still helpful in getting me going on that front so thanks. It could be that the GRPC errors you were getting while in strict mode were simply because the context in which they were running did not have the required permissions to perform those actions.
It might be off a bit. like i said `best way i understand’. The documentation is not clear to me.
What you are saying is what I initially had in mind too. But the script that I was trying to invoke, had no permissions set. Later on, I did set permissions on it with a role that was identical to the API Endpoint. Still I was getting the error.
So in my mind , this was similar to the double hop problem when writing ‘normal’ PowerShell code. The call to the API Endpoint, is the first stop of my train ride. My ID Card gets scanned, sees it is valid and allows me to drive the train. Now at the next stop, I want to continue riding the train (invoke-psuscript).
In strict mode, the train staff says ‘sorry your ID was already scanned, this ticket is no longer valid’. But in permissive, they say, ‘ the next stop is part of the entire route, please continue your travels as we already scanned and validated your ticket, we know you are good to go’.
I am curious if you can get it to work with Strict mode on.
Security is always important but i don’t feel as this is a huge risk to set it to permissive. You still have to authenticate and get authorized at the first stop.