hydra
hydra copied to clipboard
client_credentials grant type accepts audience at creation, but doesn't return them in access token
Preflight checklist
- [X] I could not find a solution in the existing issues, docs, nor discussions.
- [X] I agree to follow this project's Code of Conduct.
- [X] I have read and am following this repository's Contribution Guidelines.
- [ ] This issue affects my Ory Network project.
- [ ] I have joined the Ory Community Slack.
- [ ] I am signed up to the Ory Security Patch Newsletter.
Describe the bug
No audience is returned for client_credentials grant flow even when the audience parameter is explicitly set. This issue results in an invalid JWT token when validating it because of an empty aud claim.
How to set up an audience for the client? Docs doesn't help - https://www.ory.sh/docs/hydra/guides/audiences, same for tutorial - https://www.ory.sh/docs/hydra/5min-tutorial
Reproducing the bug
This is easily reproducible:
- Start Ory Hydra with minimal setup -
docker run --name hydra -e DSN=memory -e SECRETS_SYSTEM=abcdefghjklimnop -e STRATEGIES_ACCESS_TOKEN=jwt -p 4444:4444 -p 4445:4445 oryd/hydra:v2.0.3 serve all --dev
- Create client_credentials client with specified audience.
docker exec hydra hydra create client --endpoint http://127.0.0.1:4445/ --format json --grant-type client_credentials --audience account
. - Send a request without the audience
curl --location 'http://localhost:4444//oauth2/token' \
--header 'Authorization: Basic M2M0OGI5Y2QtNzEyNS00ZDFkLThkZDMtMGJiYTIzNGQ4NGNiOmo2LjBET2h4U0stVnpHaUhnUHVoLnppNEJQ' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials'
- We can verify that the audience is validated but not returned in the response by specifying the incorrect value.
Adding
--data-urlencode 'audience=account'
results in the same response as without the audience. - Response example
{
"access_token": "***",
"expires_in": 3599,
"scope": "",
"token_type": "bearer"
}
Relevant log output
{"audience":["account"],"client_id":"3c48b9cd-7125-4d1d-8dd3-0bba234d84cb","client_name":"","client_secret":"j6.0DOhxSK-VzGiHgPuh.zi4BP","client_secret_expires_at":0,"client_uri":"","created_at":"2023-02-15T01:55:55Z","grant_types":["client_credentials"],"jwks":{},"logo_uri":"","metadata":{},"owner":"","policy_uri":"","registration_access_token":"ory_at_v9rdUliw9PqR3X7saMk-GdMqUA-MH-HPfwyxg1ARDdQ.R6sB7EKSB0I5BoNftG6pGlqP7k2XWtxB3i5vrbXKOK4","registration_client_uri":"http://localhost:4444/oauth2/register/3c48b9cd-7125-4d1d-8dd3-0bba234d84cb","request_object_signing_alg":"RS256","response_types":["code"],"scope":"offline_access offline openid","subject_type":"public","token_endpoint_auth_method":"client_secret_basic","tos_uri":"","updated_at":"2023-02-15T01:55:55.234026Z","userinfo_signed_response_alg":"none"}
Relevant configuration
No response
Version
2.0.3(latest)
On which operating system are you observing this issue?
Linux
In which environment are you deploying?
Docker
Additional Context
I'm unable to use Ory Hydra as a token provider for Kafka Oauthbearer OIDC because of empty audience array, which is unexpected for JwtConsumer.
Keycloak works fine since it returns audience.
Caused by: org.jose4j.jwt.consumer.InvalidJwtException: JWT (claims->{"aud":[],"client_id":"a61f7d4d-e365-4134-8b5c-2053213b4cd8","exp":1676427193,"ext":{},"iat":1676423593,"iss":"http://localhost:4444/","jti":"a98d16a5-6bfd-4498-b3d9-ef6d961615f9","nbf":1676423593,"scp":[],"sub":"a61f7d4d-e365-4134-8b5c-2053213b4cd8"}) rejected due to invalid claims or other invalid content. Additional details: [[8] Audience (aud) claim [] present in the JWT but no expected audience value(s) were provided to the JWT Consumer. Expected one of [] as an aud value.]
at org.jose4j.jwt.consumer.JwtConsumer.validate(JwtConsumer.java:459)
The OAuth2 spec does not specify how the audience would be used and validated for client_credentials flows, which is why we do not support it currently. I think auth0 supports an audience claim, but I don't think they validate it?
I will check later if the audience is validated, but it's included in JWT tokens - here are decoded tokens from Azure AD and Keycloak.
Sorry for the delay in response.
I think auth0 supports an audience claim, but I don't think they validate it?
I checked for Keycloak: there are multiple ways to use audience there. One is a hardcoded value without a validation that can be customized, and another one, dynamic setting/verifying the audience claim based on the provided scope. So answering to your question, they have an option for validating an audience.
-
https://www.keycloak.org/docs/latest/server_admin/#_audience_hardcoded For example, Client -> Client Details -> Client Scope -> choose dedicated scope -> add mapper -> by configuration -> audience/audience resolve. Then added audience claims can be included in the token.
-
https://www.keycloak.org/docs/latest/server_admin/#setup-4
"verify-token-audience" : true,
When setting up audience checking:
Ensure that services are configured to check audience on the access token sent to them by adding the flag verify-token-audience in the adapter configuration. See Adapter configuration for details.
Ensure that access tokens issued by Keycloak contain all necessary audiences. Audiences can be added using the client roles as described in the next section or hardcoded. See Hardcoded audience.
I don't have a ready to test auth0 setup to verify how it works there, but they also have examples with audience
and client_credentials
requests - https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#example-post-to-token-url
The OAuth2 spec does not specify how the audience would be used and validated for client_credentials flows, which is why we do not support it currently.
But as I showed in my first message, specifying an invalid audience leads to an error. The only problem is that aud
claim is empty in the JWT token obtained for the client_credentials
grant type in case of Ory Hydra.
I think it makes sense for Ory Hydra to include an audience claim in the JWT token if specified at client creation to mimic the hardcoded behaviour from the Keycloak. What do you think, @aeneasr?
i am also curious how we should validate the token without the aud
is returned from introspection? using scope
instead? if using scope
, does hydra support registering resource with custom scope?
In our case, we are trying to use hydra as the authorization server for secure our APIs. currently we are using the context path as the scope, so that nginx will intercept the request and use issuer url
+scope
to do the authorization before sending request to the upstream. I am hoping to use aud
for this validation, and use scope
for granting permission for things like read
or write
I believe this to now be possible using actions / webhooks: https://www.ory.sh/docs/hydra/guides/claims-at-refresh