Skip to main content

Read the signed ShinyHub identity a Shiny/Streamlit/Dash app receives, in one call.

Project description

shinyhub-identity

Read the signed identity ShinyHub forwards to your app, in one call. No per-app JWT plumbing.

ShinyHub injects a short-lived, per-app HS256 JWT (X-Shinyhub-Identity-Token) into every request it proxies, and hands your app its verification key via SHINYHUB_IDENTITY_KEY and SHINYHUB_APP_SLUG. This package verifies that token and returns the identity.

pip install shinyhub-identity
# or: uv add shinyhub-identity

Use it

from shinyhub_identity import current_user

def server(input, output, session):
    user = current_user(session.http_conn.headers)   # None when anonymous
    if user is None:
        ...  # logged-out visitor
    elif "platform-admins" in user.groups:
        ...  # gate admin features on the VERIFIED groups

current_user(headers) returns an Identity or None. It works with any header mapping - Shiny for Python's session.http_conn.headers, a Starlette/Flask request's headers, or a plain dict.

Identity fields:

Field Type Value
user_id str Decimal user ID
username str Username
role str Platform role: viewer, developer, operator, or admin
groups tuple[str, ...] Verified group names
groups_truncated bool True when the group list was capped at 100
email str "" unless the deployment's IdP asserts one
name str Display name; "" unless the IdP asserts one
claims Mapping The raw verified JWT claims

Every failure is anonymous, never a crash. No token, bad signature, wrong audience/issuer, an expired token, or no ShinyHub in front at all (running the app locally) all return None - no exception is raised - so your app stays testable without SSO.

current_user reads SHINYHUB_IDENTITY_KEY/SHINYHUB_APP_SLUG from the environment by default; pass key=/slug= explicitly for tests.

Diagnostics: a present-but-rejected token warns

A genuine anonymous visitor sends no token at all, so a token that is present but fails verification almost always means a misconfigured deployment (missing or wrong SHINYHUB_IDENTITY_KEY, audience/issuer mismatch, clock skew). That case emits a WARNING on the stdlib "shinyhub_identity" logger - once per distinct reason per process - while the return value stays None (fail-closed). A request without a token stays completely silent, so anonymous traffic never spams your logs.

If your platform gates on identity, add a startup self-check so a broken deployment fails fast instead of silently rendering everyone anonymous:

import os

assert os.environ.get("SHINYHUB_IDENTITY_KEY"), "identity key not injected"
assert os.environ.get("SHINYHUB_APP_SLUG"), "app slug not injected"

Local development

With no ShinyHub proxy in front there is no token, so current_user is always None. Instead of writing a per-app mock, set:

export SHINYHUB_IDENTITY_DEV_USER=devlin
export SHINYHUB_IDENTITY_DEV_GROUPS="team-a, team-b"   # optional
export SHINYHUB_IDENTITY_DEV_EMAIL=devlin@example.com  # optional
export SHINYHUB_IDENTITY_DEV_NAME="Devlin Example"     # optional
export SHINYHUB_IDENTITY_DEV_ROLE=admin                # optional, default viewer

current_user then returns a synthetic Identity marked with claims == {"dev": True, ...}. This can never activate under a real deployment: it only applies when no token arrived and SHINYHUB_IDENTITY_KEY is absent, and ShinyHub always injects that key into app processes.

Compatibility

This helper is versioned independently of the ShinyHub server: its version tracks changes to this package's API, not the server's release train. Any release verifies tokens from any ShinyHub v0.8.6 or later (the release that introduced identity forwarding); the token contract is stable across server releases. Claims a later server added (email, name) are simply "" when an older server minted the token.

Why verify, not just read the plain headers?

ShinyHub also forwards convenience plain headers (X-Shinyhub-User, -Role, -Groups, ...) and strips any client-supplied ones. But app processes listen on host-local ports, so a co-located process can bypass the proxy and forge plain headers. Anything that gates access must verify the token - which is exactly what this package does. See ShinyHub's docs/identity.md for the full trust model.

Project details


Download files

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

Source Distribution

shinyhub_identity-0.2.0.tar.gz (8.2 kB view details)

Uploaded Source

Built Distribution

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

shinyhub_identity-0.2.0-py3-none-any.whl (6.6 kB view details)

Uploaded Python 3

File details

Details for the file shinyhub_identity-0.2.0.tar.gz.

File metadata

  • Download URL: shinyhub_identity-0.2.0.tar.gz
  • Upload date:
  • Size: 8.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for shinyhub_identity-0.2.0.tar.gz
Algorithm Hash digest
SHA256 59ccfe2c549387ff5815c1eb7fb20b0523d64afd0c6d4137dc1cc9571efe61b2
MD5 5a7868f188008ff34b57314e663f9293
BLAKE2b-256 9b32b23d761250c7af59870138317ceeb6ff1b42c13dee3a81c44fe2d1ca7ab9

See more details on using hashes here.

Provenance

The following attestation bundles were made for shinyhub_identity-0.2.0.tar.gz:

Publisher: release.yml on rvben/shinyhub

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

File details

Details for the file shinyhub_identity-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for shinyhub_identity-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ee8ae14fa54e2d79700c69c1ff50624dbcad83872a8b7a96298fbf43f3e66581
MD5 5dab52635281646beffb7c2fd90ecae4
BLAKE2b-256 297d8cbd304929c2bf2dc40934199e3f735b771a0b3466cee9e8616361ffd331

See more details on using hashes here.

Provenance

The following attestation bundles were made for shinyhub_identity-0.2.0-py3-none-any.whl:

Publisher: release.yml on rvben/shinyhub

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page