Open yceruto opened 1 year ago
the password grant (since it is handled internally like the client_credentials) grant only works with Tokens of the kind of APP_PASSWORD
@BeryJu does that mean we cannot authenticate on behave of a user?
From what we tried, the client_credentials
work properly with the service account + token but we are not able to access to protected endpoint where a user resource is required, e.g. /core/users/me
, and that's expected as it's a machine-to-machine flow.
Thanks for your quick answer.
@BeryJu @rissson What we are trying to accomplish is that a user authenticates using only username and password, as specified in the RFC 6749 as Resource Owner Password Credentials Grant
it looks like this:
I took that from Auth0 because it was the simplest one I could find but in the end, the Resource Owner Password Flow is always the same:
Is this something that could be done using Authentik?
I'm interested in hearing more about this too. I've been reading documentation about this kind of use-case and I've been having difficulty implementing this.
Currently also having issues with this, working on dms and can't get grant password working with app passwords.
hello, same error for me, is there any workaround to make the password flow authentication work with a curl request on goauthentik ?
same here for Jamf Connect
@fheisler Maybe this is related to #6139 ? In my case Jamf Connect tries to validate username/password of user by sending it to the token endpoint with "password" as grant_type. Unfortunately authentik only reponds with HTTP 400.
so, basically, we need this to function:
curl --request POST \
--url 'https://authentik.url.local/application/o/token/' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=password \
--data username=user-login \
--data password=user-pw \
--data 'client_id=client-id' \
--data 'client_secret=client-secret' \
--data 'scope=openid profile read:sample'
Agree. Im having real difficulties understanding how to solve it other ways… is it possible to create a flow for this?
--data password=user-pw \
this should be an app password instead of the user's password (see https://github.com/goauthentik/authentik/issues/5860#issuecomment-1577081591)
Yeah, but with esp Jamf Connect the user password gets transferred, as the user types in his password. This is the one which needs to be verified, not an app password. Like the others also mentioned after the comment #5860
This is really not clear in the documentation what an app_password is (i.e. how it differs from a token), if there's a way for a client to request one except through the web interface, or what its purpose is altogether. I'm trying to set up a similar setup to many here:
User gets invited to create an account, creates it, and creates an API Key. This API key is used to authenticate with authentik which issues JWTs for the user.
There doesn't seem to be a clear distinction between tokens and app passwords. The web interface and API call them both tokens. All I've found is that the app passwords work with the /application/o/token/ endpoint, and the tokens don't.
EDIT: Just figured this out for anyone else confused. The admin GUI and terraform docs shed some light: Tokens are just for API access and app passwords are for flow authentication.
I figured out how to fix this problem. The main reason why we have this problem is because someone merged GRANT_TYPE_CLIENT_CREDENTIALS and GRANT_TYPE_PASSWORD a long time ago.
Digging deeper I found out. The error occurs only because the user and his APP_PASSWORD are checked. Logically, a regular user does not have this password.
But we can add a simple check and everything will start working like clockwork. If the usertype is a SERVICE_ACCOUNT, check his APP_PASSWORD, if the user is regular, check his password in the database. But this is still not the correct behavior.
def __post_init_client_credentials_creds(
self, request: HttpRequest, username: str, password: str
):
# Authenticate user based on credentials
user = User.objects.filter(username=username).first()
if not user:
raise TokenError("invalid_grant")
if user.type == UserTypes.SERVICE_ACCOUNT:
token: Token = Token.filter_not_expired(
key=password, intent=TokenIntents.INTENT_APP_PASSWORD
).first()
if not token or token.user.uid != user.uid:
raise TokenError("invalid_grant")
else:
if not user.check_password(password):
raise TokenError("invalid_grant")
self.user = user
# Authorize user access
app = Application.objects.filter(provider=self.provider).first()
if not app or not app.provider:
raise TokenError("invalid_grant")
self.__check_policy_access(app, request)
Event.new(
action=EventAction.LOGIN,
**{
PLAN_CONTEXT_METHOD: "token",
PLAN_CONTEXT_METHOD_ARGS: {
"identifier": token.identifier if token else {},
},
PLAN_CONTEXT_APPLICATION: app,
},
).from_http(request, user=user)
How it works now, grant_type "password" and "client_credentials" works the same!!!:
OK
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'username=your_service_account' \
--data-urlencode 'password=your_service_account_APP_PASSWORD'
OK
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'client_secret=your_client_secret'
OK
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'client_secret=your_client_secret'
OK
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'username=your_service_account' \
--data-urlencode 'password=your_service_account_APP_PASSWORD'
Ideally, these two flows should be separated. When code validate client_id and client_secret it returns the client_credentials token. If client_secret is invalid or empty it tries to check service account and APP_PASSWORD.
After my patch, both flows still don't work correctly. It turns out that we can log out a user without client_secret, regardless of grant_type.
Case 1:
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password or client_credentials' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'client_secret=your_client_secret'
// will be ignored
--data-urlencode 'username=username' \
--data-urlencode 'password=password'
Case 2:
curl --location 'https://auth.example.com/application/o/token/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password or client_credentials' \
--data-urlencode 'client_id=your_client_id' \
--data-urlencode 'username=username' \
--data-urlencode 'password=password'
Describe your question/ We are trying to use Authentik as our own identity provider inside a Microservice architecture to login users through OAuth2 Password Grant. Basically, we want to implement this flow: https://auth0.com/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow.
We found in the documentation that it's not listed as grant type https://goauthentik.io/docs/providers/oauth2/ but inside https://goauthentik.io/docs/providers/oauth2/client_credentials there is a note about password grant saying:
Further, checking the OpenID endpoint
/application/o/{appName}/.well-known/openid-configuration
we see that the password grant is supported:According to that, we've tried to send requests with many alternatives, including scope, response_type, etc, without success:
It always fails saying:
We appreciate it any advice about this topic or any confirmation that the password grant is not supported. Thanks!
Version and Deployment (please complete the following information):