Compass — Authentication Flow Engine

Compass is FerrisKey’s authentication flow engine. It records every authentication attempt as a structured flow — a sequence of named steps with individual outcomes, timings, and error details. Compass gives you deep observability into how users authenticate, where failures occur, and how long each step takes.

Why Compass?

Authentication looks simple from the outside: the user logs in and gets a token. But inside, a single login request can involve redirect validation, credential hashing, MFA challenges, external IdP callbacks, session creation, and token signing. When something fails, you need to know which step broke and why.

Without Compass, a failed login is just a 401. With Compass, you see:

Flow 01914b3c-... for client my-frontend via authorization_code: ✓ authorize (12ms) → ✓ credential_validation (85ms) → ✗ mfa_challenge (0ms, error: invalid_otp) → Flow failed at 97ms

How It Works

When Compass is enabled, every authentication request creates a CompassFlow. As the request progresses through credential validation, MFA challenges, token exchange, and finalization, each step is recorded as a CompassFlowStep with its own status and duration.

graph TD
    A[Flow Started] --> B[Authorize]
    B --> C[Credential Validation]
    C --> D{MFA Required?}
    D -->|Yes| E[MFA Challenge]
    D -->|No| F[Token Exchange]
    E --> F
    F --> G[Finalize]
    G --> H[Flow Completed]

Flow Lifecycle

Each flow progresses through a clear lifecycle:

Flow Created

When an authentication request arrives, Compass creates a CompassFlow with the realm, client, grant type, IP address, and user agent. The flow status is pending.

Steps Recorded

As the authentication progresses, each step (authorize, credential validation, MFA, etc.) is recorded with its outcome, duration, and any error details. Steps are persisted asynchronously.

User Identified

After successful credential validation, the user_id is attached to the flow. This links the flow to a specific user for later querying.

Flow Completed

When authentication finishes (success or failure), the flow is marked as completed with a final status, completion timestamp, and total duration in milliseconds.

Flow Structure

A CompassFlow captures the full picture of an authentication attempt:

FieldTypeDescription
idUUIDv7Unique flow identifier (time-ordered for efficient querying)
realm_idUUIDRealm context
client_idStringClient ID that initiated the authentication
user_idUUID?Authenticated user (set after credential validation succeeds)
grant_typeStringOAuth2 grant type (authorization_code, password, client_credentials, refresh_token)
statusFlowStatusOverall outcome: pending, success, failure, expired
ip_addressString?Source IP address
user_agentString?Client user agent
started_atDateTimeWhen the flow began
completed_atDateTime?When the flow finished (null while pending)
duration_msi64?Total flow duration in milliseconds
stepsVec<FlowStep>Ordered list of step records

Flow Status Values

StatusMeaning
pendingFlow is in progress — steps are still being recorded
successAuthentication completed successfully, tokens were issued
failureAuthentication failed at one of the steps
expiredThe auth session expired before completion (user took too long)

Flow Steps

Each step within a flow records:

FieldTypeDescription
idUUIDv7Unique step identifier
flow_idUUIDParent flow reference
step_nameFlowStepNameOne of the 7 step types
statusStepStatussuccess, failure, or skipped
duration_msi64?Step execution time in milliseconds
error_codeString?Machine-readable error code (on failure)
error_messageString?Human-readable error description (on failure)
started_atDateTimeWhen the step began executing

Step Types

StepWhen It ExecutesTypical Duration
authorizeOAuth2 authorization request validation — checks redirect URI, scope, response type, CSRF state<5ms
credential_validationUsername lookup + password hash verification (Argon2)50–200ms
mfa_challengeTOTP code validation or WebAuthn assertion verification5–50ms
token_exchangeAuthorization code → token exchange (code lookup + token generation)10–30ms
idp_redirectBuilding and recording the redirect to an external identity provider<5ms
idp_callbackProcessing the callback from an external IdP (token exchange + user lookup)100–500ms
finalizeSession creation, SeaWatch event emission, and cleanup5–15ms

Step Status Values

StatusMeaning
successStep completed successfully
failureStep failed — check error_code and error_message
skippedStep was not applicable (e.g., mfa_challenge skipped when no MFA is configured)

Configuration

SettingDefaultDescription
compass_enabledtrueEnable/disable flow recording per realm

When disabled, authentication works exactly the same — the flow recording is simply skipped. No flows are created, no steps are recorded, and no database writes occur. Toggle this off for realms where you don’t need flow-level observability.

Zero performance impact when disabled

When compass_enabled is false, the FlowRecorder short-circuits immediately. No channels are used, no database writes happen, no memory is allocated for flow objects.