Closed sean-r-williams closed 3 months ago
Hi Sean, I'm not familiar with Vault, but when using AAD as the identity provider, you'll likely need to obtain a JWT using your Azure AD app registration (client), then post this to the /auth/azure/login endpoint.
In order to use a pre-built authorization url it would probably be better to use Invoke-WebView2 directly (this function is not exported by default). Invoke-OAuth2AuthorizationEndpoint generates state/nonce values automatically, at least for now this would lead to duplicates if provided through customParameters.
@alflokken Thanks for the context.
Unfortunately, the azure
login method is (AFAICT, based on this doc) specific to Managed Service Identity login - that is, a VM, Function app, etc. can call the IMDS to get a token, then send that to /auth/azure/login
to authenticate as the VM itself.
We may be able to send an AAD-issued JWT directly to the JWT login endpoint (I think this defaults to /auth/jwt/login
) since OIDC and JWT auth share some config elements, but the docs are pretty vague in this area so I'll need to test this in practice.
HDYF about adjusting Invoke-OAuth2AuthorizationEndpoint
to support this scenario? I saw you mention "at least for now", so I'd like to understand whether you see this as something within the scope of this module.
I see two possible options for supporting this:
-PrebuiltUrl
parameter to a separate parameter set with no other parameters, parse out critical fields like redirect_uri
from the URL parameter, then pass to Invoke-WebView2
.-ExternalNonce
and -ExternalState
parameters, then use the provided nonce/state instead of generating our own.Happy to file a PR for either of these options if you see value in supporting a workflow like this.
Although I'm uncertain about the specific use-case, and I secretly think that this might be what you are looking for. 😆 I do see the value of supporting the workflow, after all PSAuthClient is supposed to be a flexible client.
However, I would prefer to refactor how Invoke-OAuth2AuthorizationEndpoint
constructs the request URI, giving priority to parameters specified in customParameters
instead of adding any new parameters.
I appreciate your suggestion and the offer to submit a pull request. However, I prefer to handle the changes myself to maintain familiarity with the code base. I can't specify when I'll get to this due to my current workload, but I will add it to my to-do list. If you need this change urgently, please feel free to fork the repository.
In a way, you're absolutely right. The OIDC auth method in the Vault web UI (they appear to be using a locally-hosted Vault instance) will call the same auth_url
endpoint on the API, then redirect the browser to that endpoint (with a redirect_uri
back to oidc/callback
directly).
The complication arises when inside a script/other client library abstracting Vault into another human-driven process. (In our case, we're importing certs into a KV engine with a specific format - we're writing scripts to parse/ingest the certificate without manually keying all of it into the UI.) For some reason, Vault API clients also use the same auth_url
/callback
mechanism instead of just sending an access token to a login endpoint. Vault's own client (in Go) supports this with vault login -method=oidc
. The vault client launches a web browser, accepts the auth code from the OP via a localhost redirect_uri
, then calls oidc/callback
to exchange that auth_code for a Vault login token. You can see an equivalent Python implementation here.
I'll abstain from submitting a PR in that case - please let me know if you need help testing this scenario in the future.
Thanks for providing details. As briefly mentioned, I think a quick fix could involve honoring 'state', 'nonce', 'code_challenge', and 'code_challenge_method' when provided in customParameters
.
This would require you to parse your authorization URL and input values into the respective parameters of Invoke-OAuth2AuthorizationEndpoint
. I believe this approach maintains the function's general purpose and idea, while still allowing flexibility for your scenario. However, it's important to note that you would not be able to send, for example, OIDC requests without a nonce or OAuth requests without a state. I'm not entirely sure how I want to address this and if it's useful at all. Perhaps it's better to leave it as is, since the code is already highly modifiable for anyone wanting to fork it.
Would this solve your problem?
I think a quick fix could involve honoring 'state', 'nonce', 'code_challenge', and 'code_challenge_method' when provided in
customParameters
.
Yes, I think that would be a suitable alternative.
However, it's important to note that you would not be able to send, for example, OIDC requests without a nonce or OAuth requests without a state. I'm not entirely sure how I want to address this
Conditionalizing lines 95 and 100 in Invoke-OAuth2AuthorizationEndpoint
based on whether ($null -ne $customParameters) -and ($CustomParameters.ContainsKey("..."))
is probably the lowest-friction method. This would only add in nonce/state if they're not already defined in the $customParameters
hashtable.
We're trying to authenticate to Hashicorp Vault using an OIDC provider (AAD in this case, but I reckon the exact OP/IdP isn't relevant).
The API login method for Vault (for OIDC clients) looks something like this:
oidc/auth_url
endpoint with a redirect URI the client can receive data at. (Forvault login
, this defaults tohttp://localhost:8250/oidc/callback
.) Vault returns a prebuilt URL for doing auth-code grant with PKCE against the OP. All of the relevant data is already built into the URL, includingcode_challenge
,nonce
,state
,client_id
, etc.oidc/callback
endpoint, passing thenonce
/state
/code
back to Vault for it to perform PKCE.This seems (from a naive perspective) to operate on the edge of what OIDC is designed for, since the client is neither generating nor performing the actual code-exchange (just issuing the auth code proper). Vault's own CLI handles this very well with
vault login
, but bundling a CLI binary alongside PowerShell scripts feels unwieldy.Can you provide some clarity on whether this is even a supported scenario with PSAuthClient? Would feeding the data from this generated auth URL into
Invoke-OAuth2AuthorizationEndpoint
even function as expected, given the client isn't doing PKCE itself? Would feeding the extra PKCE challenge parameters in through-customParameters
with-UsePkce:$false
be a supported scenario for this?