Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure AD Single Page Application should include Origin header for CORS support #1048

Open
adkafka opened this issue Feb 12, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@adkafka
Copy link

adkafka commented Feb 12, 2024

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:

I0212 11:53:00.490607    8300 cmd.go:66] stacktrace: get-token: authentication error: authcode-browser error: authentication error: authorization code flow error: oauth2 error: could not exchange the code and token: oauth2: "invalid_request" "AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests. ..."

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 #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 the Origin 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.

@adkafka adkafka added the enhancement New feature or request label Feb 12, 2024
@adkafka
Copy link
Author

adkafka commented Feb 12, 2024

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.

@adkafka
Copy link
Author

adkafka commented Apr 22, 2024

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.

@adkafka
Copy link
Author

adkafka commented Apr 23, 2024

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant