tapir icon indicating copy to clipboard operation
tapir copied to clipboard

Specify audience in Oauth 2.0 Client Credentials flow

Open truonghoangnordiska opened this issue 6 months ago • 1 comments

Hi, I'm trying to test the built in securityIn with client credentials flow but getting an error because I haven't specified an audience on this server I set up in auth0.

  val oauthToken = apiEndpoint
    .in("oauth" / "client")
    .securityIn(auth.oauth2.clientCredentialsFlow("https://<omitted>.us.auth0.com/oauth/token"))
    .out(stringBody)

curL created by Tapir/Swagger

curl 'https://<omitted>.us.auth0.com/oauth/token' \
  -H 'accept: application/json, text/plain, */*' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'authorization: Basic <omitted>' \
  -H 'content-type: application/x-www-form-urlencoded' \
  -H 'dnt: 1' \
  -H 'origin: http://localhost:8083' \
  -H 'priority: u=1, i' \
  -H 'referer: http://localhost:8083/' \
  -H 'sec-ch-ua: "Chromium";v="137", "Not/A)Brand";v="24"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: cross-site' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36' \
  -H 'x-requested-with: XMLHttpRequest' \
  --data-raw 'grant_type=client_credentials'

Auth0's sample request on how they want it to look like.

curl --request POST \
  --url https://<omitted>.us.auth0.com/oauth/token \
  --header 'content-type: application/json' \
  --data '{
    "client_id":"<omitted>",
    "client_secret":".<omitted>",
    "audience":"https:/<omitted>.us.auth0.com/api/v2/",
    "grant_type":"client_credentials"
  }'

Right now I'm getting this error in my Swagger:

Image

EDIT: I can get around this by specifying a default audience in Auth0 but this question is still relevant.

truonghoangnordiska avatar Jun 19 '25 11:06 truonghoangnordiska

From what I've found out, the OpenAPI specification that we generate from Tapir is correct - that is, there's no audience parameter to include. This can, however, be specified by the client performing the authentication. In your case, it's the Swagger UI. Here are docs on how to setup the Swagger UI and pass additional config options. ChatGPT claims that this:

additionalQueryStringParams: {
  audience: "https://api.example.com"
}

should cause the audience to be passed properly, however I haven't tested it. As for generating the proper options from the level of SwaggerInterpreter, the additionalQueryStringParams can be set as part of SwaggerUIOptions, however they only support String keys (not objects), so I'm not sure if this will work properly, or if you'll end up with escaped JSON. So please let me know if this works / doesn't work :)

adamw avatar Jun 24 '25 10:06 adamw