Skip to main content

Add your description here

Project description

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

Project details


Release history Release notifications | RSS feed

This version

1.0.5

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.0.5.tar.gz (795.4 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.0.5-py3-none-any.whl (36.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for appkit_user-1.0.5.tar.gz
Algorithm Hash digest
SHA256 5064b36937168e763cee6156f3019c2c3d82a47dd2adb980060b7987a30412e3
MD5 01b2c21d01a2e2a4b57d5e8b516534a6
BLAKE2b-256 813684a1292fbabc189bfdc61228d61ccfec7de1e0097662666b231a86eba899

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for appkit_user-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 430f5ef6bf64bae071e01f925ed638d0d612ad495bd93b394e185a7cb441639c
MD5 b2e956e25a8c900ebd7473699514a47f
BLAKE2b-256 0a48f5d06550c5d13bdd23738cdda3f665ce70877a6f0830ab19a3bf4db0e1ab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page