cloudfoundry / uaa

CloudFoundry User Account and Authentication (UAA) Server
Apache License 2.0
1.58k stars 827 forks source link

Receiving auth token in Authorization Code Grant with PKCE #1839

Closed aartek closed 2 years ago

aartek commented 2 years ago

What version of UAA are you running?

75.18.0

What output do you see from curl <YOUR_UAA>/info -H'Accept: application/json'?

curl 'https://example.com/uaa/oauth/token' \
  -H 'Accept: */*' \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-raw 'grant_type=authorization_code&code=111...222&redirect_uri=example.com&code_verifier=1234...5678&client_id=my.client' \
  --compressed
{"error":"unauthorized","error_description":"Bad credentials"}

What did you do?

Some time ago PKCE suport was added to UAA. I wanted to switch from oAuth2 Implicit Grant flow to Authorization Code Grant with PKCE. I'm able to get the code using browser flow, however i keep getting 401 when trying to request the token. As it's a browser flow, of course i'm not sending Authorization header, or client_secret in the POST request to /oauth/token.

What did you expect to see? What goal are you trying to achieve with the UAA?

How to exchange code for token in the browser?

cf-gitbot commented 2 years ago

We have created an issue in Pivotal Tracker to manage this:

https://www.pivotaltracker.com/story/show/181909246

The labels on this github issue will be updated when the story is started.

regisebersole commented 2 years ago

I have the same question: Does UAA support a public OIDC Authorization Code flow client using PKCE? The use-case is a browser single-page app (as described above) or a mobile application where a client_secret also cannot be safely stored.

For relying parties to UAA:

  1. The client_secret is required to create a client when the authorized_grant_type is authorization_code.
  2. The documentation notes that a client_secret is required to call the token endpoint: https://docs.cloudfoundry.org/api/uaa/version/75.18.0/index.html#openid-connect
  3. Not sending a client_secret result in the error noted above: {"error":"unauthorized","error_description":"Bad credentials"}
strehle commented 2 years ago

Hi , ok, for now UAA does not support this public usage.

However I agree to add this support since UAA has now PKCE support. Btw. The so-called public usage is supported already for the OIDC proxy scenario, because here it allows UAA to omit a secret in Idp configuration, see https://github.com/cloudfoundry/uaa/blob/develop/docs/okta-public-oidc-provider.md

UAA has for all grant types and usages configurations, e.g. implicit, auth code and so on. That was / is the reason why this support was not added as default.

PKCE itself is an enhancement for authorization_code, valid for confidential flow but most often combined in public flow.

Finally the support for public use in authorization_code in combination with PKCE makes sense, because many other OIDC providers support this already. However I vote for a configuration option in order to activate public use similar to https://developer.spotify.com/documentation/general/guides/authorization/code-flow/ .

If I do not receive a PR I will add this in the next weeks with an option to activate it similar to "autoapprove" in case of consent screen. This means you have to activate the public use via uaac or REST.

Hope this helps.

strehle commented 2 years ago

Question - Is there even a way to request auth token in browser using flow with PKCE, without sending the client_secret?

If you read https://developer.spotify.com/documentation/general/guides/authorization/code-flow/ then you see there is no client_secret in post but the client is authenticated, so this example is no public use but only PKCE support and this approach is supported in UAA already

regisebersole commented 2 years ago

@strehle That would be great if you could add that in an upcoming release.

To confirm, different from the Spotify doc in the link, the new UAA public OIDC client's Authorization Code Flow would be as follows where only the bold text in Step 1 and Step 7 represent a feature that isn't currently in UAA, right?

  1. Create/configure a public OIDC client_ with authorized_grant_types=authorization_code in UAA via uaac or REST API.
  2. Client generates PKCE code_verifier and code_challenge.
  3. Client redirects user to the UAA authorize endpoint with:
    redirect_uri
    client_id
    response_type=code
    state
    scope
    code_challenge
    code_challenge_method=S256
  4. UAA interacts with user to complete authentication.
  5. UAA redirects user to replay the request from (3), and now that the user has been authenticated in (4), the user is directed back to the client's redirect_uri with:
    code
    state
    1. Client calls UAA token endpoint _without a client_secret_:
      grant_type=authorization_code
      client_id
      redirect_uri
      code
      code_verifier
  6. UAA responds to the client call in (7) with:
    access_token
    token_type=bearer
    id_token
    refresh_token
    expires_in
    scope
    jti
regisebersole commented 2 years ago

@strehle as a more accessible summary than mine above, the standard Authorization Code Flow looks like this and _does require a client_secret_: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow#how-it-works

The PKCE-enhanced Authorization Code Flow builds on top of that standard Authorization Code Flow and _does NOT require a client_secret_: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce#how-it-works

This is only for public clients and only applicable to the Authorization Code Flow.

strehle commented 2 years ago

I know about these vendor specific definitions. auth0 is okta. they and many others - including Microsoft and SAP - does it in this way but all of them allow it if configured.

UAA will support same but similar to "autoapprove" with a flag e.g. "public" that needs to be maintained for the clients where you want use use.

strehle commented 2 years ago

Hi, ready for review https://github.com/cloudfoundry/uaa/pull/1888