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.
- Deployment:
- The system starts up for the first time (via
main.rs). - It detects that the
PLATFORM_OWNER_EMAILandPLATFORM_OWNER_PASSWORDenvironment variables are set.
api(Backend -main.rs->ensure_platform_owner):
- It checks if a user with that email already exists in the
userstable. - If not, it creates a new user and sets the
is_platform_ownerflag totrue. - It calls the
UserStore::bootstrap_platform_ownerfunction.
api(Backend -store/users.rs->bootstrap_platform_owner):
- It creates a default “Free” organization tier in the
organization_tierstable if it doesn’t exist.
- Result:
- The platform owner can now log in via the standard login flow.
- Once logged in, their JWT contains the
is_platform_owner: trueclaim, granting access to/api/platform/*endpoints.
Journey 1.2: Approving a New Organization
A developer wants to use the platform and registers their organization.
web-client(UI - Registration):
- The developer fills out the organization registration form (name, slug).
- The frontend calls
POST /api/organizations/register.
api(Backend -handlers/organizations.rs->register_organization):
- The system creates the organization record with a
pendingstatus. - The developer is assigned as the
ownerof this organization.
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
activeand assigns an initial tier (e.g.,tier_free).
- 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.
web-client(UI - Service Management):
- The admin clicks “New Service” and enters the service name and slug.
- They define the allowed
redirect_uris.
api(Backend -handlers/services.rs->create_service):
- The handler generates a unique
client_idand aclient_secret(stored as a hash). - It creates a default “free” plan for the service in the
planstable. - It creates the service record in the
servicestable.
- Result:
- The
client_secretis displayed to the admin once in the UI. - The admin configures their application with the
client_idandclient_secretto 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.
web-client(UI - Integration Settings):
- The admin goes to “Authentication Providers” -> “GitHub”.
- They enter their company’s GitHub
client_idandclient_secret.
sso-sdk(Client-Side):
- The SDK calls
POST /api/organizations/:org_slug/oauth-credentials/github.
api(Backend -handlers/organizations.rs->set_org_oauth_credentials):
- The handler receives the credentials.
- It uses the
EncryptionService(encryption/mod.rs) to encrypt theclient_secretwith the platform’s master key (AES-GCM). - It stores the record in the
organization_oauth_credentialstable.
- 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.
web-client(UI - Team Management):
- The admin enters the colleague’s email and selects a role (e.g.,
admin).
api(Backend -handlers/invitations.rs->create_invitation):
- The system creates a record in the
organization_invitationstable with a secure, random token. - It triggers an “Email Invitation” job.
api(Background Job -JobProcessor):
- The
JobProcessorpicks up the job and sends an email containing a link tohttps://auth.example.com/invitations/accept?token=....
- Colleague Accept:
- The colleague clicks the link and logs in.
- The
accept_invitationhandler validates the token, creates amembershiprecord, and deletes the invitation.
- 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.
web-client(UI - Branding):
- The admin enters
auth.acme.comand uploads the company logo.
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.
- 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-resolverto perform a DNS lookup.
- Result:
- Once verified, the platform’s reverse proxy (e.g., Netlify/Nginx) is configured to route
auth.acme.comto 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.
web-client(UI - Billing):
- The admin selects the “Pro” tier and clicks “Upgrade”.
- The frontend calls
POST /api/organizations/:slug/billing/checkout.
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.
- Webhook Handling:
- Once the payment is successful, Stripe sends a
checkout.session.completedwebhook. - The
handlers/billing.rswebhook handler validates the signature. - It updates the organization’s
tier_idin theorganizationstable.
- 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.
web-client(UI - Audit Logs):
- The admin navigates to the “Audit Logs” section.
- They filter by “Action” =
service.updatedand “Date” = “Last 24 hours”.
sso-sdk(Client-Side):
- The SDK calls
GET /api/organizations/:org_slug/audit-log?action=service.updated&limit=50.
api(Backend -handlers/organization_audit.rs->get_organization_audit_logs):
- The handler verifies the admin has ownership permissions.
- It queries the
organization_audit_logtable, strictly scoped to theorg_id. - It returns a paginated list of events, including the
actor_user_id,ip_address, anddetails(JSON).
- 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.
web-client(UI - Service Settings):
- The admin clicks “Create API Key” for “Main API”.
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_keystable. - The key itself is prefixed with
ak_live_for easy identification.
- Result:
- The plaintext key is shown to the admin only once.
- The microservice uses this key in the
X-API-Keyheader 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.
web-client(UI - Webhooks):
- The admin enters the Slack integration URL and selects the
user.signup.successevent.
api(Backend -handlers/webhooks.rs->create_webhook):
- The system generates a random
secretfor HMAC signing. - It stores the webhook configuration in the
webhookstable.
- Event Processing:
- Later, a new user signs up. The
auth_callbackhandler publishes aUserSignupSuccessevent to theEventDispatcher. - The
EventDispatcher(services/events.rs) finds the webhook that subscribes to this event. - It creates a “pending” record in the
webhook_deliveriestable.
api(Background Job -JobProcessor):
- The
JobProcessor(jobs/job_processor.rs) background worker picks up the pending delivery. - The job constructs a
POSTrequest, 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.
- External System (Okta/Azure AD):
- An employee joins the company. Okta triggers a SCIM
POSTrequest to the SSO platform:POST /scim/v2/Users. - The request includes the user’s email, name, and other attributes.
api(Backend -middleware.rs->scim_auth_middleware):
- The middleware intercepts the request and validates the Bearer token against the
scim_tokenstable. - It verifies the token is active and belongs to a valid organization.
api(Backend -handlers/scim/users.rs->create_user):
- The handler creates the user in the
userstable (if they don’t already exist). - It creates a
membershiprecord for the organization associated with the SCIM token. - It grants standard ReBAC permissions (e.g.,
organization:123#member@user:456).
- 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
DELETEorPATCH active=falserequest, 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.
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
challengefor scores above 70.
api(Backend -handlers/organizations/risk.rs->update_risk_settings):
- The handler updates the
risk_rulestable for the organization.
- 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.
web-client(UI - User Management):
- The admin selects a user and clicks “Anonymize User” (GDPR Delete).
sso-sdk(Client-Side):
- The SDK calls
DELETE /api/privacy/forget/:user_id.
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
usersrecord (settingdeleted_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_logentries to maintain the security audit trail (integrity). - It revokes all active sessions for the user immediately.
- 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.
- Frontend (Settings Dashboard):
- The admin enters the Datadog API key and endpoint URL.
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_configstable.
- Result:
- The organization can now test the connection via the
/testendpoint, 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.
- Tenant App (
app.acme.com):
- The user clicks “Login with GitHub”. The app’s frontend calls the
sso-sdk.
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.
api(Backend -handlers/auth.rs->auth_provider):
- The
GET /auth/:providerendpoint is hit. - It validates that the
redirect_uriis registered for the specified service. - It checks the
organization_oauth_credentialstable 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
statein theoauth_statestable, linking it to theorg,service, andredirect_uri. - The user is redirected to GitHub for authorization, but using Acme Corp’s app, not the platform’s default.
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
statefrom the DB to restore the context (org,service,redirect_uri). - It exchanges the
codefor anaccess_tokenandrefresh_tokenusing GitHub’s API. - It retrieves the user’s email from GitHub.
- It finds or creates the user in the local
userstable and creates anidentityrecord (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=....
- Result:
- The user is now logged into
app.acme.comvia 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.
web-client(UI - Security Settings):
- The user clicks “Enable MFA”.
api(Backend -handlers/user.rs->setup_mfa):
- The handler generates a random TOTP secret.
- It encrypts the secret using
EncryptionServiceand stores it in theuser_totp_secretstable withenabled: false. - It generates a QR code (SVG) using the
totp-rscrate. - It returns the QR code to the frontend.
- 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.
- 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.
- 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.
- MFA Challenge:
- Instead of a full session JWT, it issues a short-lived Pre-Authentication JWT with an
mfa_required: trueclaim. - The user is redirected to the MFA verification page.
- The user enters their 6-digit TOTP code.
- Verification:
- The
handlers/auth/mfa.rshandler validates the Pre-Auth JWT and the TOTP code. - On success, it issues the final session JWT and refresh token.
- 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.
- Registration:
- The user clicks “Register Passkey” in their profile.
- The
api(handlers/webauthn.rs) uses thewebauthn-rscrate 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_passkeystable.
- 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.
- 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.
- Login Attempt:
- The user submits their credentials.
api(Backend -services/risk_engine.rs->evaluate_login):
- The
RiskEngineis called. It retrieves the organization’srisk_rules. - It checks the
login_eventstable for the user’s history. - It detects a “New Device” (+20) and “New IP” (+10).
- It calculates a total risk score of 30.
- 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 tochallenge).
- 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.
- Event Trigger:
- The
registerhandler successfully creates a user. - It calls
event_dispatcher.dispatch(UserRegisteredEvent).
api(Backend -services/events.rs):
- The
EventDispatcherqueries thewebhookstable for all webhooks in that organization subscribed touser.registered.
- Delivery Creation:
- For each match, it creates a
webhook_deliveriesrecord with apendingstatus.
- Worker Processing:
- The
JobProcessorbackground 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.
- Startup:
- The application binary starts.
- Environment Check:
- It reads
PLATFORM_OWNER_EMAILandPLATFORM_OWNER_PASSWORD.
- Database Sync:
- It ensures the
userstable contains this user and they have theis_platform_ownerflag. - It ensures the
organization_tierstable has atier_freeentry.
Journey 4.4: Background Token Rotation (OAuth)
Keeping user identities active without user intervention.
- Scheduler:
- The
TokenRefreshJob(jobs/token_refresh.rs) runs every 30 minutes.
- Identification:
- It scans the
identitiestable for tokens that expire in the next 60 minutes.
- Refresh Flow:
- For each expiring token, it retrieves the
refresh_token(decrypted viaEncryptionService). - 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 newrefresh_token).
- 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.
- 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-Keyheader.
api(Backend -handlers/provider_token.rs->get_provider_token):
- The middleware validates the API Key and injects the
ServicePrincipalcontext (Service ID and Org ID). - The handler verifies that the service is configured with the necessary scopes for the requested provider.
- It queries the
identitiestable for the user’s identity record, strictly scoped to the authenticatedservice_idto ensure isolation.
- 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
TokenRefreshLockStoreto 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.
- Response:
- The handler decrypts the valid access token using
EncryptionService. - It returns the plaintext
access_tokenand currentscopesto 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.
- 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_codestable. - Purpose: Prevents table bloat and ensures expired codes cannot be brute-forced.
- OAuth State Cleanup:
- Actor:
OAuthStateCleanupJob(jobs/oauth_state_cleanup.rs). - Action: Runs every 10 minutes to remove expired CSRF state tokens from the
oauth_statestable. - Purpose: mitigating replay attacks and freeing storage.
- 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.
api(Event Occurs):
- A user fails MFA 10 times. The
RiskEnginetriggers aSecurityAlertevent.
api(Event Dispatcher):
- The
EventDispatcheridentifies that SIEM streaming is enabled for this organization. - It looks up active
siem_configs.
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.
- Scheduler:
- The
UserCleanupJobwakes up once every 24 hours.
- Identification:
- It scans the
userstable for records wheredeleted_atis not NULL and is older than 30 days.
- Hard Delete:
- It executes a hard
DELETEon these user records. - Database foreign key constraints cascade this deletion to all related tables (
identities,memberships,subscriptions).
- 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.
- 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).
- Cache Lookup:
- The system checks the in-memory cache (
moka) for the user’s permission set using thesub(User ID). - Cache hit: Permissions attached to request context immediately.
- Cache miss: Proceeds to database lookup.
- 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.
- Result:
- Handlers receive a fully hydrated
AuthUserobject 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).