Skip to main content

appkit-user

Python 3.13+ License: MIT

Enterprise user management and authentication for Reflex applications.

appkit-user provides comprehensive user authentication, authorization, and management capabilities for Reflex applications. It includes OAuth2 integration with GitHub and Azure, role-based access control (RBAC), multi-tenant user profiles, and secure session management.


✨ Features

  • OAuth2 Authentication - GitHub and Azure OAuth2 providers with PKCE support
  • Role-Based Access Control - Flexible RBAC with custom roles and permissions
  • Multi-Tenant Support - User profiles organized by tenants and projects
  • Session Management - Secure session handling with automatic cleanup
  • User Management UI - Complete admin interface for user CRUD operations
  • Authentication Decorators - Easy-to-use decorators for protecting routes and components
  • Profile Management - User profile editing with role assignment
  • Security Features - CSRF protection, secure redirects, and session validation

🚀 Installation

As Part of AppKit Workspace

If you're using the full AppKit workspace:

git clone https://github.com/jenreh/appkit.git
cd appkit
uv sync

Standalone Installation

Install from PyPI:

pip install appkit-user

Or with uv:

uv add appkit-user

Dependencies

  • greenlet>=3.2.4 (async utilities)
  • appkit-commons (shared utilities)
  • appkit-ui (UI components)
  • requests_oauthlib>=2.0.0 (OAuth2 client)

🏁 Quick Start

Basic OAuth Configuration

Configure OAuth providers in your application:

from appkit_user.configuration import GithubOAuthConfig, AzureOAuthConfig

# GitHub OAuth
github_config = GithubOAuthConfig(
    client_id="your-github-client-id",
    client_secret="secret:github-client-secret",
    redirect_url="http://localhost:3000/auth/github/callback"
)

# Azure OAuth
azure_config = AzureOAuthConfig(
    client_id="your-azure-client-id",
    client_secret="secret:azure-client-secret",
    tenant_id="your-tenant-id",
    redirect_url="http://localhost:3000/auth/azure/callback"
)

Protecting Routes

Use authentication decorators to protect your pages:

import reflex as rx
from appkit_user.authentication.components import requires_authenticated, requires_role

# Require authentication
@requires_authenticated
def protected_page():
    return rx.text("This page requires login")

# Require specific role
@requires_role("admin")
def admin_page():
    return rx.text("Admin only content")

# Require admin privileges
@requires_admin
def super_admin_page():
    return rx.text("Super admin content")

Login Integration

Add login functionality to your app:

from appkit_user.authentication.components import login_form

def login_page():
    return login_form(
        header="My App",
        logo="/img/logo.svg",
        logo_dark="/img/logo_dark.svg"
    )

📖 Usage

OAuth Configuration

GitHub OAuth

Configure GitHub OAuth application:

from appkit_user.configuration import GithubOAuthConfig

config = GithubOAuthConfig(
    client_id="gh_oauth_client_id",
    client_secret="secret:github_oauth_secret",
    redirect_url="https://myapp.com/auth/github/callback",
    scopes=["user", "user:email", "read:org"]  # Optional custom scopes
)

Azure OAuth

Configure Azure AD application:

from appkit_user.configuration import AzureOAuthConfig

config = AzureOAuthConfig(
    client_id="azure_client_id",
    client_secret="secret:azure_client_secret",
    tenant_id="tenant-id",  # or "common" for multi-tenant
    redirect_url="https://myapp.com/auth/azure/callback",
    is_public_client=False,  # Set to True for PKCE-only apps
    scopes=["openid", "profile", "email", "User.Read"]
)

Authentication Decorators

Basic Authentication

from appkit_user.authentication.components import requires_authenticated

@requires_authenticated
def dashboard():
    return rx.text("Welcome to your dashboard!")

Role-Based Access

from appkit_user.authentication.components import requires_role

@requires_role("editor")
def content_editor():
    return rx.text("Content editor interface")

@requires_role("viewer", fallback=rx.text("Access denied"))
def reports():
    return rx.text("Reports dashboard")

Admin Access

from appkit_user.authentication.components import requires_admin

@requires_admin
def admin_panel():
    return rx.text("Admin control panel")

User Management

User Table

Display and manage users:

from appkit_user.user_management.components import users_table

def user_management_page():
    return rx.vstack(
        rx.heading("User Management"),
        users_table(),
        spacing="4"
    )

User Profile

Manage user profiles and roles:

from appkit_user.user_management.components import profile_roles, profile_state

def user_profile_page():
    return rx.vstack(
        rx.heading("User Profile"),
        profile_roles(),
        spacing="4"
    )

Session Management

Access current user session:

from appkit_user.authentication.states import UserSession

def current_user_info():
    return rx.vstack(
        rx.text(f"User: {UserSession.user.email}"),
        rx.text(f"Roles: {UserSession.user.roles}"),
        rx.text(f"Tenant: {UserSession.user.tenant_id}"),
        rx.text(f"Authenticated: {UserSession.is_authenticated}")
    )

🔧 Configuration

OAuth Redirect URLs

Configure OAuth callback URLs in your Reflex app:

# In rxconfig.py or main app file
app.add_page(
    oauth_login_splash,
    route="/auth/github/callback",
    title="GitHub Login"
)

app.add_page(
    oauth_login_splash,
    route="/auth/azure/callback",
    title="Azure Login"
)

Custom OAuth Providers

Extend OAuth support for custom providers:

from appkit_user.configuration import OAuthConfig, OAuthProvider

class CustomOAuthConfig(OAuthConfig):
    provider: OAuthProvider = "custom"
    auth_url: str = "https://custom.provider.com/oauth/authorize"
    token_url: str = "https://custom.provider.com/oauth/token"
    user_url: str = "https://custom.provider.com/api/user"
    scopes: list[str] = ["read", "write"]

Multi-Tenant Setup

Configure tenant-based user isolation:

# Users are automatically scoped by tenant_id
# Access current tenant
current_tenant = UserSession.user.tenant_id

# Filter data by tenant
tenant_users = get_users_by_tenant(current_tenant)

📋 API Reference

Authentication Components

  • requires_authenticated() - Decorator for authentication-required content
  • requires_role() - Decorator for role-based access control
  • requires_admin() - Decorator for admin-only content
  • login_form() - Login form with OAuth providers
  • oauth_login_splash() - OAuth callback splash screen
  • default_fallback() - Default unauthorized access message

User Management Components

  • users_table() - User management table with CRUD operations
  • add_user_button() - Button to add new users
  • update_user_button() - Button to edit existing users
  • delete_user_button() - Button to remove users
  • user_form_fields() - Form fields for user creation/editing
  • profile_roles() - User profile role management
  • profile_state() - User profile state management

Configuration Classes

  • OAuthConfig - Base OAuth configuration
  • GithubOAuthConfig - GitHub OAuth settings
  • AzureOAuthConfig - Azure AD OAuth settings
  • OAuthProvider - Enum of supported OAuth providers

State Management

  • UserSession - Current user session state
  • LoginState - Login form state management

🔒 Security

[!IMPORTANT] Always configure HTTPS in production and use secure secrets management. OAuth client secrets should never be hardcoded.

  • OAuth2 PKCE Support - Proof Key for Code Exchange for enhanced security
  • Secure Redirects - Configurable redirect URLs prevent open redirect attacks
  • Session Security - Automatic session cleanup and validation
  • CSRF Protection - Built-in CSRF tokens for forms
  • Role Validation - Server-side role checking in addition to client-side decorators
  • Tenant Isolation - Multi-tenant data isolation prevents cross-tenant access

🤝 Integration Examples

Complete Authentication Flow

Set up a full authentication system:

import reflex as rx
from appkit_user.authentication.components import (
    login_form,
    requires_authenticated,
    oauth_login_splash
)
from appkit_user.configuration import GithubOAuthConfig

# Configure OAuth
oauth_config = GithubOAuthConfig(
    client_id="your-client-id",
    client_secret="secret:your-client-secret"
)

# Public login page
def login():
    return login_form(
        header="My App",
        logo="/img/logo.svg",
        logo_dark="/img/logo_dark.svg"
    )

# Protected dashboard
@requires_authenticated
def dashboard():
    return rx.text(f"Welcome {UserSession.user.email}!")

# OAuth callback
def github_callback():
    return oauth_login_splash(
        provider="github",
        message="Signing in with GitHub..."
    )

# Add to app
app = rx.App()
app.add_page(login, route="/login")
app.add_page(dashboard, route="/dashboard")
app.add_page(github_callback, route="/auth/github/callback")

User Management System

Create an admin user management interface:

from appkit_user.user_management.components import users_table
from appkit_user.authentication.components import requires_admin

@requires_admin
def admin_users():
    return rx.vstack(
        rx.heading("User Management", size="5"),
        rx.flex(
            users_table(),
            direction="column",
            gap="4",
            width="100%"
        ),
        padding="6",
        spacing="4"
    )

Role-Based Navigation

Dynamic navigation based on user roles:

def navigation():
    return rx.hstack(
        rx.link("Home", href="/"),
        rx.cond(
            UserSession.is_authenticated,
            rx.hstack(
                rx.link("Dashboard", href="/dashboard"),
                rx.cond(
                    UserSession.user.roles.contains("admin"),
                    rx.link("Admin", href="/admin"),
                    rx.text("")  # Empty for non-admins
                ),
                rx.button("Logout", on_click=UserSession.logout)
            ),
            rx.link("Login", href="/login")
        )
    )

📚 Related Components

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

appkit_user-1.13.7.tar.gz (850.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

appkit_user-1.13.7-py3-none-any.whl (64.6 kB view details)

Uploaded Python 3

File details

Details for the file appkit_user-1.13.7.tar.gz.

File metadata

  • Download URL: appkit_user-1.13.7.tar.gz
  • Upload date:
  • Size: 850.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for appkit_user-1.13.7.tar.gz
Algorithm Hash digest
SHA256 2b0905db778f4c2803a3b8a552a38a0e0cf7f80bf6ebcbf0a5cfb94badc26e46
MD5 192174d3afcf168de1d684f822712dc6
BLAKE2b-256 9cb2eb8c5f29002a59561feb294d9f2492b4a3ca5d1fee5bd69e962c599287e1

See more details on using hashes here.

File details

Details for the file appkit_user-1.13.7-py3-none-any.whl.

File metadata

  • Download URL: appkit_user-1.13.7-py3-none-any.whl
  • Upload date:
  • Size: 64.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for appkit_user-1.13.7-py3-none-any.whl
Algorithm Hash digest
SHA256 7131485b514d78f231fa24dcc1f5f59cf3da747b63d0849a5376df624a466d58
MD5 18fd66afe3e78281419bffb382c8822d
BLAKE2b-256 927dccb9d6f6de3d2e60ac902c856d26afe0a2a0bb78fa7f9348fb38cd88d551

See more details on using hashes here.

Release history Release notifications | RSS feed

1.14.0

2 files

This release

1.13.7 This release

2 files

1.13.6

2 files

1.13.3

2 files

1.13.2

2 files

1.13.1

2 files

1.13.0

2 files

1.12.2

2 files

1.12.1

2 files

1.12.0

2 files

1.11.3

2 files

1.11.2

2 files

1.11.1

2 files

1.11.0

2 files

1.10.2

2 files

1.10.1

2 files

1.10.0

2 files

1.9.7

2 files

1.9.6

2 files

1.9.5

2 files

1.9.4

2 files

1.9.3

2 files

1.9.2

2 files

1.9.1

2 files

1.9.0

2 files

1.8.6

2 files

1.8.5

2 files

1.8.4

2 files

1.8.3

2 files

1.8.2

2 files

1.8.1

2 files

1.8.0

2 files

1.7.0

2 files

1.6.3

2 files

1.6.2

2 files

1.6.1

2 files

1.6.0

2 files

1.5.1

2 files

1.5.0

2 files

1.4.3

2 files

1.4.2

2 files

1.4.1

2 files

1.4.0

2 files

1.3.0

2 files

1.2.6

2 files

1.2.5

2 files

1.2.4

2 files

1.2.3

2 files

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

1.1.2

2 files

1.1.1

2 files

1.1.0

2 files

1.0.5

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.17.3

2 files

0.17.2

2 files

0.17.1

2 files

0.17.0

2 files

0.16.3

2 files

0.16.2

2 files

0.16.1

2 files

0.16.0

2 files

0.15.4

2 files

0.15.3

2 files

0.15.2

2 files

0.15.1

2 files

0.15.0

2 files

0.14.1

2 files

0.14.0

2 files

0.13.1

2 files

0.13.0

2 files

0.12.1

2 files

0.12.0

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.8

2 files

0.7.7

2 files

0.7.6

2 files

0.7.5

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page