Install the Python SDK
Install the package, hold your keys in the environment, build one client and reuse it. Five minutes, and the last two steps are the ones that matter later.
Install the package
Bash1pip install neuctra-authix 2 3# or, with the tool you actually use 4poetry add neuctra-authix 5uv add neuctra-authix 6pipenv install neuctra-authixRequires Python 3.8 or newer. The only runtime dependency is
requests.Create an app and issue a key
In the dashboard, create an app and copy its app id, then issue a key from the API Keys page. The key is shown once — it is stored only as a hash, so neither you nor we can retrieve it afterwards. Lose it and you issue a new one.
Put the keys in the environment
Bash1# .env — never commit this file 2AUTHIX_APP_ID=cmsq8f2k10001na9x... 3AUTHIX_SECRET_KEY=sk_live_a1b2c3d4_... 4 5# Only if this process authenticates end users on their behalf: 6# AUTHIX_PUBLISHABLE_KEY=pk_live_a1b2c3d4_...Keys in source control are the most common way secrets leak. If one reaches a commit, revoke it in the dashboard — rewriting history is not enough, because the value is already in every clone.
Construct the client
Python1import os 2from neuctra_authix import Authix 3 4authix = Authix( 5 app_id=os.environ["AUTHIX_APP_ID"], 6 secret_key=os.environ["AUTHIX_SECRET_KEY"], 7)Both arguments are keyword-only. Pass exactly one credential; passing both raises
ConfigurationError.Verify it works
Python1# Confirms the key, the app id and the network path in one call. 2print(authix.key_type) # "secret" or "publishable" 3print(authix.key_prefix) # "sk_live_a1b2c3d4" — safe to log 4 5page = authix.get_all_users_from_app(limit=1) 6print(f"reachable, {len(page)} user(s) returned")
Constructor arguments
| Param | Type | Required | Description |
|---|---|---|---|
| app_id | str | Yes | The app these calls belong to. Every request carries it. |
| secret_key | str | No | sk_live_… — full account authority. Server-side only. Pass this or publishable_key, not both. |
| publishable_key | str | No | pk_live_… — end-user auth and the signed-in user's own records. |
| base_url | str | No | API origin. Override only when pointing at a different deployment. |
| app_name | str | No | Optional label sent with requests; useful when one account serves several services. |
| timeout | float | No | Per-request timeout in seconds. Set one — the default is generous for a web request. |
| session | requests.Session | No | Bring your own session to configure retries, proxies or TLS. |
Acting as an end user
A publishable-key client can sign someone in and then act as them. The session cookie lives on the client's requests.Session, so no user id is needed afterwards — the server resolves it.
1# A client that acts as an end user instead of as the account owner.
2authix = Authix(
3 app_id=os.environ["AUTHIX_APP_ID"],
4 publishable_key=os.environ["AUTHIX_PUBLISHABLE_KEY"],
5)
6
7authix.login_user(email="[email protected]", password="…")
8
9# The cookie from that login lives on the client's requests.Session,
10# so this call is scoped to Ada and no user id is needed.
11session = authix.check_user_session()One client per signed-in user
Because the cookie is stored on the client, a client shared across a web server's requests would serve one user's session to the next visitor. In a web application, either build a short-lived publishable client per request, or use a secret-key client and pass the user id explicitly.
Key mistakes caught at startup
1# Passing the wrong kind of key fails at construction, before any
2# request is sent — so the mistake surfaces at startup, not as a
3# confusing 403 in production.
4Authix(app_id=APP_ID, publishable_key="sk_live_…")
5# ConfigurationError: A secret key (sk_…) was passed as publishable_key.
6# Secret keys carry full account authority and must never be exposed.
7
8Authix(app_id=APP_ID, secret_key="pk_live_…")
9# ConfigurationError: A publishable key (pk_…) was passed as secret_key.The key is parsed locally before anything is sent, so a swapped key raises immediately with a message naming the actual problem — rather than working with more privilege than you intended, which is the failure mode that matters.
One client per process
1# authix_client.py — build once, import everywhere.
2import os
3from functools import lru_cache
4from neuctra_authix import Authix
5
6
7@lru_cache(maxsize=1)
8def get_authix() -> Authix:
9 """One client per process.
10
11 The client owns a requests.Session and therefore a connection pool;
12 constructing a new one per request throws that away and adds a TLS
13 handshake to every call.
14 """
15 return Authix(
16 app_id=os.environ["AUTHIX_APP_ID"],
17 secret_key=os.environ["AUTHIX_SECRET_KEY"],
18 )Timeouts and retries
1authix = Authix(
2 app_id=APP_ID,
3 secret_key=SECRET_KEY,
4 timeout=10.0, # seconds; applies to every request
5)
6
7# Bring your own session to add retries, proxies or custom TLS.
8import requests
9from requests.adapters import HTTPAdapter
10from urllib3.util.retry import Retry
11
12session = requests.Session()
13session.mount(
14 "https://",
15 HTTPAdapter(
16 max_retries=Retry(
17 total=3,
18 backoff_factor=0.5,
19 # Only idempotent methods. A retried POST can create twice.
20 allowed_methods={"GET"},
21 status_forcelist=(502, 503, 504),
22 )
23 ),
24)
25
26authix = Authix(app_id=APP_ID, secret_key=SECRET_KEY, session=session)Never blanket-retry writes
A create that timed out may well have succeeded, with only the response lost. Retrying it produces two records. Restrict automatic retries to GET, and handle write failures where you can decide what the right answer is.
Keys never appear in logs
repr(authix) and authix.key_prefix expose only the non-secret lookup handle, e.g. sk_live_a1b2c3d4. Use mask_key() if you need to display a key you hold elsewhere.
Related