Docs

Python: Authentication

Sign app users up and in with passwords, magic links, SMS codes and providers; manage sessions, MFA, app users and roles with the Python SDK.

Updated Oct 16, 2026

Sign app users — the people who use your app — in and out of your project. After sign_in, every call from this client runs as that user, so your policies and row-level security apply.

from sovaria import create_client

async with create_client("https://<project-ref>.sovaria.in", "<anon-key>") as sovaria:
    await sovaria.sign_up("ada@example.com", "Correct-Horse-9!", "Ada")
    await sovaria.sign_in("ada@example.com", "Correct-Horse-9!")
    me = await sovaria.get_me()
    await sovaria.logout()

Methods

sovaria.ban_product_user

Toggle a product user's active state in the resolved scope.

await sovaria.ban_product_user(
    user_id: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

user_idstrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.confirm_verification_email

Confirm an email verification token.

await sovaria.confirm_verification_email(token: str) -> dict[str, Any]

Parameters

tokenstrrequired
Returns
dict[str, Any]

sovaria.console_login

Strict console-lane login for Sovaria operators.

await sovaria.console_login(email: str, password: str) -> TokenResponse

Parameters

emailstrrequired
passwordstrrequired
Returns
TokenResponse

sovaria.create_event_hook

Create event hook.

await sovaria.create_event_hook(body: dict[str, Any]) -> dict[str, Any]

Parameters

bodydict[str, Any]required
Returns
dict[str, Any]

sovaria.create_product_user

Create product user.

await sovaria.create_product_user(
    body: dict[str, Any],
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

bodydict[str, Any]required
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.delete_event_hook

Delete event hook.

await sovaria.delete_event_hook(hook_id: str) -> dict[str, Any]

Parameters

hook_idstrrequired
Returns
dict[str, Any]

sovaria.delete_product_user

Delete a product user credential in the resolved scope.

await sovaria.delete_product_user(
    user_id: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

user_idstrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.disable_mfa

Disable mfa.

await sovaria.disable_mfa(totp_code: str) -> dict[str, Any]

Parameters

totp_codestrrequired
Returns
dict[str, Any]

sovaria.disconnect_github

Disconnect github.

await sovaria.disconnect_github(*, project_id: str) -> dict[str, Any]

Parameters

project_idstrrequired
Returns
dict[str, Any]

sovaria.enroll_mfa

Enroll mfa.

await sovaria.enroll_mfa() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.fn_github_commit

Fn github commit.

await sovaria.fn_github_commit(body: dict[str, Any]) -> dict[str, Any]

Parameters

bodydict[str, Any]required
Returns
dict[str, Any]

sovaria.fn_github_import

Fn github import.

await sovaria.fn_github_import(body: dict[str, Any]) -> dict[str, Any]

Parameters

bodydict[str, Any]required
Returns
dict[str, Any]

sovaria.fn_list_github_repos

Fn list github repos.

await sovaria.fn_list_github_repos(
    *, token: str | None = None,
    limit: int = 40,
) -> dict[str, Any]

Parameters

tokenstr | Noneoptionaldefault None
limitintoptionaldefault 40
Returns
dict[str, Any]

sovaria.get_github_connection_state

Get github connection state.

await sovaria.get_github_connection_state(
    *, project_id: str,
) -> dict[str, Any]

Parameters

project_idstrrequired
Returns
dict[str, Any]

sovaria.get_me

Return the authenticated user's profile (user_id, email, roles).

await sovaria.get_me() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.get_mfa_status

Get mfa status.

await sovaria.get_mfa_status() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.get_product_user_roles

Return a product user's app roles in the resolved scope.

await sovaria.get_product_user_roles(
    user_id: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

user_idstrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.get_providers_config

Get providers config.

await sovaria.get_providers_config() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.get_sessions_config

Get sessions config.

await sovaria.get_sessions_config() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.list_console_product_users

List console product users.

await sovaria.list_console_product_users() -> list[dict[str, Any]]
Returns
list[dict[str, Any]]

sovaria.list_event_hooks

List event hooks.

await sovaria.list_event_hooks() -> list[dict[str, Any]]
Returns
list[dict[str, Any]]

sovaria.list_product_users

Every project/product user in the resolved org/project scope (follows the API's pages). For large projects prefer list_product_users_page and page with next_cursor.

await sovaria.list_product_users(
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> list[dict[str, Any]]

Parameters

org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
list[dict[str, Any]]

sovaria.list_product_users_page

One page of product users, newest first: {"users", "next_cursor", "total"}. search matches part of an email or an exact user id; status is active or banned.

await sovaria.list_product_users_page(
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
    limit: int = 50,
    cursor: str | None = None,
    search: str | None = None,
    status: str | None = None,
) -> dict[str, Any]

total (for the filter) comes with the first page.

Parameters

org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
limitintoptionaldefault 50
Page size.
cursorstr | Noneoptionaldefault None
next_cursor from the previous page.
searchstr | Noneoptionaldefault None
Part of an email or name.
statusstr | Noneoptionaldefault None
Returns
dict[str, Any]
cursor = None
while True:
    page = await sovaria.list_product_users_page(limit=100, cursor=cursor)
    for user in page["users"]:
        print(user["email"])
    cursor = page.get("next_cursor")
    if not cursor:
        break

sovaria.list_sessions

List sessions.

await sovaria.list_sessions() -> list[dict[str, Any]]
Returns
list[dict[str, Any]]

sovaria.login

Deprecated compatibility login. Unscoped calls post to POST /api/v1/auth/console/login.

await sovaria.login(email: str, password: str) -> TokenResponse

When set_scope(org_id, project_id) has been called, posts to POST /api/v1/auth/project/login. Prefer console_login() or project_login() in new code.

Parameters

emailstrrequired
passwordstrrequired
Returns
TokenResponse

sovaria.login_console

Alias for console_login(), matching TypeScript lane terminology.

await sovaria.login_console(email: str, password: str) -> TokenResponse

Parameters

emailstrrequired
passwordstrrequired
Returns
TokenResponse

sovaria.login_product

Alias for project_login(), matching TypeScript lane terminology.

await sovaria.login_product(
    email: str,
    password: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> TokenResponse

Parameters

emailstrrequired
passwordstrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
TokenResponse

sovaria.logout

Revoke the active refresh token server-side, then clear in-memory tokens. Sends Authorization: Bearer plus {"refresh_token": ...}.

await sovaria.logout() -> None

Non-2xx responses are treated as failure. Local session state (tokens + KEK) is always cleared, including when the HTTP call fails.

Returns
None

sovaria.oauth_handoff

Exchange an OAuth handoff token for a session. Passwordless: session KEK is not derived unless password is supplied and the response includes argon2_salt.

await sovaria.oauth_handoff(
    token: str,
    password: str | None = None,
) -> TokenResponse

Parameters

tokenstrrequired
passwordstr | Noneoptionaldefault None
Returns
TokenResponse

sovaria.product_users_list

Alias for list_product_users(), matching TypeScript productUsers.list().

await sovaria.product_users_list(**kwargs) -> list[dict[str, Any]]
Returns
list[dict[str, Any]]

sovaria.product_users_set_roles

Alias for replace_product_user_roles(), matching TypeScript productUsers.setRoles().

await sovaria.product_users_set_roles(
    user_id: str,
    roles: list[str],
    **kwargs,
) -> dict[str, Any]

Parameters

user_idstrrequired
The app user's id.
roleslist[str]required
App roles, e.g. ["librarian"] (policies use app:<role>).
Returns
dict[str, Any]

sovaria.project_login

Strict project-lane login for product end-users.

await sovaria.project_login(
    email: str,
    password: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> TokenResponse

Parameters

emailstrrequired
passwordstrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
TokenResponse

sovaria.register

Create an app user in a project (or, with no project scope at all, a Sovaria console account). The project comes from org_id/project_id or the client's scope (set_scope).

await sovaria.register(
    email: str,
    password: str,
    name: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> TokenResponse

Without either, the account created is a console account — app code should always pass a scope. Registration may not return tokens when the project requires email verification.

Parameters

emailstrrequired
passwordstrrequired
namestrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
TokenResponse

sovaria.replace_product_user_roles

Replace a product user's app roles in the resolved scope.

await sovaria.replace_product_user_roles(
    user_id: str,
    roles: list[str],
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

user_idstrrequired
roleslist[str]required
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.revoke_other_sessions

Revoke other sessions.

await sovaria.revoke_other_sessions() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.revoke_session

Revoke session.

await sovaria.revoke_session(session_id: str) -> dict[str, Any]

Parameters

session_idstrrequired
Returns
dict[str, Any]

sovaria.send_otp

Send an SMS OTP code for phone-based login.

await sovaria.send_otp(
    phone: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
) -> dict[str, Any]

Parameters

phonestrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
Returns
dict[str, Any]

sovaria.send_verification_email

Trigger a verification email for the authenticated user.

await sovaria.send_verification_email() -> dict[str, Any]
Returns
dict[str, Any]

sovaria.sign_in

Sign an app user in with email and password (same as project_login).

await sovaria.sign_in(email: str, password: str) -> TokenResponse

Parameters

emailstrrequired
The user's email.
passwordstrrequired
Their password.
Returns
TokenResponse
try:
    await sovaria.sign_in(email, password)
except SovariaError as err:
    if err.status_code == 401:
        print("Wrong email or password")
    else:
        raise

sovaria.sign_up

Create an app user and sign them in (unless the project requires email confirmation).

await sovaria.sign_up(
    email: str,
    password: str,
    name: str = '',
) -> TokenResponse

Parameters

emailstrrequired
The user's email.
passwordstrrequired
Must meet the project's password rules.
namestroptionaldefault ''
Display name.
Returns
TokenResponse
  • 403 SIGNUP_DISABLED when new sign-ups are off.

sovaria.update_providers_config

Update providers config.

await sovaria.update_providers_config(
    body: dict[str, Any],
) -> dict[str, Any]

Parameters

bodydict[str, Any]required
Returns
dict[str, Any]

sovaria.update_sessions_config

Update sessions config.

await sovaria.update_sessions_config(
    body: dict[str, Any],
) -> dict[str, Any]

Parameters

bodydict[str, Any]required
Returns
dict[str, Any]

sovaria.verify_mfa

Complete MFA using a pre-MFA challenge token from login.

await sovaria.verify_mfa(
    code: str,
    *, method: str = 'totp',
) -> TokenResponse

Parameters

codestrrequired
methodstroptionaldefault 'totp'
Returns
TokenResponse

sovaria.verify_otp

Verify an SMS OTP code and establish a session. Passwordless by default: pass password when argon2_salt is present if you need session-cached E2EE without a follow-up login.

await sovaria.verify_otp(
    phone: str,
    code: str,
    *, org_id: str | None = None,
    project_id: str | None = None,
    env_id: str | None = None,
    password: str | None = None,
) -> TokenResponse

Parameters

phonestrrequired
codestrrequired
org_idstr | Noneoptionaldefault None
project_idstr | Noneoptionaldefault None
env_idstr | Noneoptionaldefault None
passwordstr | Noneoptionaldefault None
Returns
TokenResponse
Something unclear or missing on this page?Tell us