Reposting here at the suggestion of @hackerman from the slack channel;
The Problem:
When making a introspection request for a token that was generated via a registered auth code client, extra information that was assigned when the session is created is returned in the response allowing oathkeeper to use it within the id_token mutator.
However, when a client is created with the client_credentials grant type, when a token that was generated by the token endpoint is inspected, it does not return the extra meta information (Or indeed owner values) that where submitted when the client was created.
It is slightly unclear from the the documentation as to if this should be the case, and if this is a deliberate design decision.
The long version*
We want to allow users to create their own oauth clients using client credentials grant but constrain such client so as to operate only within the context of the user and their associated realm.
When a user signs in via an auth_code flow, they are issued an access token that can be inspected via oathkeeper and thus generate an id_token that can be passed to backend applications.
{
"active": true,
"scope": "openid profile myapp offline_access",
"client_id": "test_ui_dev",
"sub": "1234567890",
"exp": 1594892078,
"iat": 1594888477,
"iss": "https://hydra.foo.dev/",
"token_type": "access_token",
"ext": {
"realm": {
"id": 1234567890
},
"user": {
"id": 9876543210
}
}
}
Backend applications can then rely on the id_token custom claims generated via oathkeeper for the required information (user.id and realm.id in this case)
However this breaks down when a request is made via a client with the client_creds grant type. The client was created using the standard method (http client create body to hydra admin endpoint). Amongst its provisions, is the ability to provide extra information (metadata and owner).
If this client requests a token from the hydra/oath2/token endpoint a valid access token is issued. However upon introspection, the response does not include any of the metadata values associated with the client.
{
"active": true,
"client_id": "test_client_creds_client",
"sub": "1234567890",
"exp": 1594891895,
"iat": 1594888295,
"iss": "https://hydra.foo.dev/",
"token_type": "access_token"
}
My expectation here is that the introspection endpoint should have included the metadata information associated with the client.
My questions are;
- Is this a design decision or oversight?
- Is what I am trying to do a good idea (I do want 3rd party clients to register but I want them scoped to just their realm so they get to work only on their data) and consistent with the values of hydra/oathkeeper
Workaround
On oathkeeper using a hydrator to detect the subject name and determine if it is a client or user can be performed to obtain the correct information and pass down onto the next mutator (id_token). While this is fine, it is another small application to maintain and introduces another http request in an increasing chain of them.
Observations
The “issue” around this appears to stem from the fact that an auth code flow requires a session and during that session the developer is free to add data to the session (access_token, id_token) when accepting the request.
However in this particular use case, a 3rd party registered a client with client creds flow only. As part of that process meta data is attached to the client within hydra. As there is no session active when a request is made for a token to the token endpoint, there is no session information. In pseudo code this in my expectation would have been
if (grant_type === "client_credentials") {
meta = fetchClientMetaData(client_id)
}
Appreciate that hydra is golang (I’m just not that comfortable with its sources yet to be able to write a sample in go)
It would make sense to me that a token issued via a client creds grant in the absence of session information should return the static meta_data attached to that client when it was created as part of the introspection request. This would negate the use for a hydrator handler.
Similar, if using the oauth2_client_credentials authenticator for oathkeeper (which I would prefer not to use in the first instance) would still induce this issue.
I would value your thoughts on this use case and if I should progress this to a request for change.
TIA