Auth & user management

Every method for creating an end user, signing them in, verifying their email, resetting their password, and reading or deleting their account. All arguments are keyword-only.

The session lives on the client

login_user() stores a cookie on the client's requests.Session, and every later call on that client acts as that user. In a script that is exactly what you want. In a web server it is a serious bug: one shared client would hand the first visitor's session to the next.

In a web application, either construct a short-lived publishable client per request, or use a secret-key client and pass user_id explicitly.

signup_userSession cookie

POST /api/users/signup

authix.signup_user(
    *, name: str, email: str, password: str,
    username: str | None = None,
    phone: str | None = None,
    address: str | None = None,
) -> dict
ParamTypeRequiredDescription
namestrYesDisplay name.
emailstrYesUnique within this app. The same address can exist in another app.
passwordstrYesSent over HTTPS and stored as a bcrypt hash. Never stored in plaintext.
usernamestrNoOptional handle, usable with get_user().
phonestrNoOptional.
addressstrNoOptional.

Returns: dict — the created user

Python
1user = authix.signup_user(
2    name="Ada Lovelace",
3    email="[email protected]",
4    password="a-long-passphrase",
5)
6
7print(user["user"]["id"])

Throws: ValidationError on a malformed payload; AuthixAPIError (409) if the email already exists in this app.

Signing up does not verify the email. Call request_email_verification_otp() next if your app requires a verified address.

login_userSession cookie

POST /api/users/login

authix.login_user(*, email: str, password: str) -> dict
ParamTypeRequiredDescription
emailstrYesThe user's email.
passwordstrYesTheir password.

Returns: dict — the signed-in user

Python
1result = authix.login_user(email="[email protected]", password="…")
2
3# The cookie is now on this client. Subsequent calls act as Ada.
4print(result["user"]["id"])

Throws: AuthenticationError (401) on a wrong password or unknown email — deliberately indistinguishable, so the response cannot be used to enumerate accounts.

logout_userSession cookie

POST /api/users/logout

authix.logout_user() -> dict

Returns: dict

Python
1authix.logout_user()
2
3authix.check_user_session()
4# {"authenticated": False}

Clears the cookie both server-side and on the local session, so the client is genuinely signed out rather than merely appearing to be.

check_user_sessionSession cookie

GET /api/users/session

authix.check_user_session() -> dict

Returns: dict — {"authenticated": bool, "user": dict | None}

Python
1session = authix.check_user_session()
2
3if session["authenticated"]:
4    print(session["user"]["email"])
5else:
6    prompt_login()

Never raises for a missing or expired session — the server answers 200 with authenticated: False, because 'not signed in' is an answer rather than a failure. Safe to call on every request without a try/except.

change_passwordSession cookie

POST /api/users/change-password

authix.change_password(
    *, user_id: str, current_password: str, new_password: str,
) -> dict
ParamTypeRequiredDescription
user_idstrYesWhose password to change.
current_passwordstrYesVerified before the change is applied.
new_passwordstrYesThe replacement.

Returns: dict

Python
1authix.change_password(
2    user_id=user_id,
3    current_password=old,
4    new_password=new,
5)
6# Every session for this user is now invalid, including this one.

Throws: AuthenticationError (401) if current_password is wrong.

Bumps the user's token version, which invalidates every session they have anywhere. The device that made the change must sign in again too — that is the correct trade, because it is also what stops a stolen session surviving a password change.

request_email_verification_otpSession cookie

POST /api/users/request-verification

authix.request_email_verification_otp(*, user_id: str, email: str) -> dict
ParamTypeRequiredDescription
user_idstrYesThe user to verify.
emailstrYesWhere to send the code.

Returns: dict

Python
1authix.request_email_verification_otp(user_id=user_id, email=email)

The code is stored hashed and expires shortly after it is issued.

verify_emailSession cookie

POST /api/users/verify-email

authix.verify_email(*, email: str, otp: str) -> dict
ParamTypeRequiredDescription
emailstrYesThe address being confirmed.
otpstrYesThe code from the email.

Returns: dict

Python
1authix.verify_email(email=email, otp=code)

Throws: ValidationError (400) if the code is wrong or has expired.

request_reset_user_password_otpSession cookie

POST /api/users/request-password-reset

authix.request_reset_user_password_otp(*, email: str) -> dict
ParamTypeRequiredDescription
emailstrYesWhere to send the reset code.

Returns: dict

Python
1authix.request_reset_user_password_otp(email="[email protected]")

Succeeds whether or not the address exists, so the response cannot be used to discover which emails are registered. Show the same confirmation either way.

reset_user_passwordSession cookie

POST /api/users/reset-password

authix.reset_user_password(
    *, email: str, otp: str, new_password: str,
) -> dict
ParamTypeRequiredDescription
emailstrYesThe account being reset.
otpstrYesThe emailed code.
new_passwordstrYesThe new password.

Returns: dict

Python
1authix.reset_user_password(
2    email=email,
3    otp=code,
4    new_password=new_password,
5)

Throws: ValidationError (400) if the code is wrong or expired.

Also invalidates every existing session for that user — which is the point, since a reset usually means the account may have been compromised.

get_user_profileSession cookie

GET /api/users/:id/profile

authix.get_user_profile(*, user_id: str) -> dict
ParamTypeRequiredDescription
user_idstrYesWhose profile to read.

Returns: dict

Python
1profile = authix.get_user_profile(user_id=user_id)

With a publishable key the server pins this to the signed-in user, so passing someone else's id returns their own record rather than the other person's.

get_userAPI key only

GET /api/users/lookup

authix.get_user(
    *, id: str | None = None, username: str | None = None,
) -> dict
ParamTypeRequiredDescription
idstrNoLook up by id. Pass this or username.
usernamestrNoLook up by handle.

Returns: dict

Python
1user = authix.get_user(username="ada")

Throws: InsufficientScopeError (403) with a publishable key; NotFoundError (404) if no such user exists in this app.

Requires a secret key — it can read any user on the account.

update_userSession cookie

PUT /api/users/:id

authix.update_user(*, user_id: str, **fields) -> dict
ParamTypeRequiredDescription
user_idstrYesWho to update.
**fieldsAnyYesProfile fields to change: name, username, phone, address, avatar_url.

Returns: dict

Python
1authix.update_user(user_id=user_id, name="Ada L.", phone="+44…")

Profile fields only. Passwords go through change_password, and email changes go through the verification flow.

delete_userSession cookie

DELETE /api/users/:id

authix.delete_user(*, user_id: str) -> dict
ParamTypeRequiredDescription
user_idstrYesWho to delete.

Returns: dict

Python
1authix.delete_user(user_id=user_id)

Throws: NotFoundError (404) if the user does not exist in this app.

Deletes the user and every record they own, permanently. There is no recycle bin and no undo — export first if the data matters.

check_if_user_existsAPI key only

GET /api/users/:id/exists

authix.check_if_user_exists(user_id: str) -> dict
ParamTypeRequiredDescription
user_idstrYesPositional, unlike the rest of the SDK.

Returns: dict

Python
1if authix.check_if_user_exists(user_id)["exists"]:
2    ...

Throws: InsufficientScopeError (403) with a publishable key.

The one method taking a positional argument. Requires a secret key.

Do not build your own authorisation on these

A successful check_user_session() tells you who someone is. It does not tell you what they may do. Ownership is enforced by the API on every request, and your own rules — which screens, which records, which actions — belong in your code.

Related