# KeyCloakAuthenticator
Authenticates users via SSO using OIDC.
This authenticator implements a refresh mechanism, ensuring that the tokens stored in the user dict are always up-to-date (if the update is not possible, it forces a re-authentication of the user). It also allows exchanging the user token for tokens that can be used to authenticate against other (external) services.
This Authenticator is built on top of [OAuthenticator](https://github.com/jupyterhub/oauthenticator) and should be possible to use some of its configuration values.
## Requirements
* Jupyterhub
* oauthenticator
* PyJWT[crypto]
* openssl\_devel (see below)
## Installation
```bash
pip install keycloakauthenticator
```
If you enable check\_signature, you also need the `openssl_devel` (or equivalent in your distribution) package.
## Usage
In your JupyterHub config file, set the authenticator and configure it:
```python
# Enable the authenticator
c.JupyterHub.authenticator_class = 'keycloakauthenticator.KeyCloakAuthenticator'
c.KeyCloakAuthenticator.username_claim = 'preferred_username'
# URL to redirect to after logout is complete with auth provider.
c.KeyCloakAuthenticator.logout_redirect_url = 'https://cern.ch/swan'
c.KeyCloakAuthenticator.oauth_callback_url = 'https://swan.cern.ch/hub/oauth_callback'
# Specify the issuer url, to get all the endpoints automatically from .well-known/openid-configuration
c.KeyCloakAuthenticator.oidc_issuer = 'https://auth.cern.ch/auth/realms/cern'
# If you need to set a different scope, like adding the offline option for longer lived refresh token
c.KeyCloakAuthenticator.scope = ['profile', 'email', 'offline_access']
# Only allow users with this specific roles (none, to allow all)
c.KeyCloakAuthenticator.allowed_roles = []
# Specify the role to set a user as admin
c.KeyCloakAuthenticator.admin_role = 'swan-admin'
# If you have the roles in a non default place inside the user token, you can retrieve them
# This must return a set
def claim_roles_key(env, token):
return set(token.get('app_roles', []))
c.KeyCloakAuthenticator.claim_roles_key = claim_roles_key
# Request access tokens for other services by passing their id's (this uses the token exchange mechanism)
c.KeyCloakAuthenticator.exchange_tokens = ['eos-service', 'cernbox-service']
# If your authenticator needs extra configurations, set them in the pre-spawn hook
def pre_spawn_hook(authenticator, spawner, auth_state):
spawner.environment['ACCESS_TOKEN'] = auth_state['exchanged_tokens']['eos-service']
spawner.environment['OAUTH_INSPECTION_ENDPOINT'] = authenticator.userdata_url.replace('https://', '')
spawner.user_uid = auth_state['oauth_user']['cern_uid']
decoded_token = authenticator._decode_token(auth_state['access_token'])
spawner.user_roles = authenticator.claim_roles_key(authenticator, decoded_token)
c.KeyCloakAuthenticator.pre_spawn_hook = pre_spawn_hook
#Configure token signature verification
c.KeyCloakAuthenticator.check_signature=True
c.KeyCloakAuthenticator.jwt_signing_algorithms = ["HS256", "RS256"]
# Once a token is refreshed, by default jupyterhub does not trigger a refresh again (triggered when receiving any authenticated request) in `Authenticator.auth_refresh_age` seconds (default 5 minutes)
# If you want to refresh the token less often, and align the refresh to your tokens expiration, which will also trigger the update of the oAuth/OIDC token, this value can be changed:
c.KeyCloakAuthenticator.auth_refresh_age = 900 # 15 minutes
```
It's also necessary to configure the Client ID and secret. One way of doing this is by setting the following environment variables:
```bash
OAUTH_CLIENT_ID=my_id
OAUTH_CLIENT_SECRET=my_secret
```
Raw data
{
"_id": null,
"home_page": "https://github.com/swan-cern/jupyterhub-extensions",
"name": "keycloakauthenticator",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "JupyterHub,Authenticator,SWAN,CERN",
"author": "SWAN Admins",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/39/f9/40d722a69433d164779f72e1994bfc355518891c3506f0387d666c9ae85e/keycloakauthenticator-4.0.0.tar.gz",
"platform": "Linux",
"description": "# KeyCloakAuthenticator\n\nAuthenticates users via SSO using OIDC. \n\nThis authenticator implements a refresh mechanism, ensuring that the tokens stored in the user dict are always up-to-date (if the update is not possible, it forces a re-authentication of the user). It also allows exchanging the user token for tokens that can be used to authenticate against other (external) services.\n\nThis Authenticator is built on top of [OAuthenticator](https://github.com/jupyterhub/oauthenticator) and should be possible to use some of its configuration values.\n\n\n## Requirements\n\n* Jupyterhub\n* oauthenticator\n* PyJWT[crypto]\n* openssl\\_devel (see below)\n\n## Installation\n\n```bash\npip install keycloakauthenticator\n```\n\nIf you enable check\\_signature, you also need the `openssl_devel` (or equivalent in your distribution) package.\n\n## Usage\n\nIn your JupyterHub config file, set the authenticator and configure it:\n\n```python\n# Enable the authenticator\nc.JupyterHub.authenticator_class = 'keycloakauthenticator.KeyCloakAuthenticator'\nc.KeyCloakAuthenticator.username_claim = 'preferred_username'\n\n# URL to redirect to after logout is complete with auth provider.\nc.KeyCloakAuthenticator.logout_redirect_url = 'https://cern.ch/swan'\nc.KeyCloakAuthenticator.oauth_callback_url = 'https://swan.cern.ch/hub/oauth_callback'\n\n# Specify the issuer url, to get all the endpoints automatically from .well-known/openid-configuration\nc.KeyCloakAuthenticator.oidc_issuer = 'https://auth.cern.ch/auth/realms/cern'\n\n# If you need to set a different scope, like adding the offline option for longer lived refresh token\nc.KeyCloakAuthenticator.scope = ['profile', 'email', 'offline_access']\n# Only allow users with this specific roles (none, to allow all)\nc.KeyCloakAuthenticator.allowed_roles = []\n# Specify the role to set a user as admin\nc.KeyCloakAuthenticator.admin_role = 'swan-admin'\n\n# If you have the roles in a non default place inside the user token, you can retrieve them\n# This must return a set\ndef claim_roles_key(env, token):\n return set(token.get('app_roles', []))\nc.KeyCloakAuthenticator.claim_roles_key = claim_roles_key\n\n# Request access tokens for other services by passing their id's (this uses the token exchange mechanism)\nc.KeyCloakAuthenticator.exchange_tokens = ['eos-service', 'cernbox-service']\n\n# If your authenticator needs extra configurations, set them in the pre-spawn hook\ndef pre_spawn_hook(authenticator, spawner, auth_state):\n spawner.environment['ACCESS_TOKEN'] = auth_state['exchanged_tokens']['eos-service']\n spawner.environment['OAUTH_INSPECTION_ENDPOINT'] = authenticator.userdata_url.replace('https://', '')\n spawner.user_uid = auth_state['oauth_user']['cern_uid']\n decoded_token = authenticator._decode_token(auth_state['access_token'])\n spawner.user_roles = authenticator.claim_roles_key(authenticator, decoded_token)\nc.KeyCloakAuthenticator.pre_spawn_hook = pre_spawn_hook\n\n#Configure token signature verification\nc.KeyCloakAuthenticator.check_signature=True\nc.KeyCloakAuthenticator.jwt_signing_algorithms = [\"HS256\", \"RS256\"]\n\n# Once a token is refreshed, by default jupyterhub does not trigger a refresh again (triggered when receiving any authenticated request) in `Authenticator.auth_refresh_age` seconds (default 5 minutes)\n# If you want to refresh the token less often, and align the refresh to your tokens expiration, which will also trigger the update of the oAuth/OIDC token, this value can be changed:\nc.KeyCloakAuthenticator.auth_refresh_age = 900 # 15 minutes\n```\n\n\nIt's also necessary to configure the Client ID and secret. One way of doing this is by setting the following environment variables:\n\n```bash\nOAUTH_CLIENT_ID=my_id\nOAUTH_CLIENT_SECRET=my_secret\n```\n",
"bugtrack_url": null,
"license": "AGPL-3.0",
"summary": "KeyCloakAuthenticator: Authenticate JupyterHub users with KeyCloak and OIDC",
"version": "4.0.0",
"project_urls": {
"Homepage": "https://github.com/swan-cern/jupyterhub-extensions"
},
"split_keywords": [
"jupyterhub",
"authenticator",
"swan",
"cern"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e348fff6f682b079a3d7c6450337a5a2ca47dc839ebd968acd0b9986bcda35ef",
"md5": "bd95c7d7950186e740b1b5d3632f602e",
"sha256": "7730da5c6c3a30612254a993caf37ab18b6b78e4439d7510fd5a18f4c17b1e0e"
},
"downloads": -1,
"filename": "keycloakauthenticator-4.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bd95c7d7950186e740b1b5d3632f602e",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 10562,
"upload_time": "2023-10-24T12:46:15",
"upload_time_iso_8601": "2023-10-24T12:46:15.557697Z",
"url": "https://files.pythonhosted.org/packages/e3/48/fff6f682b079a3d7c6450337a5a2ca47dc839ebd968acd0b9986bcda35ef/keycloakauthenticator-4.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "39f940d722a69433d164779f72e1994bfc355518891c3506f0387d666c9ae85e",
"md5": "dd074e84179eab12cf1144784d5b6827",
"sha256": "ac950c44ecfefae87cd22cfcf71a2f1b97bcc60cfb6cbabee015abbc29a3dfa5"
},
"downloads": -1,
"filename": "keycloakauthenticator-4.0.0.tar.gz",
"has_sig": false,
"md5_digest": "dd074e84179eab12cf1144784d5b6827",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11045,
"upload_time": "2023-10-24T12:46:16",
"upload_time_iso_8601": "2023-10-24T12:46:16.576379Z",
"url": "https://files.pythonhosted.org/packages/39/f9/40d722a69433d164779f72e1994bfc355518891c3506f0387d666c9ae85e/keycloakauthenticator-4.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-10-24 12:46:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "swan-cern",
"github_project": "jupyterhub-extensions",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "keycloakauthenticator"
}