Client created via management api is broken until dashboard interaction

This management API curl:

curl -X POST \
  https://TENANT.auth0.com/api/v2/clients \
  -H 'Authorization: Bearer TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "foobar",
  "grant_types": ["password"],
  "app_type": "spa",
  "oidc_conformant": true
}
'

Creates a client that will never authenticate a request:

curl 'https://TENANT.auth0.com/oauth/token' -H 'Content-Type: application/json' -d '{"username":"U","password":"P","grant_type":"password","client_id":"CLIENT_ID","audience":"API_AUDIENCE"}'
{"error":"access_denied","error_description":"Unauthorized"}

until I go into the client dashboard https://manage.auth0.com/#/applications/CLIENT_ID/settings

go to advanced, click save (having changed nothing)

curl 'https://TENANT.auth0.com/oauth/token' -H 'Content-Type: application/json' -d '{"username":"U","password":"P","grant_type":"password","client_id":"CLIENT_ID","audience":"API_AUDIENCE"}'
{"access_token":"TOKEN","scope":"SCOPES","expires_in":86400,"token_type":"Bearer"}

The above code snippets are copy-pasted from working requests, not pseudo. I have simply redacted identifying information.

I have been able to isolate further the issue.

When “save” is clicked on the client advanced settings a PATCH request to update the client is made. It is this request which causes the client to work thereafter. I confirmed its this request by extracting a curl version of it and running the flow in my terminal.

curl 'https://manage.auth0.com/api/clients/CLIENT_ID' -X PATCH -H 'content-type: application/json' -d '{"name":"NAME","client_secret":"CLIENT_SECRET","description":"","logo_uri":"","sso":true,"oidc_conformant":true,"allowed_origins":[],"web_origins":[],"jwt_configuration":{"lifetime_in_seconds":36000,"alg":"RS256"},"callbacks":[],"allowed_logout_urls":[],"allowed_clients":[],"mobile":null,"app_type":"spa","token_endpoint_auth_method":"none","is_token_endpoint_ip_header_trusted":false,"grant_types":["http://auth0.com/oauth/grant-type/password-realm","password"],"cross_origin_auth":false,"cross_origin_loc":null}'

I isolated the significant patch data, much smaller repro:

curl -X PATCH \
  https://manage.auth0.com/api/clients/REDACTED \
  -H 'content-type: application/json' \
  -H 'cookie: auth0l=REDACTED' \
  -H 'x-csrftoken: REDACTED' \
  -b auth0l=REDACTED \
  -d '{
    "client_secret": "REDACTED",
    "token_endpoint_auth_method": "none"
}'

I tried putting

"token_endpoint_auth_method": "none"

in the initial create-client post payload, and doing so resolved the issue.

1 Like

Hey there @jason.kuhrt, thank you for sharing the solution to this situation. Be sure to swing by and share your build at Show Your Auth0 if you get a chance and as always, keep us posted on any questions you may have in the future!

Hey James,

Do you agree that there is a bug with Auth0 behaviour.

Being able to create clients in the API that are impossible states to reach with the management app seems wrong.

Furthermore when visiting the client settings page the token_endpoint_auth_method in the UI says “none”, which is not true (its why the client won’t authenticate curls) following a client create by API.

It took quite a few hours to narrow down the root case of the problem. We’re automating Auth0 with Terraform.

This is the comment we’re currently accumulating insight with in our code:

# Warning about Auth0 business rule discreprencies:
#
#   Auth0 Management App, for SPAs, enforces:
#     - sso = true
#     - `password-realm` grant-type if `password` present
#     - grant-type list ordering
#     - token_endpoint_auth_method = "none"
#
#   If in doubt, after creating your client, click "save" on its setting page (Auth0 app)
#   and then do another terraform plan, note how the state has inadvertently changed.

I can’t say whether or not it’s a bug @jason.kuhrt but it’s definitely worth a look with our team to take a deeper look at the situation. I will keep you posted with what we find. Thanks!

I was able to confirm with support @jason.kuhrt, as the value was not be established by the client there’s no way to verify that values attribute. As it in turn we aren’t considering this a bug. I hope this brings some clarity, thanks.

Hi @James.Morrison, I don’t understand your reply.

Hey @jason.kuhrt, sorry about that. Let me see if I can explain it a little better this go around. The value needs to be set for the application to work. Since it hasn’t been set during the creation time, it needs to be set at sometime so that’s why the need patch the connection to be able to correctly grab that value when it’s needed. Otherwise it will produce a null value. Please let me know if this helps explain the situation better. Thank you.

Hi @James.Morrison, thanks for rephrasing.

The value needs to be set for the application to work. Since it hasn’t been set during the creation time, it needs to be set at sometime

Why does the Auth0 API allow for an application to be created that won’t work?

It was a costly area of confusion for us, as we’ve been increasingly automating auth0 with terraform.

1 Like

Hi @jason.kuhrt.
If you don’t specify token_endpoint_auth_method, then the default value assumed is client_secret_post. This means that the /oauth/token endpoint is expecting the client to authenticate itself (by providing the client secret). When you do this:

curl 'https://TENANT.auth0.com/oauth/token' -H 'Content-Type: application/json' -d '{"username":"U","password":"P","grant_type":"password","client_id":"CLIENT_ID","audience":"API_AUDIENCE"}'

you get:

{"error":"access_denied","error_description":"Unauthorized"}

The client is not really in a “bad state”, it’s simply taking a default value that requires the client secret to be provided in the token requests. By adding "token_endpoint_auth_method": "none" you indicate that client authentication is not required (i.e. it’s a public client), so the /oauth/token request is allowed without a client secret provided.

You might argue that "token_endpoint_auth_method": "none" should be set by default for "app_type":"spa", and that’s exactly what the dashboard does (that’s why it works after you click Save). But the API v2 endpoint doesn’t have this logic. I’m not sure if this was by design or not, but changing the behavior at this point might be impossible without breaking existing users.

I will pass this feedback for the team to analyze whether it’s possible at this moment to make the API v2 and server default better match what you get in the dashboard but, in the meantime, the recommendation is to be explicit in the payload as you are doing now. :+1:

3 Likes

Thanks for this explanation! Makes sense now.

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.