{"id":15344342,"url":"https://github.com/jorgecarleitao/ipython-oidc-client","last_synced_at":"2025-04-15T03:32:36.497Z","repository":{"id":62571617,"uuid":"276041888","full_name":"jorgecarleitao/ipython-oidc-client","owner":"jorgecarleitao","description":"A notebook extension to perform OAuth2 flows (e.g. token, code) in Jupyter notebooks.","archived":false,"fork":false,"pushed_at":"2020-08-04T03:40:52.000Z","size":19,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-01T08:42:07.001Z","etag":null,"topics":["authentication","jupyter","notebooks","oauth2-client","python"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jorgecarleitao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-30T08:29:27.000Z","updated_at":"2024-09-12T04:42:55.000Z","dependencies_parsed_at":"2022-11-03T17:01:00.934Z","dependency_job_id":null,"html_url":"https://github.com/jorgecarleitao/ipython-oidc-client","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgecarleitao%2Fipython-oidc-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgecarleitao%2Fipython-oidc-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgecarleitao%2Fipython-oidc-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgecarleitao%2Fipython-oidc-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jorgecarleitao","download_url":"https://codeload.github.com/jorgecarleitao/ipython-oidc-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223657852,"owners_count":17181024,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","jupyter","notebooks","oauth2-client","python"],"created_at":"2024-10-01T10:57:41.417Z","updated_at":"2024-11-08T09:04:30.081Z","avatar_url":"https://github.com/jorgecarleitao.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OAuth2 on Jupyter Notebook\n\nA Jupyter extension to perform OAuth2 flows (e.g. token, code) in notebooks.\n\n## Rational\n\nA major challenge in using APIs from notebooks is to form a trust relationship between the client (notebook)\nand the API.\n\nThis problem is often solved by trusting the *host* of the kernel. The typical approach here is the managed identity pattern through a metadata service, that all major cloud providers offer. A major disadvantage of this pattern is that any user that can access the execution engine (the kernel through a notebook), can also access whatever API that host has access to. I.e. it does not allow discrimatory access to APIs as it does not separate \"access to notebooks\" from \"access to APIs\". This generally leads to host-based access architectures with one host per set of access policies. An aditional limitation of this pattern is that it incentivizes vendor lock-in, as it implies that the service needs to run on the vendor's infrastructure.\n\nAnother pattern to solve this problem is to use a service principal (OAuth2) to access the API through a client secret. This unfortunatelly suffers from the same problems as the managed identity: it leads to indiscrimatory access to the API by anyone with access to the execution engine. This pattern has another risk: in the context of a notebook, it is easy to programatically obtain the client secret, which gives an attacker indiscrimatory access to the API from *any host* in a zero trust network.\n\n### This package\n\nThis package allows users to perform OAuth2 flows (e.g. token, code) in notebooks, thus considering a notebook, and consequently the kernel, as a client application with limited trust. This allows kernels to run on infrastructure without a metadata service, while at the same time maintaining high security standards.\n\n## How to install\n\n```\npip install ipython-oidc-client\n\njupyter nbextension install --py ipython_oidc_client\njupyter nbextension enable --py ipython_oidc_client\njupyter serverextension enable --py ipython_oidc_client\n```\n\nOn your identity provider (e.g. Azure, Google, Auth0), add a reply url to the path `/redirect.html`,\ne.g. `https://example.com/redirect.hml`.\n\n## How to use\n\nOpen a new notebook and run\n\n```\nfrom ipython_oidc_client import authenticate\n\n\naccess_configuration = {\n    'authority': 'https://.../.well-known/openid-configuration',\n    'client_id': '...',\n    'response_type': '...',\n    'scope': '...',\n}\n# valid variables available here: https://github.com/IdentityModel/oidc-client-js/wiki#usermanager\n\ntoken = {}\nauthenticate(access_configuration, token)  # this changes token (see note in README.md)\n```\n\nAt this point, you will be redirected to the authentication page of the identity provider declared\nin `authority`. Once authenticated (e.g. through MFA), you will be redirected back to the notebook.\n\nOnce back in the notebook, re-run the cell above, and `token['access_token']` becomes the access token returned by the authority. Re-running the first cell does not trigger a new authentication; in fact, running that cell on any notebook on the same jupyterhub will yield the same access token.\n\nAt this point, you can run e.g.\n\n```\nimport requests\nr = requests.get('https://api....', headers={'Authorization': f'Bearer {token[\"access_token\"]}'})\n```\n\nOnce the token expires (typically after 1 hour), re-run the cell above to get a new token.\n\nThis procedure can be repeated for access tokens to multiple APIs within the same notebook.\n\n### Why not returning the token?\n\nDue to a [limitation in Jupyter](https://github.com/jupyter/notebook/issues/3187),\nthe access token only becomes available to the kernel after the execution of the *whole* cell.\nAs such, we can't return the token from `authenticate` and instead have to assign it to a variable of global\nscope. This may change in the future.\n\n## Example\n\n[Dockerfile](./Dockerfile) contains a complete installation of the package from pypi on a server,\ndemonstrating how an administrator can install this extension system-wide. Run it with\n\n```bash\ndocker build -t t . \u0026\u0026 docker run -p 8888:8888 --rm -it t\n```\n\nand add `http://localhost:8888/redirect.html` as a reply url to an application in your identity provider.\n\nAfter start, copy the snipped above to a cell and run it.\n\n## Security\n\nThis package has to deal with two execution environments:\n\n* javascript, on the browser\n* Python, on the kernel \n\nOn the browser, it uses [oidc-client-js](https://github.com/IdentityModel/oidc-client-js) to perform\nthe oauth2 flows. In Python, it uses this package's source code, which performs a redirect and communicates with the browser.\n\nThe flow after running the example above is:\n\n1. The client code is loaded when the kernel starts, loading external client dependencies (see below)\n2. The cell is ran, which stores the current path on a cookie and triggers a javascript redirect to the identity provider\n3. the identity provider redirects to `/redirect.html` after sucessful authentication\n4. the callback client code stores the token and redirects the user to the path in a cookie\n\nThis package does not deliver js dependencies; the client needs access to \n\n* https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.10.0/oidc-client.min.js\n* https://unpkg.com/universal-cookie@3/umd/universalCookie.min.js\n\nthis may change in the future.\n\n### Kernel - Browser trust\n\nThis package assumes that the kernel is less trustworthy than the browser. This is because, by design, in a notebook environment, it is easy to\n\n* print a variable on an output cell of a notebook and \n* share the notebook with someone\n\nThese induce a risk of inadvertedly sharing tokens, in particular refresh tokens. To reduce this risk, the browser only shares access tokens with the kernel, which are extrictly necessary to communicate with an API.\n\nAnother advantage of this pattern is that an attack on the kernel server requires significantly more effort to grant access to an API: a user needs to have printed its access token to a notebook and the attacker\nneeds to access that notebook (privileged access) within the expiration date of the token (within 1 hour).This is in opposition to the metadata service, which is available to any process running on the host (see [AWS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) and [Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service#security)).\n\n### Browser trust\n\nThe pattern used by this library has the same risks of a single page application, including secret exfiltration from the browser. This implies that auditing is required for any client-side code that jupyter delivers to end users, as to not exfiltrate tokens from the client.\n\n## How to develop\n\nThis package has 4 components:\n\n* [js client running on the browser](ipyoauth_oidc_client/client)\n* [Python extension running on the server](ipyoauth_oidc_client/server)\n* [Python API to authenticate on a notebook](ipyoauth_oidc_client/__init__.py)\n* [html/js callback page to process the response from the IP](ipyoauth_oidc_client/server/static/redirect.html)\n\nThe easiest way to develop this package is to run\n\n```bash\ndocker build -f Dockerfile.dev -t t . \u0026\u0026 docker run -p 8888:8888 -v $(pwd):/project --rm -it t\n```\n\nand open the browser at http://localhost:8888/?token= (note, *not* 127.0.0.1). Afterwards, add \n`http://localhost:8888/redirect.html` as a reply url in your identity provider.\n\nThis runs a Python-based image with Jupyter and the package installed in a way that\nchanging the js only requires refreshing the page. Changing the Python code requires re-running the image.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgecarleitao%2Fipython-oidc-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjorgecarleitao%2Fipython-oidc-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgecarleitao%2Fipython-oidc-client/lists"}