Skip to content
meldry-comPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

186 Commits

Folders and files

Repository files navigation

Pasion

An identity, notification, operations, and integration platform for Palpo Matrix homeservers.

Overview

Pasion is a comprehensive user operations platform built for Palpo. While it implements OAuth 2.0 and OpenID Connect for standards-based authentication (MSC3861), Pasion goes well beyond a conventional auth service. It provides a workflow engine for managing user lifecycle operations, a unified notification center for multi-channel dispatch, a connector platform for external system integration, and a dual policy engine for fine-grained access control.

Key Features

  • Workflow Engine — Registration, recovery, and verification flows managed as state machines with step tracking, deadlines, retry logic, and audit snapshots
  • Unified Notification Center — Email + SMS dispatch with provider abstraction (SMTP, Sendmail, Resend, SendGrid, Twilio SendGrid, Brevo, AWS SES for email; Twilio, Aliyun SMS, and Tencent Cloud SMS for messaging)
  • Connector Platform — Pluggable external system integration: Palpo Matrix homeserver provisioning and upstream OAuth 2.0 identity provider federation
  • Chinese Ecosystem SSO — Native support for QQ, WeChat, WeCom, Feishu, Lark, and DingTalk with their non-standard OAuth2 flows
  • Cedar + OPA Policy Engine — Dual policy backend: Amazon Cedar policies evaluated natively in Rust, OPA/Rego compiled to WebAssembly, or remote HTTP delegation
  • Dioxus Frontend — Full-Rust SPA built with Dioxus (no TypeScript or React)
  • Admin Operational API — User management, session oversight, OAuth 2.0 client administration, upstream provider management, and policy data control
  • Multi-Channel Verification — Email and SMS verification codes with configurable templates, language selection, and background job dispatch
  • OAuth 2.0 & OpenID Connect — Full OIDC Provider with authorization code, client credentials, and device code grant flows
  • Security — Argon2id password hashing, encrypted cookies, rate limiting, CAPTCHA support
  • Observability — OpenTelemetry tracing and Prometheus metrics export
  • Internationalization — Multi-language UI with configurable templates

Credential rotation policy

Every secret-bearing field in config.dev.yaml, sample configs, and the documentation is a placeholder that must be replaced before any non-local use. If a real secret slipped into a commit, container, or issue attachment, treat it as compromised and rotate it:

  • Encryption / signing keys (secrets.encryption, secrets.keys[]) → regenerate with openssl rand -hex 32 and openssl genpkey / openssl ecparam. Reference them via key_file: rather than inline key: blocks for production.
  • SMTP credentials (email.provider.password) → revoke and reissue (for Gmail App Passwords see https://myaccount.google.com/apppasswords).
  • Matrix shared secret (matrix.secret) → openssl rand -base64 24 and update the homeserver to match.
  • Upstream OAuth client secrets (upstream_oauth2.providers[].client_secret) → regenerate at the provider console.

Quick Start

1. Install

Pre-built Binaries (Linux)

curl -sL https://github.com/taidge/pasion/releases/latest/download/pasion-x86_64-linux.tar.gz | tar xz
mv pasion /usr/local/bin/

Docker

docker pull ghcr.io/taidge/pasion:latest

From Source

git clone https://github.com/taidge/pasion.git
cd pasion
# Build the WebAssembly frontend with the Dioxus CLI (cargo install dioxus-cli@0.7.5).
dx build -p pasion-frontend --release
# Then build the server binary.
cargo build --release --bin pasion --no-default-features --features docker,cedar

2. Prepare Database

CREATE USER pasion WITH PASSWORD 'your_password';
CREATE DATABASE pasion WITH OWNER pasion;

3. Generate and Edit Configuration

pasion config generate > config.yaml
# Edit config.yaml — see Configuration section below

4. Start the Server

pasion server -c config.yaml

This single command will automatically run database migrations, start the HTTP server, and launch the background task worker.

Configuration

Pasion uses a YAML configuration file. Key sections:

# Public-facing URL
http:
  public_base: https://auth.example.com/
  listeners:
    - name: web
      binds:
        - address: "[::]:8080"
      resources:
        - name: discovery     # OIDC discovery endpoints
        - name: human         # Login / registration UI
        - name: oauth         # OAuth 2.0 endpoints
        - name: health        # Health check
        - name: assets        # Static frontend assets

# Database connection
database:
  uri: postgresql://pasion:password@localhost/pasion

# Matrix homeserver integration
matrix:
  homeserver: matrix.example.com
  secret: "shared-secret-with-homeserver"
  endpoint: "https://matrix.example.com"

# Encryption and signing keys
secrets:
  encryption: "base64-encoded-32-byte-key"
  keys:
    - kid: "key-id-1"
      key: |
        -----BEGIN RSA PRIVATE KEY-----
        ...
        -----END RSA PRIVATE KEY-----

# Password authentication
passwords:
  enabled: true
  schemes:
    - version: 1
      algorithm: argon2id

# Upstream SSO providers (optional)
upstream_oauth2:
  providers:
    - id: "01HFRQFT5QFBM3Y5BHNFHMP6M0"
      issuer: "https://accounts.google.com"
      client_id: "your-client-id"
      client_secret: "your-client-secret"
      token_endpoint_auth_method: client_secret_post
      scope: "openid email profile"

# Email (optional, for verification and recovery)
email:
  from: '"Pasion" <noreply@example.com>'
  provider:
    type: resend
    api_key: "re_xxxxxxxxx"
    # Supported types: smtp, sendmail, resend, sendgrid, twilio, brevo, aws_ses, http_webhook

# SMS (optional, for phone verification and messaging)
sms:
  provider:
    type: twilio
    account_sid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    auth_token: "your-auth-token"
    from_number: "+12065550123"

See the full configuration reference for all options.

When registering a Google / GitHub / other upstream OAuth app, the callback URL is always derived from http.public_base:

<http.public_base>/upstream/callback/<provider-id>

For example, if http.public_base is https://auth.example.com/pasion/, the callback for provider 01JABCDEF0123456789ABCDEFG is https://auth.example.com/pasion/upstream/callback/01JABCDEF0123456789ABCDEFG.

Architecture

Pasion is deployed alongside a Palpo Matrix homeserver behind a reverse proxy. Internally, HTTP requests flow through handler layers into workflow services, which coordinate across storage repositories, external connectors (Palpo Matrix, upstream OAuth 2.0 providers), and the notification center (email/SMS). The policy engine evaluates access decisions at each control point.

              ┌───────────────┐
 Users ──────>│ Reverse Proxy │ (TLS termination)
              └───────┬───────┘
                      │
         ┌────────────┼────────────┐
         │            │            │
    ┌────▼────┐  ┌────▼─────┐  ┌──▼──────────┐
    │ Pasion  │  │  Palpo   │  │   Static    │
    │  :8080  │  │ (Matrix) │  │   Assets    │
    └────┬────┘  │  :8008   │  └─────────────┘
         │       └──────────┘
         │
         │  ┌─────────────────────────────────────┐
         │  │          Pasion Internals            │
         │  │                                     │
         │  │  HTTP Handlers                      │
         │  │    ├── Workflow Engine               │
         │  │    │     (registration, recovery,    │
         │  │    │      verification state machines)│
         │  │    ├── Notification Center           │
         │  │    │     (email + SMS dispatch)       │
         │  │    ├── Connectors                    │
         │  │    │     (Palpo Matrix, upstream SSO) │
         │  │    └── Policy Engine                 │
         │  │          (Cedar / OPA / Remote)       │
         │  └─────────────────────────────────────┘
         │
    ┌────▼──────┐
    │ PostgreSQL │
    └───────────┘

Palpo Homeserver Configuration

Configure Palpo to delegate authentication to Pasion:

experimental_features:
  msc3861:
    enabled: true
    issuer: https://auth.example.com/
    client_id: 0000000000000000000PALPO
    client_auth_method: client_secret_basic
    client_secret: "your-secret"
    admin_token: "admin-token"
    account_management_url: "https://auth.example.com/account/"

CLI Reference

Command Description
pasion server -c config.yaml Start the HTTP server (default)
pasion config generate Generate a default configuration file
pasion config check -c config.yaml Validate configuration
pasion config sync -c config.yaml Sync OAuth clients / upstream providers to the database
pasion database migrate -c config.yaml Run database migrations manually
pasion manage register-user Create a new user
pasion manage set-password Set or reset a user's password
pasion manage promote-user Promote a user to admin
pasion worker -c config.yaml Run background task worker separately
pasion doctor -c config.yaml Check deployment health

Server Options

pasion server -c config.yaml                # Full startup (default)
pasion server -c config.yaml --no-worker    # HTTP only, no background worker
pasion server -c config.yaml --no-migrate   # Skip automatic DB migrations
pasion server -c config.yaml --no-sync      # Skip config sync to DB

Upstream SSO Providers

Pasion supports federation with external identity providers. Any standard OIDC provider works out of the box. Additionally, dedicated support is provided for these Chinese platforms with non-standard OAuth2 flows:

Provider token_endpoint_auth_method Notes
Google, GitLab, Keycloak, Authentik, etc. client_secret_post / client_secret_basic Standard OIDC
GitHub client_secret_post OAuth 2.0 with manual authorization, token, and userinfo endpoints
Apple sign_in_with_apple Apple-specific JWT client secret
QQ qq_connect Non-standard token + separate OpenID endpoint
WeChat wechat Uses appid/secret, token includes openid
WeCom wecom Corp access token + user identity resolution
Feishu feishu Two-step: app_access_token then user token
Lark lark International Feishu, same flow with different endpoints
DingTalk dingtalk JSON body + custom access token header

See the SSO setup guide for provider-specific configuration examples.

Production Deployment

For production, consider separating the HTTP server and background workers:

# HTTP server (can be load-balanced)
pasion server --no-worker -c config.yaml

# Background workers (can run multiple instances)
pasion worker -c config.yaml

Key endpoints exposed by the server:

Endpoint Purpose
/health Health check
/healthz Health check alias
/metrics Prometheus metrics
/.well-known/openid-configuration OIDC discovery
/oauth2/authorize OAuth 2.0 authorization
/oauth2/token Token endpoint
/api/admin/v1/* Admin API

Documentation

Full documentation is available at https://palpo-im.github.io/pasion/.

Section Description
Installation Install and configure Pasion
General Setup Basic configuration walkthrough
Database Database setup and migrations
Homeserver Palpo / Matrix integration
Reverse Proxy nginx / Caddy configuration
SSO Upstream identity provider setup
Configuration Reference Full configuration options
CLI Reference Command-line tool documentation
Admin API Manage users and sessions via API
Architecture Internal design and crate structure
Contributing How to contribute to the project

Requirements

  • PostgreSQL 17 or later
  • Palpo homeserver 0.2.1 or later (or any compatible Matrix homeserver)
  • A reverse proxy (nginx, Caddy, etc.) for TLS termination

License

Pasion is distributed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). See LICENSE.

Some files retain upstream copyright and notice headers where required.

Embedding in another Salvo server

pasion_backend::PasionServer initializes the same application state as pasion server, including migrations, configured clients/providers, policy refresh, notification workers and activity tracking. It opens no ports and installs no tracing subscriber or signal handlers. Call it once per process; storage and version metadata currently have process-wide state.

let pasion = pasion_backend::PasionServer::initialize(
    &figment,
    pasion_backend::ServerOptions::default(),
).await?;
let router = salvo::Router::new()
    .push(pasion.router(&resources, Some("/_pasion/")))
    .push(host_routes);
// The host binds one listener, serves router and handles shutdown signals.
// After draining incoming requests:
pasion.shutdown().await;

Set http.public_base (and http.issuer, if present) to the public URL including its trailing-slash mount, for example https://example.com/_pasion/. Supply frontend assets, templates, translations and Cedar policy paths as in the standalone configuration. Build the frontend with dx build -p pasion-frontend --release --base-path /_pasion/ --debug-symbols false so generated JS loads the WASM under that mount. http.listeners is consulted for asset discovery but never bound by the embedding API. All middleware stays inside the mounted router; unrelated host routes do not need Pasion state.

Hosts that already have lifecycle tokens/task tracking can use initialize_with_runtime. The standalone CLI uses this shared initializer and retains its listener, reload and signal handling.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages