User & System Journeys

Detailed end-to-end walkthroughs of primary user and system interactions within AuthOS.

Updated Apr 12, 2026 Edit this page

User & System Journeys

This document provides a high-level walkthrough of how different components within the platform interact to fulfill common use cases. It bridges the gap between the high-level architecture and the low-level API reference.


1. Platform Owner Journeys (Global Admin)

These journeys describe the actions taken by the person who manages the entire AuthOS instance.

Journey 1.1: Initial Platform Setup & Bootstrap

The platform is deployed for the first time.

  1. Deployment:
  • The system starts up for the first time (via main.rs).
  • It detects that the PLATFORM_OWNER_EMAIL and PLATFORM_OWNER_PASSWORD environment variables are set.
  1. api (Backend - main.rs -> ensure_platform_owner):
  • It checks if a user with that email already exists in the users table.
  • If not, it creates a new user and sets the is_platform_owner flag to true.
  • It calls the UserStore::bootstrap_platform_owner function.
  1. api (Backend - store/users.rs -> bootstrap_platform_owner):
  • It creates a default “Free” organization tier in the organization_tiers table if it doesn’t exist.
  1. Result:
  • The platform owner can now log in via the standard login flow.
  • Once logged in, their JWT contains the is_platform_owner: true claim, granting access to /api/platform/* endpoints.

Journey 1.2: Approving a New Organization

A developer wants to use the platform and registers their organization.

  1. web-client (UI - Registration):
  • The developer fills out the organization registration form (name, slug).
  • The frontend calls POST /api/organizations/register.
  1. api (Backend - handlers/organizations.rs -> register_organization):
  • The system creates the organization record with a pending status.
  • The developer is assigned as the owner of this organization.
  1. api (Backend - handlers/platform/governance.rs -> approve_organization):
  • The Platform Owner receives an alert and reviews the pending organization.
  • They click “Approve” in the platform admin dashboard.
  • The API updates the organization’s status to active and assigns an initial tier (e.g., tier_free).
  1. Result:
  • The developer (Org Owner) receives an email notification.
  • The organization can now create services and manage users.

2. Organization Admin Journeys (Tenant Admin)

These journeys describe the actions taken by an administrator of a specific organization (tenant).

Journey 2.1: Creating a New Service (OIDC Application)

An admin wants to integrate a new internal application with the platform.

  1. web-client (UI - Service Management):
  • The admin clicks “New Service” and enters the service name and slug.
  • They define the allowed redirect_uris.
  1. api (Backend - handlers/services.rs -> create_service):
  • The handler generates a unique client_id and a client_secret (stored as a hash).
  • It creates a default “free” plan for the service in the plans table.
  • It creates the service record in the services table.
  1. Result:
  • The client_secret is displayed to the admin once in the UI.
  • The admin configures their application with the client_id and client_secret to use the OIDC flow.

Journey 2.2: Configuring “Bring Your Own OAuth” (BYOO)

An admin wants their users to log in using the company’s own GitHub OAuth app.

  1. web-client (UI - Integration Settings):
  • The admin goes to “Authentication Providers” -> “GitHub”.
  • They enter their company’s GitHub client_id and client_secret.
  1. sso-sdk (Client-Side):
  • The SDK calls POST /api/organizations/:org_slug/oauth-credentials/github.
  1. api (Backend - handlers/organizations.rs -> set_org_oauth_credentials):
  • The handler receives the credentials.
  • It uses the EncryptionService (encryption/mod.rs) to encrypt the client_secret with the platform’s master key (AES-GCM).
  • It stores the record in the organization_oauth_credentials table.
  1. Result:
  • When users log in via this organization, the platform will use these custom credentials instead of the platform default, providing a white-labeled login experience (e.g., “Authorize Acme Corp” instead of “Authorize SSO Platform”).

Journey 2.3: Managing Organization Invitations

An admin wants to invite a colleague to help manage the organization.

  1. web-client (UI - Team Management):
  • The admin enters the colleague’s email and selects a role (e.g., admin).
  1. api (Backend - handlers/invitations.rs -> create_invitation):
  • The system creates a record in the organization_invitations table with a secure, random token.
  • It triggers an “Email Invitation” job.
  1. api (Background Job - JobProcessor):
  • The JobProcessor picks up the job and sends an email containing a link to https://auth.example.com/invitations/accept?token=....
  1. Colleague Accept:
  • The colleague clicks the link and logs in.
  • The accept_invitation handler validates the token, creates a membership record, and deletes the invitation.
  1. Result:
  • The colleague is now an admin of the organization.

Journey 2.4: Custom Domain & Branding Setup

An organization wants to use auth.acme.com instead of acme.auth.example.com.

  1. web-client (UI - Branding):
  • The admin enters auth.acme.com and uploads the company logo.
  1. api (Backend - handlers/branding.rs -> set_custom_domain):
  • The handler validates the domain and generates a DNS verification token (UUID).
  • It returns the token and instructions to add a TXT record.
  1. DNS Verification:
  • The admin adds the TXT record to their DNS provider.
  • They click “Verify” in the AuthOS dashboard, which calls POST /api/organizations/:slug/domain/verify.
  • The API uses hickory-resolver to perform a DNS lookup.
  1. Result:
  • Once verified, the platform’s reverse proxy (e.g., Netlify/Nginx) is configured to route auth.acme.com to the AuthOS instance.
  • The login pages now display the organization’s logo and primary color.

Journey 2.5: Tier & Feature Management (Billing)

An organization needs to upgrade to the “Pro” tier for more users.

  1. web-client (UI - Billing):
  • The admin selects the “Pro” tier and clicks “Upgrade”.
  • The frontend calls POST /api/organizations/:slug/billing/checkout.
  1. api (Backend - billing/mod.rs -> create_checkout_session):
  • The system interacts with the BillingProvider (e.g., Stripe or Polar).
  • It creates a checkout session and redirects the user to the provider’s payment page.
  1. Webhook Handling:
  • Once the payment is successful, Stripe sends a checkout.session.completed webhook.
  • The handlers/billing.rs webhook handler validates the signature.
  • It updates the organization’s tier_id in the organizations table.
  1. Result:
  • The organization’s limits (max users, max services) are automatically increased according to the new tier’s configuration.

Journey 2.6: Reviewing Organization Audit Logs

An admin needs to investigate a suspicious configuration change.

  1. web-client (UI - Audit Logs):
  • The admin navigates to the “Audit Logs” section.
  • They filter by “Action” = service.updated and “Date” = “Last 24 hours”.
  1. sso-sdk (Client-Side):
  • The SDK calls GET /api/organizations/:org_slug/audit-log?action=service.updated&limit=50.
  1. api (Backend - handlers/organization_audit.rs -> get_organization_audit_logs):
  • The handler verifies the admin has ownership permissions.
  • It queries the organization_audit_log table, strictly scoped to the org_id.
  • It returns a paginated list of events, including the actor_user_id, ip_address, and details (JSON).
  1. Result:
  • The admin sees exactly which user changed the redirect URI of a service and from which IP address.

Journey 2.7: Managing Service API Keys

An admin creates an API key for a backend microservice to call AuthOS.

  1. web-client (UI - Service Settings):
  • The admin clicks “Create API Key” for “Main API”.
  1. api (Backend - handlers/services.rs -> create_api_key):
  • The handler generates a secure random key.
  • It stores a hash (SHA-256) of the key in the api_keys table.
  • The key itself is prefixed with ak_live_ for easy identification.
  1. Result:
  • The plaintext key is shown to the admin only once.
  • The microservice uses this key in the X-API-Key header to authenticate requests to protected AuthOS endpoints.

Journey 2.8: Webhook Integration for External Automation

An admin wants to notify an internal Slack channel whenever a new user signs up.

  1. web-client (UI - Webhooks):
  • The admin enters the Slack integration URL and selects the user.signup.success event.
  1. api (Backend - handlers/webhooks.rs -> create_webhook):
  • The system generates a random secret for HMAC signing.
  • It stores the webhook configuration in the webhooks table.
  1. Event Processing:
  • Later, a new user signs up. The auth_callback handler publishes a UserSignupSuccess event to the EventDispatcher.
  • The EventDispatcher (services/events.rs) finds the webhook that subscribes to this event.
  • It creates a “pending” record in the webhook_deliveries table.
  1. api (Background Job - JobProcessor):
  • The JobProcessor (jobs/job_processor.rs) background worker picks up the pending delivery.
  • The job constructs a POST request, signs the payload with the webhook’s secret (HMAC-SHA256), and sends it to the target URL.
  • It records the response and updates the delivery record to “delivered” or schedules a retry on failure.

Journey 2.9: Automated Provisioning via SCIM 2.0

An enterprise customer (e.g., using Okta) provisions a user automatically into the SSO platform.

  1. External System (Okta/Azure AD):
  • An employee joins the company. Okta triggers a SCIM POST request to the SSO platform: POST /scim/v2/Users.
  • The request includes the user’s email, name, and other attributes.
  1. api (Backend - middleware.rs -> scim_auth_middleware):
  • The middleware intercepts the request and validates the Bearer token against the scim_tokens table.
  • It verifies the token is active and belongs to a valid organization.
  1. api (Backend - handlers/scim/users.rs -> create_user):
  • The handler creates the user in the users table (if they don’t already exist).
  • It creates a membership record for the organization associated with the SCIM token.
  • It grants standard ReBAC permissions (e.g., organization:123#member@user:456).
  1. Result:
  • The user is now provisioned and can immediately log in to the organization’s apps without needing an invitation.
  • When the user leaves the company, Okta sends a DELETE or PATCH active=false request, and the system automatically revokes their access.

Journey 2.10: Configuring Risk & Security Policy

An Organization Admin configures adaptive authentication rules to secure their users.

  1. web-client (UI - Risk Settings):
  • The admin sets the “Impossible Travel” score to 50 and the “New Device” score to 20.
  • They set the “Enforcement Mode” to challenge for scores above 70.
  1. api (Backend - handlers/organizations/risk.rs -> update_risk_settings):
  • The handler updates the risk_rules table for the organization.
  1. Result:
  • Future logins will be evaluated by the RiskEngine. If a user logs in from London and then 10 minutes later from New York, the high risk score will trigger an MFA challenge.

Journey 2.11: GDPR “Right to be Forgotten”

An Organization Admin processes a user’s request to delete their data.

  1. web-client (UI - User Management):
  • The admin selects a user and clicks “Anonymize User” (GDPR Delete).
  1. sso-sdk (Client-Side):
  • The SDK calls DELETE /api/privacy/forget/:user_id.
  1. api (Backend - handlers/privacy.rs -> forget_user):
  • The handler verifies the admin has ownership permissions over the user.
  • It performs a “soft delete” on the users record (setting deleted_at).
  • It replaces the email with an anonymized string: deleted_{uuid}@redacted.invalid.
  • It hard deletes all PII tables: identities, user_passkeys, user_totp_secrets.
  • It preserves audit_log entries to maintain the security audit trail (integrity).
  • It revokes all active sessions for the user immediately.
  1. Result:
  • The user can no longer log in.
  • Their personal data is removed.
  • Historical logs remain consistent but anonymized.

Journey 2.12: Configuring SIEM Integration

An Organization Admin configures security event streaming to their corporate Datadog instance.

  1. Frontend (Settings Dashboard):
  • The admin enters the Datadog API key and endpoint URL.
  1. api (Backend - handlers/siem_configs.rs -> create_siem_config):
  • The handler validates the configuration.
  • The API key is encrypted using the EncryptionService (AES-GCM).
  • The configuration is stored in the siem_configs table.
  1. Result:
  • The organization can now test the connection via the /test endpoint, which decrypts the key and sends a test payload.

3. End-User Journeys (Customers of an Organization’s App)

These journeys describe the experience of a final user authenticating into a tenant’s application.

Journey 3.1: End-User SSO Login (Web Redirect with BYOO)

A customer of “Acme Corp” logs into app.acme.com.

  1. Tenant App (app.acme.com):
  • The user clicks “Login with GitHub”. The app’s frontend calls the sso-sdk.
  1. sso-sdk (Client-Side - modules/auth.ts):
  • The app calls sso.auth.getLoginUrl('github', { org: 'acme-corp', service: 'main-app', redirect_uri: 'https://app.acme.com/callback' }).
  • The SDK constructs the URL: https://auth.example.com/auth/github?org=acme-corp&service=....
  • The user’s browser is redirected to this URL.
  1. api (Backend - handlers/auth.rs -> auth_provider):
  • The GET /auth/:provider endpoint is hit.
  • It validates that the redirect_uri is registered for the specified service.
  • It checks the organization_oauth_credentials table for “acme-corp” and finds the custom GitHub credentials (from Journey 2.2).
  • It dynamically creates an OAuth client using Acme Corp’s BYOO credentials.
  • It generates and stores a state in the oauth_states table, linking it to the org, service, and redirect_uri.
  • The user is redirected to GitHub for authorization, but using Acme Corp’s app, not the platform’s default.
  1. api (Backend - handlers/auth.rs -> auth_callback):
  • After the user approves GitHub access, GitHub redirects back to /auth/github/callback?code=...&state=....
  • The handler retrieves the state from the DB to restore the context (org, service, redirect_uri).
  • It exchanges the code for an access_token and refresh_token using GitHub’s API.
  • It retrieves the user’s email from GitHub.
  • It finds or creates the user in the local users table and creates an identity record (storing the encrypted tokens).
  • It generates a session JWT (OIDC Id Token) signed by the platform’s private RSA key.
  • It redirects the user back to https://app.acme.com/callback?id_token=....
  1. Result:
  • The user is now logged into app.acme.com via Acme Corp’s GitHub app.

Journey 3.2: Setting up Multi-Factor Authentication (MFA)

A user wants to add an extra layer of security to their account.

  1. web-client (UI - Security Settings):
  • The user clicks “Enable MFA”.
  1. api (Backend - handlers/user.rs -> setup_mfa):
  • The handler generates a random TOTP secret.
  • It encrypts the secret using EncryptionService and stores it in the user_totp_secrets table with enabled: false.
  • It generates a QR code (SVG) using the totp-rs crate.
  • It returns the QR code to the frontend.
  1. User Verification:
  • The user scans the QR code with their Google Authenticator app.
  • They enter the 6-digit code shown in the app.
  • The frontend calls POST /api/user/mfa/verify.
  • The API decrypts the stored secret, validates the code, and sets enabled: true.
  1. Result:
  • MFA is now active for this user. Future logins will require a TOTP code.

Journey 3.3: Login with MFA Enforcement

A user with MFA enabled logs in to an application.

  1. Login Flow:
  • The user enters their email and password (or uses an OAuth provider).
  • The api (handlers/auth.rs) identifies that MFA is enabled for this user.
  1. MFA Challenge:
  • Instead of a full session JWT, it issues a short-lived Pre-Authentication JWT with an mfa_required: true claim.
  • The user is redirected to the MFA verification page.
  • The user enters their 6-digit TOTP code.
  1. Verification:
  • The handlers/auth/mfa.rs handler validates the Pre-Auth JWT and the TOTP code.
  • On success, it issues the final session JWT and refresh token.
  1. Result:
  • The user is securely logged in.

Journey 3.4: Passwordless Login with Passkeys (WebAuthn)

A user wants to log in using their MacBook’s TouchID or Windows Hello.

  1. Registration:
  • The user clicks “Register Passkey” in their profile.
  • The api (handlers/webauthn.rs) uses the webauthn-rs crate to generate a challenge.
  • The user’s browser triggers the native biometric prompt.
  • The browser sends the signed challenge back to the API.
  • The API validates the signature and stores the public key in the user_passkeys table.
  1. Login:
  • On the login page, the user clicks “Sign in with Passkey”.
  • The API sends a challenge. The user touches the sensor.
  • The API verifies the response against the stored public key.
  1. Result:
  • The user is logged in instantly without a password.

4. System & Background Journeys

These journeys describe automated processes that keep the platform running securely.

Journey 4.1: Adaptive Risk Assessment

A user attempts to log in from a new location.

  1. Login Attempt:
  • The user submits their credentials.
  1. api (Backend - services/risk_engine.rs -> evaluate_login):
  • The RiskEngine is called. It retrieves the organization’s risk_rules.
  • It checks the login_events table for the user’s history.
  • It detects a “New Device” (+20) and “New IP” (+10).
  • It calculates a total risk score of 30.
  1. Enforcement:
  • If the score exceeds the organization’s medium_threshold, the system dynamically injects an MFA challenge, even if the user didn’t previously enable it (if the policy is set to challenge).
  1. Result:
  • The platform proactively secures the account against potential credential stuffing.

Journey 4.2: Automated Event Notifications (Webhooks)

A new user registers, and the system notifies external services.

  1. Event Trigger:
  • The register handler successfully creates a user.
  • It calls event_dispatcher.dispatch(UserRegisteredEvent).
  1. api (Backend - services/events.rs):
  • The EventDispatcher queries the webhooks table for all webhooks in that organization subscribed to user.registered.
  1. Delivery Creation:
  • For each match, it creates a webhook_deliveries record with a pending status.
  1. Worker Processing:
  • The JobProcessor background worker picks up the delivery.
  • It signs the JSON payload with the webhook secret (HMAC-SHA256).
  • It performs the HTTP POST request and records the result.

Journey 4.3: Platform Owner Bootstrap (Startup)

Ensuring the platform always has an administrator.

  1. Startup:
  • The application binary starts.
  1. Environment Check:
  • It reads PLATFORM_OWNER_EMAIL and PLATFORM_OWNER_PASSWORD.
  1. Database Sync:
  • It ensures the users table contains this user and they have the is_platform_owner flag.
  • It ensures the organization_tiers table has a tier_free entry.

Journey 4.4: Background Token Rotation (OAuth)

Keeping user identities active without user intervention.

  1. Scheduler:
  • The TokenRefreshJob (jobs/token_refresh.rs) runs every 30 minutes.
  1. Identification:
  • It scans the identities table for tokens that expire in the next 60 minutes.
  1. Refresh Flow:
  • For each expiring token, it retrieves the refresh_token (decrypted via EncryptionService).
  • It calls the provider’s (e.g., Google) token endpoint to get a new access_token.
  • The provider returns a new access_token (and optionally a new refresh_token).
  1. Database Update:
  • The job encrypts the new tokens using EncryptionService.
  • It updates the identity record in the database with the new encrypted tokens and the new expiration timestamp via IdentityStore::update_tokens_encrypted.

Journey 4.5: Service-Initiated Provider Token Retrieval (On-Demand)

This journey describes how a tenant’s backend service retrieves a fresh access token for a user’s connected provider (e.g., GitHub) to perform actions on their behalf.

  1. External Service (Tenant’s Backend):
  • The tenant’s application needs to call the GitHub API for a specific user.
  • It requests a fresh token from the SSO platform: GET /api/provider-token/github.
  • It authenticates using its API Key (Journey 2.7) in the X-Api-Key header.
  1. api (Backend - handlers/provider_token.rs -> get_provider_token):
  • The middleware validates the API Key and injects the ServicePrincipal context (Service ID and Org ID).
  • The handler verifies that the service is configured with the necessary scopes for the requested provider.
  • It queries the identities table for the user’s identity record, strictly scoped to the authenticated service_id to ensure isolation.
  1. Token Validation & Refresh:
  • The handler checks the token’s expiration time.
  • If expired or expiring soon (< 5 mins): It performs an inline refresh using the same logic as Journey 4.4 (acquiring a distributed lock via TokenRefreshLockStore to prevent race conditions).
    • It uses the organization’s BYOO credentials associated with the service.
    • It updates the database with the new token.
  • If valid: It proceeds with the stored token.
  1. Response:
  • The handler decrypts the valid access token using EncryptionService.
  • It returns the plaintext access_token and current scopes to the calling service.

Journey 4.6: System Cleanup & Security Maintenance

This journey covers the automated housekeeping tasks that run in the background to maintain system security, performance, and data hygiene.

  1. Device Code Cleanup:
  • Actor: DeviceCodeCleanupJob (jobs/device_code_cleanup.rs).
  • Action: Runs every 5 minutes to delete expired or abandoned device authorization codes from the device_codes table.
  • Purpose: Prevents table bloat and ensures expired codes cannot be brute-forced.
  1. OAuth State Cleanup:
  • Actor: OAuthStateCleanupJob (jobs/oauth_state_cleanup.rs).
  • Action: Runs every 10 minutes to remove expired CSRF state tokens from the oauth_states table.
  • Purpose: mitigating replay attacks and freeing storage.
  1. SAML State Cleanup:
  • Actor: SamlStateCleanupJob (jobs/saml_state_cleanup.rs).
  • Action: Runs every 10 minutes to remove expired SAML request states.
  • Purpose: Enforces the short lifespan of SAML authentication attempts (replay protection).

Journey 4.7: Security Audit Streaming (SIEM)

A high-priority security event occurs, and the platform streams it to configured SIEM destinations.

  1. api (Event Occurs):
  • A user fails MFA 10 times. The RiskEngine triggers a SecurityAlert event.
  1. api (Event Dispatcher):
  • The EventDispatcher identifies that SIEM streaming is enabled for this organization.
  • It looks up active siem_configs.
  1. api (Background Job):
  • The dispatcher queues a job to push the event to the SIEM endpoint using the encrypted credentials.

Journey 4.8: The “Reaper” (Data Lifecycle)

This journey ensures GDPR compliance by permanently deleting data that has been “soft deleted” for a retention period.

  1. Scheduler:
  • The UserCleanupJob wakes up once every 24 hours.
  1. Identification:
  • It scans the users table for records where deleted_at is not NULL and is older than 30 days.
  1. Hard Delete:
  • It executes a hard DELETE on these user records.
  • Database foreign key constraints cascade this deletion to all related tables (identities, memberships, subscriptions).
  1. Result:
  • Data is permanently purged from the primary database, satisfying strict compliance retention policies.

Journey 4.9: Authorization Context Hydration

How the system validates permissions without bloating the token.

  1. Middleware Interception:
  • Every authenticated request is intercepted by extract_user_from_jwt.
  • The middleware validates the JWT and extracts minimal claims (sub, email, org_id, service_id).
  1. Cache Lookup:
  • The system checks the in-memory cache (moka) for the user’s permission set using the sub (User ID).
  • Cache hit: Permissions attached to request context immediately.
  • Cache miss: Proceeds to database lookup.
  1. Database Hydration:
  • If not in cache, the system queries the permissions (ReBAC) table.
  • It performs a recursive expansion of roles and direct permissions.
  • The result is stored in the cache for 60 seconds.
  1. Result:
  • Handlers receive a fully hydrated AuthUser object with permissions, while the network payload remains minimal (~300 bytes vs 5-10KB).
  • Permission changes take effect within 60 seconds (vs 24 hours with JWT-embedded permissions).