authentik
authentik copied to clipboard
Misuse of client_credentials and password grant
Describe the bug
According to Section 4.3 of RFC6749, the client_credentials grant should only take in client_id and client_secret (if any) as its authentication method and return an access token, however, this is not the case in authentik.
According to authentik docs, the "client_credentials" grant somehow requires both username and password, which is not what client_credentials grant was originally designed for in the standards.
On the other hand, there is this password grant defined in Section 4.4 of RFC6749, stating it requires both username and password fields in the request body, which I believe is what authentik is originally targeting for.
Expected behavior
client_credentials to not take username and password as a required field, this grant should be named password instead.
Version and Deployment (please complete the following information):
- authentik version: 2023.5.4
- Deployment: docker-compose
Additional context In authentik docs, there's this line that says
Note that authentik does treat a grant type of
passwordthe same asclient_credentialsto support applications which rely on a password grant.
However, after testing, it appears that passing in a grant_type of password makes authentik throw the following exception
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 472, in thread_handler
raise exc_info[1]
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
response = await wrapped_callback(
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 435, in __call__
ret = await asyncio.wait_for(future, timeout=None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/tasks.py", line 442, in wait_for
return await fut
^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py", line 22, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 476, in thread_handler
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 103, in view
return self.dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 55, in wrapped_view
return view_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/authentik/providers/oauth2/views/token.py", line 429, in dispatch
response = super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 142, in dispatch
return handler(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/authentik/providers/oauth2/views/token.py", line 467, in post
raise ValueError(f"Invalid grant_type: {self.params.grant_type}")
builtins.ValueError: Invalid grant_type: password
Which is not expected by the documentations
I think some of the reason for this is due to https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow using client_credentials in conjunction with client_assertion_type
I'm not sure how we could implement a spec-accurate version of this, since there would need to be some kind of user in authentik to attribute actions to.
The exception should definitely not happen though
I think some of the reason for this is due to https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow using client_credentials in conjunction with
client_assertion_typeI'm not sure how we could implement a spec-accurate version of this, since there would need to be some kind of user in authentik to attribute actions to.
The exception should definitely not happen though
https://github.com/goauthentik/authentik/blob/0b5870f16e41d9eb5535b495443dd2b0bb65a19c/authentik/providers/oauth2/views/token.py#L456C1-L469C1 According to these lines ^, password grant is not included in the checks, therefore raising an exception
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I don’t think this issue is fully fixed yet, can @BeryJu reopen it?
I agree and also was kind of confused to see this way of passing credentials (client_id + username + password) to the /token endpoint to retrieve an access_token. Wouldn't this produce quite some issues in existing oidc/oauth2 libraries existing out there?
One quick suggestion (hack?) to make it RFC6749 compliant: concatenate username and password with a :, base64-decode it and use it as client_secret. Then you're able to extract username/password on Authentik server side again.
Hey guys,
Just came across this issue thanks to CommanderStorm's mention.
I'm not sure how we could implement a spec-accurate version of this, since there would need to be some kind of user in authentik to attribute actions to.
Would a dynamically created service user + role per outpost (if selected for example) be sufficient or would that be overcomplicating matters?
Keycloak seems to have a similar-ish method to assign the Client Credentials grant, which then allows it to work with services such as uptimekuma.
Hey guys,
Apologies for poking, but is there any progress on this one?
I'm unable to use Authentik with services like UptimeKuma, which means unfortunately I can't migrate things across.
Cheers!
We're weighing solution with an aim to fix this in the next (March/April) release in a backwards-compatible way.
grant_type password does not seem to work, still. Getting HTTP 400 when trying to use it. see: https://github.com/goauthentik/authentik/issues/5860#issuecomment-2191603409