Open adkafka opened 9 months ago
Hmm, it appears I found a better workaround. If I remove the "Single Page Application" completely in Azure, and instead use a "Mobile and desktop applications", the Client Secret is not required. Simply adding the "Mobile and desktop applications" was not sufficient, I had to also remove the "Single Page Application". We can succeed simply with:
$ kubelogin get-token \
--oidc-issuer-url "https://login.microsoftonline.com/<REDACTED>/v2.0" \
--oidc-client-id <REDACTED> \
--oidc-use-pkce \
--force-refresh \
--listen-address 127.0.0.1:8000
So, perhaps the guidance should be to use Mobile and desktop applications
in Azure, and avoid Single Page Application
completely. This is confusing, because the Azure docs only mention PKCE with Single Page Application
.
Revisiting this now... I learned recently that Azure AD applications of type Mobile and desktop applications
are not in scope for Conditional Access Policies (see documentation here), meaning in my case they do not trigger an MFA enforcement. This has be coming back to this issue, because using Single Page Application
DOES trigger an MFA enforcement, if we can make it work with kubelogin.
I confirmed that simply adding a header in the request solves this issue. Here is an example:
This command fails:
$ curl "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
-X POST \
-d 'client_id=<client-id>&code=<authorization-code>&code_verifier=<verification-code>=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8000'
...
{"error":"invalid_request","error_description":"AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests. Trace ID: <omitted> Correlation ID: <omitted> Timestamp: 2024-04-22 19:39:04Z","error_codes":[9002327],"timestamp":"2024-04-22 19:39:04Z","trace_id":"<omitted>","correlation_id":"<omitted>"}
This command succeeds (simply adding Origin: localhost:1800
as a header):
curl "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
-H 'Origin: localhost:1800' \
-X POST \
-d 'client_id=<client-id>&code=<authorization-code>&code_verifier=<verification-code>=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8000'
...
{"token_type":"Bearer","scope":"email openid profile User.Read","expires_in":4422,"ext_expires_in":4422,"access_token"...
Therefore, I would like to bring this issue back up for consideration. I'm happy to make a PR after receiving guidance for how best to proceed.
In order to implement this code, I think we need to implement the change 2 libraries upstream. This library uses https://github.com/int128/oauth2cli/tree/master which in turn uses https://github.com/golang/oauth2/tree/master. The logic to actually request the token is here: https://github.com/golang/oauth2/blob/master/internal/token.go#L183-L202. Plumbing through the call back URL as a parameter seems like a relatively large lift in this case. We do have a context.Context
object that gets passed through though. Maybe we could use that to set this header?
Purpose of the feature (why)
We would like to use Azure AD Single Page Application with PKCE and no client secret. However, after configuring
kubelogin
for such a setup, we receive an error:After digging a bit more, it seems that Azure requires the request to populate the
Origin
header for this flow to succeed. See:For a related github issue, see https://github.com/int128/kubelogin/issues/858
Your idea (how)
I'm hoping that we can include a
Origin
header in these requests to resolve this error. A couple options to consider for this are: 1) Add CORS support in the HTTP client. I'm unsure how difficult this is. We can put this behind a feature flag if we would like. 2) Populate theOrigin
header manually in the HTTP client. We can either put this behind a feature flag, or just choose to add this header to all requests. 3) Support adding arbitrary HTTP headers as a CLI parameter (ie--extra-header="Origin: localhost:8000"
)If we decide on a solution, I'm happy to take an initial pass at making the PR.
Workaround
This issue can be worked around by instead configuring the Azure Application to be a "Mobile and desktop applications". However, this requires us to include the "Client Secret" in all client's kubeconfig files, which is not desirable.