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.

  1. Install the package

    Bash
    1pip install neuctra-authix
    2
    3# or, with the tool you actually use
    4poetry add neuctra-authix
    5uv add neuctra-authix
    6pipenv install neuctra-authix

    Requires Python 3.8 or newer. The only runtime dependency is requests.

  2. 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.

  3. Put the keys in the environment

    Bash
    1# .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.

  4. Construct the client

    Python
    1import 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.

  5. Verify it works

    Python
    1# 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

ParamTypeRequiredDescription
app_idstrYesThe app these calls belong to. Every request carries it.
secret_keystrNosk_live_… — full account authority. Server-side only. Pass this or publishable_key, not both.
publishable_keystrNopk_live_… — end-user auth and the signed-in user's own records.
base_urlstrNoAPI origin. Override only when pointing at a different deployment.
app_namestrNoOptional label sent with requests; useful when one account serves several services.
timeoutfloatNoPer-request timeout in seconds. Set one — the default is generous for a web request.
sessionrequests.SessionNoBring 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.

Python
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

Python
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

Python
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

Python
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