Stackure Python SDK
Passwordless magic-link authentication SDK for Python — drop-in ASGI and WSGI middleware, zero dependencies.
Protect an app with one line, or verify sessions and send magic links directly against the Stackure auth API.
Install
pip install stackure
Requires Python 3.14+.
Protect an app
import stackure
app_id = "7f3c1a2e-9b4d-4e6f-8a1b-2c3d4e5f6071" # your app's UUID in Stackure
# ASGI — FastAPI, Starlette, Quart
app = stackure.auth(app_id, "can_approve_invoice")(app)
# WSGI — Flask, Django
flask_app.wsgi_app = stackure.auth(app_id, "can_approve_invoice")(flask_app.wsgi_app)
The same wrapper handles both; it detects the protocol it was called under.
Access the authenticated user in your view:
user = stackure.user_from_request(request)
print(user.user_email, user.user_permissions)
- API requests get JSON errors
- Browser requests get redirected to sign-in
- The sign-in handoff is automatic: Stackure hands the browser back with a
session_token, the middleware stores it as a cookie on your domain and strips it from the URL
Requirements
Stackure binds sessions to the browser's user agent and IP. The SDK validates
from your server, so it forwards the original User-Agent and
X-Forwarded-For. Your app must see the real client IP — if it runs behind a
proxy or CDN, make sure that layer sets X-Forwarded-For.
Every request is validated against Stackure, so revocation is immediate.
Verify manually
result = stackure.verify(app_id, request)
if not result.authenticated:
# result.error.code, result.error.message, result.error.sign_in_url
...
# result.user
verify never raises — transport and API failures come back as a 500 result.
It accepts a WSGI environ, an ASGI scope, or a framework request object
(Starlette, FastAPI, Flask, Django).
Send a magic link
resp = stackure.send_magic_link("user@example.com", app_id)
# resp.message
Log out
r = stackure.logout(request)
Returns the status and headers that clear the app's cookie and redirect to Stackure's sign-out. Your framework builds the response:
# Flask
return "", r.status, r.headers
# Starlette / FastAPI
return Response(status_code=r.status, headers=dict(r.headers))
Configuration
Set STACKURE_BASE_URL to point at a non-production environment:
STACKURE_BASE_URL=https://stage.stackure.com python app.py
Retry-on-5xx (one retry after 500ms) and the 2-second request timeout are hard-coded. Timeouts are never retried.
Errors
Everything except verify raises StackureError. Switch on .code:
from stackure import StackureError
try:
stackure.send_magic_link(email)
except StackureError as err:
match err.code:
case "validation": ... # bad input
case "auth": ... # 401 from the API
case "forbidden": ... # 403 from the API
case "timeout": ... # request exceeded the 2s timeout
case "network": ... # everything else
Contributing
Open a PR. Tag a release when ready: git tag vX.Y.Z && git push --tags — the release workflow builds, signs, and publishes.
Security
Report vulnerabilities via GitHub Security Advisories. Releases publish to PyPI via OIDC trusted publishing with GitHub build-provenance attestations.
License
MIT
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 stackure-1.20260906.7.tar.gz.
File metadata
- Download URL: stackure-1.20260906.7.tar.gz
- Upload date:
- Size: 12.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
615efa255e8f02e1e2719ae97261a4fcc7bdabec87dd37e9ce1b4dbfccc53861
|
|
| MD5 |
2a6c964fe759451c91671b6ead869eb1
|
|
| BLAKE2b-256 |
10e260b72557a4b35a358e9d5ab27bb947a9fe8e41c4422c7494d372e94e7ae0
|
Provenance
The following attestation bundles were made for stackure-1.20260906.7.tar.gz:
Publisher:
release.yml on syi-stackure/sdk-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stackure-1.20260906.7.tar.gz -
Subject digest:
615efa255e8f02e1e2719ae97261a4fcc7bdabec87dd37e9ce1b4dbfccc53861 - Sigstore transparency entry: 2741617280
- Sigstore integration time:
-
Permalink:
syi-stackure/sdk-py@aa661b3a186976559ef880649a439fff6017a72d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/syi-stackure
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@aa661b3a186976559ef880649a439fff6017a72d -
Trigger Event:
push
-
Statement type:
File details
Details for the file stackure-1.20260906.7-py3-none-any.whl.
File metadata
- Download URL: stackure-1.20260906.7-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8643b0f7983235b97cfb89e63cd68ab3b39fbf691e3b6daeb197052eac0a141
|
|
| MD5 |
ef6ab7e68e40ce1934f80dd68eceed65
|
|
| BLAKE2b-256 |
eb610f501fb3e72629a8211b031c04835b878169dc2a6ed8ecace0c3ec61fa2e
|
Provenance
The following attestation bundles were made for stackure-1.20260906.7-py3-none-any.whl:
Publisher:
release.yml on syi-stackure/sdk-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stackure-1.20260906.7-py3-none-any.whl -
Subject digest:
e8643b0f7983235b97cfb89e63cd68ab3b39fbf691e3b6daeb197052eac0a141 - Sigstore transparency entry: 2741617389
- Sigstore integration time:
-
Permalink:
syi-stackure/sdk-py@aa661b3a186976559ef880649a439fff6017a72d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/syi-stackure
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@aa661b3a186976559ef880649a439fff6017a72d -
Trigger Event:
push
-
Statement type: