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

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.3.0.tar.gz (796.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.3.0-py3-none-any.whl (38.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: appkit_user-1.3.0.tar.gz
  • Upload date:
  • Size: 796.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","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.3.0.tar.gz
Algorithm Hash digest
SHA256 5efdfea9d7ad20896fa9e96291aeb16736eaf221ea7e643ffe0ae96a109a587b
MD5 52a59cb5ef675396b9b589c72d77c21d
BLAKE2b-256 56967b0449489837c888c800d0593c6a9243dfcbd73fcc302d92b772cbcc1249

See more details on using hashes here.

File details

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

File metadata

  • Download URL: appkit_user-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 38.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 20428297d4c569ce28a8f076f61e429fe7c87701d6a9c12286539af159ce0927
MD5 3483d10ae7f5a0c0644de54ba24bb7c9
BLAKE2b-256 42876de170a21ed28b08cfdd816188958a742fdebcc0530e049fdb9e2f58d4f8

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