Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Arize ai Phoenix Polymorphic User Vignette: Difference between revisions

From Leeroopedia
Auto-imported from implementations/Arize_ai_Phoenix_Polymorphic_User_Vignette.md
 
Sync from local file
 
Line 90: Line 90:
== Related Pages ==
== Related Pages ==


* [[Arize_ai_Phoenix_Helm_Values]] - Helm chart with authentication configuration (basic auth, LDAP, OAuth2) that reflects this pattern
* [[Implementation:Arize_ai_Phoenix_Helm_Values]] - Helm chart with authentication configuration (basic auth, LDAP, OAuth2) that reflects this pattern
* [[Arize_ai_Phoenix_Contextvars_Async_Demo]] - Another internal vignette (async context management)
* [[Implementation:Arize_ai_Phoenix_Contextvars_Async_Demo]] - Another internal vignette (async context management)
* [[Arize_ai_Phoenix_Pyproject_Config]] - Main package with SQLAlchemy and authlib dependencies
* [[Implementation:Arize_ai_Phoenix_Pyproject_Config]] - Main package with SQLAlchemy and authlib dependencies


[[Category:Implementations]]
[[Category:Implementations]]

Latest revision as of 10:32, 27 September 2026

Overview

The users.py file is an internal vignette demonstrating SQLAlchemy's Single Table Inheritance (STI) pattern for polymorphic user authentication. It models a User base class with two concrete subclasses -- LocalUser (password-based authentication) and ExternalUser (OAuth/SSO) -- all stored in a single users database table. The discriminator column auth_method determines which Python class is instantiated for each row.

This pattern directly informs the authentication architecture used in the Phoenix server, which supports both local and external (OAuth2/OIDC/LDAP) authentication methods.

Code Reference

Attribute Value
Source File internal_docs/vignettes/sqlalchemy/polymorphic_user/users.py
Lines 354
Domain Internal_Documentation, Database
Language Python
Dependencies SQLAlchemy 2.0, bcrypt

Class Hierarchy

Base (DeclarativeBase)
  +-- User (abstract, polymorphic_on="auth_method")
       +-- LocalUser (polymorphic_identity="local")
       +-- ExternalUser (polymorphic_identity="external")

Key Classes

User (Abstract Base)

Column Type Description
id int (primary key) Auto-incrementing primary key
email str (unique) User email address
auth_method AuthMethod ("local" or "external") Discriminator column with check constraint
password_hash Optional[bytes] bcrypt password hash (NULL for external users)
password_salt Optional[bytes] bcrypt salt (NULL for external users)

Table constraints:

  • auth_method IN ('local', 'external') -- ensures valid discriminator values
  • (password_hash IS NULL) = (password_salt IS NULL) -- ensures password fields are consistent (both NULL or both populated)
  • Direct instantiation of the User base class raises TypeError

LocalUser

Represents users authenticating with email and password. The __init__ method:

  1. Generates a unique bcrypt salt via bcrypt.gensalt()
  2. Hashes the password with bcrypt.hashpw(password.encode(), salt)
  3. Stores both the hash and salt as separate LargeBinary columns

Important: SQLAlchemy bypasses __init__ when loading from the database, so the password hashing only occurs during initial creation.

ExternalUser

Represents users authenticating through external identity providers (OAuth, SSO). No password is required or stored; the password_hash and password_salt columns are explicitly NULL.

Security Considerations

  • Passwords are hashed using bcrypt with a unique salt per user
  • A module-level SECRET_KEY is generated via secrets.token_urlsafe(32) for potential JWT/session use
  • Password fields are constrained at the database level to prevent inconsistent states

Usage Example

The main() function demonstrates:

  1. Creating a LocalUser with hashed password
  2. Creating an ExternalUser without password
  3. Attempting to create a base User (raises TypeError)
  4. Querying all users polymorphically (returns mixed LocalUser/ExternalUser instances)
  5. Querying specific subclasses
uv run python internal_docs/vignettes/sqlalchemy/polymorphic_user/users.py

Related Pages