Skip to main content

tessera logo

Acquire and securely store OAuth2/OIDC tokens in JupyterHub.

CI Documentation PyPI Python License


tessera adds a per-server button in JupyterLab. On click, the user runs an OAuth2/OIDC authorization-code flow (confidential client, PKCE). A JupyterHub Service receives the callback, exchanges the code, and stores the refresh token encrypted at rest. Notebooks then read a fresh access token from the Service on demand. The button is green when a valid refresh token exists, red otherwise. tessera is generic: any OAuth2/OIDC provider is a configuration entry.

tessera is not an Authenticator. It never signs anyone in to JupyterHub: your Hub keeps whatever Authenticator it already uses (PAM, LDAP, OAuth, or any other). tessera runs a separate step after that login, acquiring tokens from external OAuth2/OIDC providers so notebooks can call the APIs those providers protect.

The tessera panel in JupyterLab: one button per declared server, green when a valid refresh token is stored, with token details on demand

Signed in on 6 August, still green on 10 August: the access token expired several times in between, and each one was renewed from the stored refresh token, on demand.

How it works

  1. One button per declared server. The panel shows a button for each OAuth server in your configuration, green when a valid refresh token is stored for that user, red otherwise.
  2. A click starts an authorization-code flow with PKCE. The Service generates the state and the PKCE verifier, sends the browser to the provider with the S256 challenge, and keeps the verifier to itself.
  3. The provider calls back to the Service, which validates the state against the flow it started and exchanges the code for tokens. The browser never handles a token.
  4. The refresh token is encrypted at rest, with the encryption key held separately from the database file, so the database on its own reveals nothing.
  5. Notebooks read an access token on demand. The kernel client (get_token("my-idp"), or TESSERA_TOKEN["my-idp"]) fetches a fresh token from the Service on each access. Nothing is cached kernel-side and no token ever sits in an environment variable, so a token revoked at the provider is never served from a stale copy.

Architecture (three surfaces)

Surface Stack Role
Frontend TypeScript/React Per-server status button (green/red), shipped as a prebuilt JupyterLab extension.
Service Python 3.10+ JupyterHub Service exposing /login, /callback, /token; encrypted token store.
Admin CLI Python (Typer) Deployment and ops helpers: config-snippet, init-config, doctor, install-kernel-config.

Install

pip install jupyterhub-tessera

Installing the Python package also ships the prebuilt JupyterLab extension; no manual frontend copy is required.

Project layout

Path What lives there
src/tessera/ Service, admin CLI, kernel client, and the prebuilt lab extension
frontend/src/ TypeScript/React panel sources, with their tests alongside them
tests/ Python test suite (config, flow, store, service, kernel, end to end)
docs/ Sphinx documentation sources

Development

Requirements: Python 3.10+, Node.js 20+.

# Python (use a virtual environment created outside any synced folder)
pip install -e ".[dev]"

# Frontend
npm install
npm run build

Security

A refresh token and a client secret are encrypted at rest, with the encryption key held separately from the database. The frontend never reads, stores, or logs a token; it only consumes a boolean status.

License

MIT, Copyright (c) 2026 Michel TRUONG.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jupyterhub_tessera-1.0.0.tar.gz (733.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jupyterhub_tessera-1.0.0-py3-none-any.whl (88.8 kB view details)

Uploaded Python 3

File details

Details for the file jupyterhub_tessera-1.0.0.tar.gz.

File metadata

  • Download URL: jupyterhub_tessera-1.0.0.tar.gz
  • Upload date:
  • Size: 733.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for jupyterhub_tessera-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1e8313959d73cdd0820ea9d35b507d12e47b915d146f05c5c142d3da51384604
MD5 50e7ad9c56910e7f8ce0611a837d2fcd
BLAKE2b-256 14885297def007826c0d433945b98f12353896848bc1dc23018b51cda6dde03d

See more details on using hashes here.

Provenance

The following attestation bundles were made for jupyterhub_tessera-1.0.0.tar.gz:

Publisher: ci.yml on KaminoU/jupyterhub-tessera

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jupyterhub_tessera-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for jupyterhub_tessera-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e49deb6959948d6f846414cd409ad46eed02c056fc900b02b74f1b7051bbce29
MD5 4eff0737c7a2b353d1aa0fb65764779b
BLAKE2b-256 be49f1bbf078d87dfea04a2e97c0ccec7c3d6aca5b555e34577ca3130881c99a

See more details on using hashes here.

Provenance

The following attestation bundles were made for jupyterhub_tessera-1.0.0-py3-none-any.whl:

Publisher: ci.yml on KaminoU/jupyterhub-tessera

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page