Skip to content

Commit

Permalink
Support client_credentials grant type
Browse files Browse the repository at this point in the history
  • Loading branch information
tomako authored and OmeGak committed Dec 19, 2024
1 parent a364d70 commit a58b21f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 14 deletions.
34 changes: 29 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,41 @@ MULTIPASS_IDENTITY_PROVIDERS = {
'title': 'Keycloak Identity Provider',
'identifier_field': 'email',
'keycloak_args': {
'client_name': '<client_name>',
'grant_type': 'client_credentials',
'client_id': '<client_id>',
'client_secret': '<client_secret>',
'username': <username>,
'password': <password>,
'access_token_url': <access-token-url>,
'realm_api_url': <realm-api-url>
'access_token_url': '<access-token-url>',
'realm_api_url': '<realm-api-url>'
}
}
}
```

The configuration values are following:

1. `grant_type`

Default value is `client_credentials`. In Keycloak, "Service accounts roles" must be enabled in client config (Client details/Settings/Capability).

`password` is also supported. In Keycloak, "Direct access grants" must be enabled in client config (Client details/Settings/Capability). In this case 2 additional fields must be added: `username` and `password`.

2. `client_id`

In Keycloak, Client details/Setting/Client ID field.

3. `client_secret`

In Keycloak, Client details/Credentials/Client Secret field.

4. `access_token_url`

In Keycloak, Realm settings/General/Endpoints/OpenID Endpoint Configuration/"token_endpoint".

5. `realm_api_url`

The URL format is `<base url>/admin/realms/<realm name>`, where the realm is where the users and user groups are configured.


### Performance

The library needs to get an API access token from Keycloak which typically takes 200-300ms. Set the `cache` key of the multipass identity provider configuration to the import path of a Flask-Caching instance or a function returning such an instance, or the instance itself to enable caching of tokens (until they expire) and group data (30 minutes).
Expand Down
15 changes: 9 additions & 6 deletions src/flask_multipass_keycloak.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from flask_multipass.group import Group
from flask_multipass.providers.authlib import AuthlibAuthProvider
from flask_multipass.providers.authlib import AuthlibIdentityProvider
from requests.auth import HTTPBasicAuth
from requests.exceptions import RequestException
from werkzeug.exceptions import BadRequest

Expand Down Expand Up @@ -209,12 +208,16 @@ def _get_api_session(self):
if api_token:
api_session.headers.update({'Authorization': f'Bearer {api_token}'})
return api_session
basic = HTTPBasicAuth(self.keycloak_settings['client_name'], self.keycloak_settings['client_secret'])
data = {'username': self.keycloak_settings['username'],
'password': self.keycloak_settings['password'],
'grant_type': 'password'}
data = {'client_id': self.keycloak_settings['client_id'],
'client_secret': self.keycloak_settings['client_secret'],
'grant_type': self.keycloak_settings['grant_type']}
# Supported grant types: password and client_credentials
if data['grant_type'] == 'password':
data |= {'username': self.keycloak_settings['username'],
'password': self.keycloak_settings['password']}

self.logger.info('Requesting access token')
response = api_session.post(self.keycloak_settings['access_token_url'], auth=basic, data=data)
response = api_session.post(self.keycloak_settings['access_token_url'], data=data)
if response.status_code != 200:
error_message = self._get_error_message(response)
self.logger.error(f'{error_message} (URL: %s)', response.url)
Expand Down
5 changes: 2 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ def provider():
settings = {
'identifier_field': 'email',
'keycloak_args': {
'client_name': 'test_client_name',
'grant_type': 'client_credentials',
'client_id': 'test_client_id',
'client_secret': 'test_client_secret',
'username': 'test_username',
'password': 'test_password',
'access_token_url': 'http://localhost/realms/test_realm/protocol/openid-connect/token',
'realm_api_url': 'http://localhost/admin/realms/test_realm'
},
Expand Down

0 comments on commit a58b21f

Please sign in to comment.