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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59ccfe2c549387ff5815c1eb7fb20b0523d64afd0c6d4137dc1cc9571efe61b2
|
|
| MD5 |
5a7868f188008ff34b57314e663f9293
|
|
| BLAKE2b-256 |
9b32b23d761250c7af59870138317ceeb6ff1b42c13dee3a81c44fe2d1ca7ab9
|
Provenance
The following attestation bundles were made for shinyhub_identity-0.2.0.tar.gz:
Publisher:
release.yml on rvben/shinyhub
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shinyhub_identity-0.2.0.tar.gz -
Subject digest:
59ccfe2c549387ff5815c1eb7fb20b0523d64afd0c6d4137dc1cc9571efe61b2 - Sigstore transparency entry: 2138082866
- Sigstore integration time:
-
Permalink:
rvben/shinyhub@c2d122461c337d78cd28c53e27894bac9e7ed997 -
Branch / Tag:
refs/tags/v0.10.7 - Owner: https://github.com/rvben
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c2d122461c337d78cd28c53e27894bac9e7ed997 -
Trigger Event:
push
-
Statement type:
File details
Details for the file shinyhub_identity-0.2.0-py3-none-any.whl.
File metadata
- Download URL: shinyhub_identity-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee8ae14fa54e2d79700c69c1ff50624dbcad83872a8b7a96298fbf43f3e66581
|
|
| MD5 |
5dab52635281646beffb7c2fd90ecae4
|
|
| BLAKE2b-256 |
297d8cbd304929c2bf2dc40934199e3f735b771a0b3466cee9e8616361ffd331
|
Provenance
The following attestation bundles were made for shinyhub_identity-0.2.0-py3-none-any.whl:
Publisher:
release.yml on rvben/shinyhub
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shinyhub_identity-0.2.0-py3-none-any.whl -
Subject digest:
ee8ae14fa54e2d79700c69c1ff50624dbcad83872a8b7a96298fbf43f3e66581 - Sigstore transparency entry: 2138082873
- Sigstore integration time:
-
Permalink:
rvben/shinyhub@c2d122461c337d78cd28c53e27894bac9e7ed997 -
Branch / Tag:
refs/tags/v0.10.7 - Owner: https://github.com/rvben
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c2d122461c337d78cd28c53e27894bac9e7ed997 -
Trigger Event:
push
-
Statement type: