Forge module wrapping identity-auth. Sprint 65: owns the staff + customer auth subsystem (repo/auth, customer_auth/workflows services, admin_auth + api_admin_auth middleware, JSON auth routers) extracted from rust-cms-engine.
| Tier | application |
| Role | unclassified (baselined) |
| Path | crates/application/auth |
| Edition | 2024 |
| Targets | application_auth, me_email, pg_forge_auth_migrations |
| Public items | 106 across 20 modules |
| Tests | 34 |
What it is for
application-auth — wraps identity-auth.
Sprint 65: also owns the staff + customer authentication subsystem lifted from rust-cms-engine — account persistence (repo::auth), the customer auth + workflow services (services), the structural /admin + /api/admin middleware (middleware), and the JSON auth routers (api).
Capabilities
crate root
application-auth — wraps identity-auth.
| Item |
|---|
async fn seed_admin_user(pool : & PgPool, email : & str, password : & str,) -> Result <bool, sqlx::Error> |
AuthModule
application-auth — wraps identity-auth.
| Item |
|---|
pub struct AuthModule |
AuthModule :: fn new() -> Self |
AuthModule :: fn name(& self) -> & 'static str |
AuthModule :: fn version(& self) -> & 'static str |
AuthModule :: fn migrations(& self) -> Vec <MigrationSet> |
AuthModule :: async fn migrate_pending(& self, pool : & PgPool) -> std::result::Result <u32, MigrationError> |
AuthModule :: fn public_router(& self) -> axum::Router <S> |
api (other)
Auth JSON routers (Sprint 65: extracted from rust-cms-engine).
| Item |
|---|
fn api_keys_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
fn router_v1 <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
api::admin_console (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
fn admin_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
fn me_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, identity_user_prefs::LocaleSettings : FromRef <S>, |
api::api_keys (other)
Self-service API-key management (Sprint 0.67).
| Item |
|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
api::auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
fn router_v1 <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
MeResponse
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct MeResponse |
PermissionsResponse
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct PermissionsResponse |
api::customer_auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
api::customer_workflows (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, |
middleware::api_admin_auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
async fn api_admin_auth(State(pool) : State <PgPool>, session : Session, ConnectInfo(peer) : ConnectInfo <SocketAddr>, mut req : Request, next : Next,) -> Response |
middleware::auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub const SESSION_USER_ID_KEY: & str |
pub const SESSION_ACTIVE_TENANT_KEY: & str |
pub const FORCE_PASSWORD_PATH: & str |
async fn admin_auth(State(pool) : State <PgPool>, session : Session, ConnectInfo(peer) : ConnectInfo <SocketAddr>, mut req : Request, next : Next,) -> Response |
repo::api_keys (other)
API-key persistence + verification lookup (Sprint 0.67).
| Item |
|---|
async fn create(pool : & PgPool, tenant_id : Uuid, owner_id : Uuid, created_by : Uuid, name : & str, scopes : & String, expires_at : Option <DateTime <Utc>>,) -> Result <(Uuid, String), sqlx::Error> |
async fn revoke(pool : & PgPool, id : Uuid, owner_id : Uuid) -> Result <bool, sqlx::Error> |
async fn touch_last_used(pool : & PgPool, id : Uuid) -> Result <(), sqlx::Error> |
ApiKeyRow
API-key persistence + verification lookup (Sprint 0.67).
| Item |
|---|
pub struct ApiKeyRow |
async fn list_for_owner(pool : & PgPool, owner_id : Uuid, tenant_id : Uuid,) -> Result <Vec <ApiKeyRow>, sqlx::Error> |
ApiKeyRow :: fn from(r : ApiKeyRowSql) -> Self |
VerifiedKey
API-key persistence + verification lookup (Sprint 0.67).
| Item |
|---|
pub struct VerifiedKey |
async fn verify_key(pool : & PgPool, plaintext : & str,) -> Result <Option <VerifiedKey>, sqlx::Error> |
repo::auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
fn status_str(status : UserStatus) -> & 'static str |
async fn touch_last_login(pool : & PgPool, id : Uuid) -> Result <(), sqlx::Error> |
async fn set_password <'e, E>(executor : E, id : Uuid, new_hash : & str, must_change_password : bool,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, |
async fn update_display_name <'e, E>(executor : E, id : Uuid, display_name : & str,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, |
async fn update_status <'e, E>(executor : E, id : Uuid, status : UserStatus,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, |
Account
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct Account |
async fn find_account_by_email(pool : & PgPool, email : & str,) -> Result <Option <Account>, sqlx::Error> |
async fn find_account_by_id(pool : & PgPool, id : Uuid) -> Result <Option <Account>, sqlx::Error> |
async fn count_accounts(pool : & PgPool) -> Result <i64, sqlx::Error> |
async fn create_account <'e, E>(executor : E, user : & User, display_name : & str, must_change_password : bool,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, |
async fn list_accounts(pool : & PgPool) -> Result <Vec <AccountListRow>, sqlx::Error> |
AccountListRow
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct AccountListRow |
repo::login_attempts (other)
Login-attempt persistence + recent-failure counts (Sprint 0.66 T2).
| Item |
|---|
async fn record_attempt(pool : & PgPool, attempt : & LoginAttempt) -> Result <(), sqlx::Error> |
async fn recent_failure_counts(pool : & PgPool, ip_address : & str, email : & str, policy : & LockoutPolicy,) -> Result <FailureCounts, sqlx::Error> |
services::admin_screens (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
async fn list_audit(pool : & PgPool, filter : AuditFilter, limit : i64,) -> Result <Vec <AuditRow>, AdminError> |
async fn list_contact(pool : & PgPool, filter : ContactFilter, limit : i64,) -> Result <Vec <ContactSubmission>, AdminError> |
async fn contact_detail(pool : & PgPool, id : Uuid) -> Result <Option <ContactDetail>, AdminError> |
async fn add_contact_note(pool : & PgPool, submission_id : Uuid, author_id : Uuid, body : String,) -> Result <ContactNote, AdminError> |
async fn list_users(pool : & PgPool, limit : i64) -> Result <Vec <UserRow>, AdminError> |
async fn invite_user(pool : & PgPool, input : InviteUserInput, actor_id : Uuid,) -> Result <InviteResult, AdminError> |
async fn list_roles(pool : & PgPool) -> Result <Vec <RoleRow>, AdminError> |
async fn list_permissions(pool : & PgPool) -> Result <Vec <PermissionRow>, AdminError> |
async fn get_profile(pool : & PgPool, user_id : Uuid) -> Result <ProfileResponse, AdminError> |
async fn update_profile(pool : & PgPool, user_id : Uuid, patch : UpdateProfileInput,) -> Result <ProfileResponse, AdminError> |
async fn change_email(pool : & PgPool, user_id : Uuid, input : UpdateEmailInput, require_verification : bool,) -> Result <ProfileResponse, AdminError> |
async fn change_password(pool : & PgPool, user_id : Uuid, input : ChangePasswordInput,) -> Result <(), AdminError> |
AdminError
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub enum AdminError |
async fn mark_contact_read(pool : & PgPool, id : Uuid, actor_id : Uuid) -> Result <(), AdminError> |
async fn get_settings(pool : & PgPool) -> Result <serde_json::Value, AdminError> |
async fn update_settings(pool : & PgPool, patch : serde_json::Value, actor_id : Uuid,) -> Result <serde_json::Value, AdminError> |
async fn email_verification_required(pool : & PgPool) -> Result <bool, AdminError> |
AuditFilter
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct AuditFilter |
AuditRow
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct AuditRow |
ChangePasswordInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ChangePasswordInput |
ContactDetail
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ContactDetail |
ContactFilter
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ContactFilter |
ContactNote
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ContactNote |
ContactSubmission
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ContactSubmission |
InviteResult
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct InviteResult |
InviteUserInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct InviteUserInput |
PermissionRow
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct PermissionRow |
ProfileResponse
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct ProfileResponse |
RoleRow
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct RoleRow |
UpdateEmailInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct UpdateEmailInput |
UpdateProfileInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct UpdateProfileInput |
UserRow
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct UserRow |
ApiKeyPrincipal
API-key request authentication — resolve a presented sk_ key to a
| Item |
|---|
pub struct ApiKeyPrincipal |
async fn authenticate(pool : & PgPool, plaintext : & str,) -> Result <Option <ApiKeyPrincipal>, sqlx::Error> |
services::api_key_scope (other)
API-key scope + principal logic (Sprint 0.67, Gate 1.5 D2).
| Item |
|---|
fn parse_bearer(header_value : & str) -> Option <& str> |
fn effective_permissions(owner_perms : & HashSet <String>, key_scopes : & String,) -> HashSet <String> |
ScopeMintError
API-key scope + principal logic (Sprint 0.67, Gate 1.5 D2).
| Item |
|---|
pub enum ScopeMintError |
fn scopes_mintable_by(creator_perms : & HashSet <String>, requested_scopes : & String, known_perms : & HashSet <String>,) -> Result <(), ScopeMintError> |
services::customer_auth (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
async fn signup(pool : & PgPool, input : SignupInput) -> Result <(), CustomerAuthError> |
async fn login(pool : & PgPool, session : & Session, input : LoginInput, client_ip : Option <& str>, user_agent : Option <& str>,) -> Result <MeResponse, CustomerAuthError> |
async fn me(pool : & PgPool, user_id : Uuid) -> Result <Option <MeResponse>, CustomerAuthError> |
CustomerAuthError
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub enum CustomerAuthError |
async fn logout(session : & Session) -> Result <(), CustomerAuthError> |
LoginInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct LoginInput |
MeResponse
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct MeResponse |
SignupInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct SignupInput |
services::customer_workflows (other)
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
async fn submit_inquiry(pool : & PgPool, input : InquiryInput, user_id : Option <Uuid>, ip : Option <& str>, user_agent : Option <& str>,) -> Result <Uuid, CustomerError> |
CustomerError
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub enum CustomerError |
async fn enqueue_email(pool : & PgPool, template_key : & str, recipient_email : & str, context : serde_json::Value, idempotency_key : Option <& str>,) -> Result <Uuid, CustomerError> |
async fn issue_verification_token(pool : & PgPool, user_id : Uuid,) -> Result <String, CustomerError> |
async fn verify_email_token(pool : & PgPool, raw_token : & str) -> Result <Uuid, CustomerError> |
async fn issue_password_reset_token(pool : & PgPool, email : & str,) -> Result <Option <String>, CustomerError> |
async fn consume_password_reset(pool : & PgPool, raw_token : & str, new_password : & str,) -> Result <Uuid, CustomerError> |
async fn delete_account(pool : & PgPool, user_id : Uuid) -> Result <(), CustomerError> |
InquiryInput
Sprint 65: extracted from rust-cms-engine.
| Item |
|---|
pub struct InquiryInput |
FailureCounts
Brute-force lockout policy (Sprint 0.66 T2).
| Item |
|---|
pub struct FailureCounts |
LockoutDecision
Brute-force lockout policy (Sprint 0.66 T2).
| Item |
|---|
pub enum LockoutDecision |
LockoutPolicy
Brute-force lockout policy (Sprint 0.66 T2).
| Item |
|---|
pub struct LockoutPolicy |
LockoutPolicy :: fn default() -> Self |
LockoutPolicy :: fn evaluate(& self, counts : FailureCounts) -> LockoutDecision |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
application_auth
apiapi::admin_consoleapi::api_keysapi::authapi::customer_authapi::customer_workflowsmiddlewaremiddleware::api_admin_authmiddleware::authreporepo::api_keysrepo::authrepo::login_attemptsservicesservices::admin_screensservices::api_key_authservices::api_key_scopeservices::customer_authservices::customer_workflowsservices::lockout
flowchart TD n_application_auth["application_auth"] n_application_auth --> n_api["api"] n_api --> n_api__admin_console["admin_console"] n_api --> n_api__api_keys["api_keys"] n_api --> n_api__auth["auth"] n_api --> n_api__customer_auth["customer_auth"] n_api --> n_api__customer_workflows["customer_workflows"] n_application_auth --> n_middleware["middleware"] n_middleware --> n_middleware__api_admin_auth["api_admin_auth"] n_middleware --> n_middleware__auth["auth"] n_application_auth --> n_repo["repo"] n_repo --> n_repo__api_keys["api_keys"] n_repo --> n_repo__auth["auth"] n_repo --> n_repo__login_attempts["login_attempts"] n_application_auth --> n_services["services"] n_services --> n_services__admin_screens["admin_screens"] n_services --> n_services__api_key_auth["api_key_auth"] n_services --> n_services__api_key_scope["api_key_scope"] n_services --> n_services__customer_auth["customer_auth"] n_services --> n_services__customer_workflows["customer_workflows"] n_services --> n_services__lockout["lockout"]
Public surface
`crate root`
| Item | What it is |
|---|---|
async fn seed_admin_user(pool : & PgPool, email : & str, password : & str,) -> Result <bool, sqlx::Error> | Seed an admin user (Sprint 65: lifted from the deleted CmsEngine::seed_admin_user) |
pub struct AuthModule | — |
AuthModule :: fn new() -> Self | — |
AuthModule :: fn name(& self) -> & 'static str | — |
AuthModule :: fn version(& self) -> & 'static str | — |
AuthModule :: fn migrations(& self) -> Vec <MigrationSet> | — |
AuthModule :: async fn migrate_pending(& self, pool : & PgPool) -> std::result::Result <u32, MigrationError> | — |
AuthModule :: fn public_router(& self) -> axum::Router <S> | Auth surfaces use legacy absolute paths (/api/v1/auth/*, /api/v1/keys), encapsulated here as the module's public router; the engine merges at root |
`api`
| Item | What it is |
|---|---|
fn api_keys_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Self-service API-key management router (/api/v1/keys, session-gated). |
fn router_v1 <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Canonical /api/v1/auth/* surface — the staff/customer JSON auth endpoints (login/logout/me/me-permissions). |
`api::admin_console`
| Item | What it is |
|---|---|
fn admin_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Admin-half router |
fn me_router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, identity_user_prefs::LocaleSettings : FromRef <S>, | Profile router |
`api::api_keys`
| Item | What it is |
|---|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Build the session-gated key-management router. |
`api::auth`
| Item | What it is |
|---|---|
pub struct MeResponse | — |
pub struct PermissionsResponse | — |
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Build the JSON auth router (LEGACY shape per Sprint 10B 30-day deprecation alias — D-10B.3) |
fn router_v1 <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Sprint 10B canonical auth surface — routes at /api/v1/auth/* |
`api::customer_auth`
| Item | What it is |
|---|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Customer-side router |
`api::customer_workflows`
| Item | What it is |
|---|---|
fn router <S>() -> Router <S> where S : Clone + Send + Sync + 'static, PgPool : FromRef <S>, | Public customer workflows router |
`middleware::api_admin_auth`
| Item | What it is |
|---|---|
async fn api_admin_auth(State(pool) : State <PgPool>, session : Session, ConnectInfo(peer) : ConnectInfo <SocketAddr>, mut req : Request, next : Next,) -> Response | Global middleware that self-scopes to the staff-API + per-user surfaces on both the legacy un-versioned and the canonical /api/v1/* paths |
`middleware::auth`
| Item | What it is |
|---|---|
pub const SESSION_USER_ID_KEY: & str | Session key holding the logged-in user's id (set at login). |
pub const SESSION_ACTIVE_TENANT_KEY: & str | Session key holding the user's active tenant selection (Sprint 0.55 model D). |
pub const FORCE_PASSWORD_PATH: & str | The first-login forced password-change route — exempt from the must_change_password redirect so the user can actually reach it. |
async fn admin_auth(State(pool) : State <PgPool>, session : Session, ConnectInfo(peer) : ConnectInfo <SocketAddr>, mut req : Request, next : Next,) -> Response | Global middleware layer that self-scopes to the /admin surface. |
`repo::api_keys`
| Item | What it is |
|---|---|
pub struct ApiKeyRow | A persisted API-key row (read shape) |
pub struct VerifiedKey | What a successful verification yields — the inputs the principal resolver needs (owner + bound tenant + granted scopes). |
async fn create(pool : & PgPool, tenant_id : Uuid, owner_id : Uuid, created_by : Uuid, name : & str, scopes : & String, expires_at : Option <DateTime <Utc>>,) -> Result <(Uuid, String), sqlx::Error> | Create a key for owner_id in tenant_id |
async fn list_for_owner(pool : & PgPool, owner_id : Uuid, tenant_id : Uuid,) -> Result <Vec <ApiKeyRow>, sqlx::Error> | List a user's keys within one tenant, newest first |
async fn revoke(pool : & PgPool, id : Uuid, owner_id : Uuid) -> Result <bool, sqlx::Error> | Revoke a key (only the owner's own) |
async fn verify_key(pool : & PgPool, plaintext : & str,) -> Result <Option <VerifiedKey>, sqlx::Error> | Verify a presented plaintext key: O(1) lookup by deterministic SHA-256 hash, requiring the key be active, not revoked, and not expired |
async fn touch_last_used(pool : & PgPool, id : Uuid) -> Result <(), sqlx::Error> | Throttled last_used_at bump — writes only if the stored value is NULL or older than 5 minutes, so a read-heavy key doesn't turn every call into a write (Gate 1.5) |
ApiKeyRow :: fn from(r : ApiKeyRowSql) -> Self | — |
`repo::auth`
| Item | What it is |
|---|---|
pub struct Account | A persisted account — the library crates User plus the app-local display_name and must_change_password columns. |
fn status_str(status : UserStatus) -> & 'static str | The DB string for a UserStatus (users.status is VARCHAR). |
async fn find_account_by_email(pool : & PgPool, email : & str,) -> Result <Option <Account>, sqlx::Error> | Look up an account by email (case-insensitive), live rows only. |
async fn find_account_by_id(pool : & PgPool, id : Uuid) -> Result <Option <Account>, sqlx::Error> | Look up an account by id, live rows only. |
async fn count_accounts(pool : & PgPool) -> Result <i64, sqlx::Error> | Count live accounts — used by the first-boot seed. |
async fn touch_last_login(pool : & PgPool, id : Uuid) -> Result <(), sqlx::Error> | Stamp last_login_at = NOW(). |
async fn create_account <'e, E>(executor : E, user : & User, display_name : & str, must_change_password : bool,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, | Insert a new account |
async fn set_password <'e, E>(executor : E, id : Uuid, new_hash : & str, must_change_password : bool,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, | Replace an account's password hash and set its must_change_password flag (an admin reset sets it true; a self-service change clears it). |
async fn update_display_name <'e, E>(executor : E, id : Uuid, display_name : & str,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, | Update an account's display name. |
async fn update_status <'e, E>(executor : E, id : Uuid, status : UserStatus,) -> Result <(), sqlx::Error> where E : Executor <'e, Database = Postgres>, | Set an account's status (deactivate / reactivate). |
pub struct AccountListRow | A row of the account list (/admin/settings → Accounts) — joined to the account's current role |
async fn list_accounts(pool : & PgPool) -> Result <Vec <AccountListRow>, sqlx::Error> | Every live account with its current role — active first, then by descending role level (deactivated accounts sink to the bottom). |
`repo::login_attempts`
| Item | What it is |
|---|---|
async fn record_attempt(pool : & PgPool, attempt : & LoginAttempt) -> Result <(), sqlx::Error> | Append a login attempt (success or failure) to login_attempts |
async fn recent_failure_counts(pool : & PgPool, ip_address : & str, email : & str, policy : & LockoutPolicy,) -> Result <FailureCounts, sqlx::Error> | Count recent FAILED attempts for each layered key, each over its own window |
`services::admin_screens`
| Item | What it is |
|---|---|
pub enum AdminError | — |
pub struct AuditRow | — |
pub struct AuditFilter | — |
async fn list_audit(pool : & PgPool, filter : AuditFilter, limit : i64,) -> Result <Vec <AuditRow>, AdminError> | — |
pub struct ContactSubmission | — |
pub struct ContactFilter | — |
async fn list_contact(pool : & PgPool, filter : ContactFilter, limit : i64,) -> Result <Vec <ContactSubmission>, AdminError> | — |
pub struct ContactNote | — |
pub struct ContactDetail | — |
async fn contact_detail(pool : & PgPool, id : Uuid) -> Result <Option <ContactDetail>, AdminError> | Per Sprint 10A US-10A.4: full submission + notes thread. |
async fn add_contact_note(pool : & PgPool, submission_id : Uuid, author_id : Uuid, body : String,) -> Result <ContactNote, AdminError> | Per Sprint 10A US-10A.4: add a staff note to a submission. |
async fn mark_contact_read(pool : & PgPool, id : Uuid, actor_id : Uuid) -> Result <(), AdminError> | — |
async fn get_settings(pool : & PgPool) -> Result <serde_json::Value, AdminError> | Return all site_settings columns as a flat JSON object |
async fn update_settings(pool : & PgPool, patch : serde_json::Value, actor_id : Uuid,) -> Result <serde_json::Value, AdminError> | Apply a partial update by treating the patch JSON object as a column → value map |
async fn email_verification_required(pool : & PgPool) -> Result <bool, AdminError> | Read the require_email_verification site setting (Sprint 0.99 Phase 1.1) |
pub struct UserRow | — |
async fn list_users(pool : & PgPool, limit : i64) -> Result <Vec <UserRow>, AdminError> | — |
pub struct InviteUserInput | — |
pub struct InviteResult | Sprint 5 simpler invite: create the user with a random password, assign the role, return the temp password to the operator |
async fn invite_user(pool : & PgPool, input : InviteUserInput, actor_id : Uuid,) -> Result <InviteResult, AdminError> | — |
pub struct RoleRow | — |
async fn list_roles(pool : & PgPool) -> Result <Vec <RoleRow>, AdminError> | — |
pub struct PermissionRow | — |
async fn list_permissions(pool : & PgPool) -> Result <Vec <PermissionRow>, AdminError> | — |
pub struct ProfileResponse | — |
async fn get_profile(pool : & PgPool, user_id : Uuid) -> Result <ProfileResponse, AdminError> | — |
pub struct UpdateProfileInput | — |
async fn update_profile(pool : & PgPool, user_id : Uuid, patch : UpdateProfileInput,) -> Result <ProfileResponse, AdminError> | — |
pub struct ChangePasswordInput | — |
pub struct UpdateEmailInput | Body for PATCH /me/email |
async fn change_email(pool : & PgPool, user_id : Uuid, input : UpdateEmailInput, require_verification : bool,) -> Result <ProfileResponse, AdminError> | Change the session user's login email |
async fn change_password(pool : & PgPool, user_id : Uuid, input : ChangePasswordInput,) -> Result <(), AdminError> | — |
`services::api_key_auth`
| Item | What it is |
|---|---|
pub struct ApiKeyPrincipal | A resolved API-key principal |
async fn authenticate(pool : & PgPool, plaintext : & str,) -> Result <Option <ApiKeyPrincipal>, sqlx::Error> | Authenticate a presented plaintext key |
`services::api_key_scope`
| Item | What it is |
|---|---|
fn parse_bearer(header_value : & str) -> Option <& str> | Extract the sk_-prefixed token from an Authorization header value |
fn effective_permissions(owner_perms : & HashSet <String>, key_scopes : & String,) -> HashSet <String> | Least-privilege intersection: the permissions a key request actually carries |
pub enum ScopeMintError | Why a requested scope set cannot be minted. |
fn scopes_mintable_by(creator_perms : & HashSet <String>, requested_scopes : & String, known_perms : & HashSet <String>,) -> Result <(), ScopeMintError> | Creation guard: a key may only be granted scopes that are (a) real permission codenames and (b) already held by the creator |
`services::customer_auth`
| Item | What it is |
|---|---|
pub enum CustomerAuthError | — |
pub struct SignupInput | — |
pub struct LoginInput | — |
pub struct MeResponse | — |
async fn signup(pool : & PgPool, input : SignupInput) -> Result <(), CustomerAuthError> | Signup |
async fn login(pool : & PgPool, session : & Session, input : LoginInput, client_ip : Option <& str>, user_agent : Option <& str>,) -> Result <MeResponse, CustomerAuthError> | Login |
async fn logout(session : & Session) -> Result <(), CustomerAuthError> | Logout |
async fn me(pool : & PgPool, user_id : Uuid) -> Result <Option <MeResponse>, CustomerAuthError> | Read the current customer's profile |
`services::customer_workflows`
| Item | What it is |
|---|---|
pub enum CustomerError | — |
async fn enqueue_email(pool : & PgPool, template_key : & str, recipient_email : & str, context : serde_json::Value, idempotency_key : Option <& str>,) -> Result <Uuid, CustomerError> | — |
async fn issue_verification_token(pool : & PgPool, user_id : Uuid,) -> Result <String, CustomerError> | — |
async fn verify_email_token(pool : & PgPool, raw_token : & str) -> Result <Uuid, CustomerError> | — |
async fn issue_password_reset_token(pool : & PgPool, email : & str,) -> Result <Option <String>, CustomerError> | — |
async fn consume_password_reset(pool : & PgPool, raw_token : & str, new_password : & str,) -> Result <Uuid, CustomerError> | — |
pub struct InquiryInput | — |
async fn submit_inquiry(pool : & PgPool, input : InquiryInput, user_id : Option <Uuid>, ip : Option <& str>, user_agent : Option <& str>,) -> Result <Uuid, CustomerError> | — |
async fn delete_account(pool : & PgPool, user_id : Uuid) -> Result <(), CustomerError> | — |
`services::lockout`
| Item | What it is |
|---|---|
pub struct LockoutPolicy | Thresholds + sliding windows for the layered brute-force guard |
LockoutPolicy :: fn default() -> Self | — |
pub struct FailureCounts | Recent FAILED-attempt counts, each already counted over its own window by the repo layer |
pub enum LockoutDecision | The guard's verdict for an incoming login attempt. |
LockoutPolicy :: fn evaluate(& self, counts : FailureCounts) -> LockoutDecision | Pure decision: Locked if ANY layered threshold is met or exceeded, else Allow |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
Account | repo::auth::Account |
api_admin_auth | middleware::api_admin_auth::api_admin_auth |
{FORCE_PASSWORD_PATH,SESSION_USER_ID_KEY,admin_auth} | middleware::auth::{FORCE_PASSWORD_PATH,SESSION_USER_ID_KEY,admin_auth} |
{admin_router,me_router} | admin_console::{admin_router,me_router} |
Boundary
Reaches into identity, platform.
Shares tier application with 120 other crates: application-agreements, application-ai, application-analytics, application-approvals, application-assessments, application-audit-log, application-billing, application-browser-automation, … (120 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | application |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/application/auth |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_application["application"] --> n_identity["identity"] n_application["application"] --> n_platform["platform"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `application-audit-log` | application | no | always |
| `application-core` | application | no | always |
| `application-rbac` | application | no | always |
| `identity-auth` | identity | no | always |
| `identity-tenant` | identity | no | always |
| `identity-user-prefs` | identity | no | always |
| `platform-dto` | platform | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
async-trait | ^0.1 | — | no | always |
axum | ^0.7 | multipart | no | always |
chrono | ^0.4 | serde | no | always |
hex | ^0.4 | — | no | always |
rand | ^0.8 | — | no | always |
serde | ^1 | derive | no | always |
serde_json | ^1 | — | no | always |
sha2 | ^0.10 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full | no | always |
tower-sessions | ^0.13 | — | no | always |
tracing | ^0.1 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `application-engine` | application | no | always |
| `application-parties` | application | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
dotenvy | ^0.15 | — | no | always |
Build. None.
Depended on by. 4 workspace crates.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_agreements["application-agreements"] -->|uses| SELF n_application_catalog["application-catalog"] -->|uses| SELF n_application_cli["application-cli"] -->|uses| SELF n_application_cms["application-cms"] -->|uses| SELF SELF["application-auth"] SELF -->|development| n_application_engine["application-engine"] SELF -->|development| n_application_parties["application-parties"] SELF -->|runtime| n_application_audit_log["application-audit-log"] SELF -->|runtime| n_application_core["application-core"] SELF -->|runtime| n_application_rbac["application-rbac"] SELF -->|runtime| n_identity_auth["identity-auth"] SELF -->|runtime| n_identity_tenant["identity-tenant"] SELF -->|runtime| n_identity_user_prefs["identity-user-prefs"] SELF -->|runtime| n_platform_dto["platform-dto"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
postgres | — | no |
flowchart LR n_postgres["postgres"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | application_auth | `src/lib.rs` |
| test | me_email | `tests/me_email.rs` |
| test | pg_forge_auth_migrations | `tests/pg_forge_auth_migrations.rs` |
Error model
| Error type | Named by |
|---|---|
AdminError | add_contact_note, change_email, change_password, contact_detail, email_verification_required, get_profile, … (16 total) |
CustomerAuthError | login, logout, me, signup |
CustomerError | consume_password_reset, delete_account, enqueue_email, issue_password_reset_token, issue_verification_token, submit_inquiry, … (7 total) |
ScopeMintError | scopes_mintable_by |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | yes |
| database access | yes |
| network I/O | yes |
| unsafe code | none detected |
| environment variables | yes |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
| Variable | Read in |
|---|---|
CARGO_PKG_VERSION | src/lib.rs |
INQUIRY_OPERATOR_EMAIL | src/api/customer_workflows.rs |
TRUST_PROXY | src/middleware/auth.rs |
Related capabilities
4 workspace crates depend on this one: application-agreements, application-catalog, application-cli, application-cms.
Verification
| Kind | Count |
|---|---|
| Unit tests | 25 |
| Integration tests | 9 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 2 | 0 | 1 |
api | 2 | 0 | 0 |
api::admin_console | 2 | 0 | 3 |
api::api_keys | 1 | 0 | 3 |
api::auth | 4 | 0 | 3 |
api::customer_auth | 1 | 0 | 3 |
api::customer_workflows | 1 | 0 | 3 |
middleware::api_admin_auth | 1 | 0 | 1 |
middleware::auth | 4 | 0 | 3 |
repo::api_keys | 7 | 0 | 5 |
repo::auth | 12 | 0 | 4 |
repo::login_attempts | 2 | 0 | 0 |
services::admin_screens | 32 | 0 | 1 |
services::api_key_auth | 2 | 0 | 0 |
services::api_key_scope | 4 | 0 | 0 |
services::customer_auth | 8 | 0 | 4 |
services::customer_workflows | 9 | 0 | 0 |
services::lockout | 3 | 0 | 0 |
What the tests establish, by name:
dto_has_no_user_id_field—tests/me_email.rsduplicate_email_conflicts—tests/me_email.rsemail_verification_required_reads_the_setting—tests/me_email.rsgate_on_stages_pending_email_and_keeps_identity_stable—tests/me_email.rshappy_path_gate_off_updates_email_immediately—tests/me_email.rsmalformed_email_is_rejected—tests/me_email.rsupdate_settings_accepts_require_email_verification—tests/me_email.rswrong_current_password_is_rejected_and_no_change—tests/me_email.rsmigrate_pending_creates_users_sessions_login_attempts_and_api_keys_tables—tests/pg_forge_auth_migrations.rstest_module_migrations_non_empty—src/lib.rsfail_closed_to_peer_on_short_chain—src/middleware/auth.rsforged_xff_victim_ip_ignored_when_untrusted—src/middleware/auth.rsno_xff_uses_peer—src/middleware/auth.rstrusted_proxy_attributes_real_client_despite_rotation—src/middleware/auth.rsxff_rotation_does_not_reset_attributed_ip_when_untrusted—src/middleware/auth.rsgate_is_off_by_default_and_a_pure_passthrough—src/services/admin_screens.rsplausible_email_accepts_valid_shapes—src/services/admin_screens.rsplausible_email_rejects_broken_shapes—src/services/admin_screens.rseffective_is_owner_intersect_scopes—src/services/api_key_scope.rsempty_scopes_grant_nothing—src/services/api_key_scope.rsmint_ok_when_all_scopes_known_and_held—src/services/api_key_scope.rsmint_rejects_scope_creator_lacks—src/services/api_key_scope.rsmint_rejects_unknown_scope—src/services/api_key_scope.rsmint_unknown_takes_precedence_and_is_deterministic—src/services/api_key_scope.rsparse_bearer_accepts_valid_sk_token—src/services/api_key_scope.rsparse_bearer_rejects_non_bearer_and_non_sk_and_malformed—src/services/api_key_scope.rsscopes_never_exceed_owner—src/services/api_key_scope.rsabove_threshold_stays_locked—src/services/lockout.rsdefaults_match_gate_1_5_consensus—src/services/lockout.rsemail_layer_trips_independently—src/services/lockout.rs- _… 4 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 59 | 106 |
Public modules with a //! block | 20 | 20 |
pie showData
title Public items with rustdoc
"Documented" : 59
"No rustdoc detected" : 47
Metrics
| Metric | Value |
|---|---|
| Rust source files | 21 |
| Source lines | 4834 |
| Code lines | 3736 |
| Public API items | 106 |
| Public modules | 20 |
| Tests | 34 |
| Examples | 0 |
| Cargo features | 1 |
| Direct runtime dependencies | 21 |
| Workspace reverse dependencies | 4 |
pie showData
title Public API by kind
"constant" : 3
"enum" : 5
"function" : 60
"method" : 9
"struct" : 29
pie showData
title Rust source composition
"Code" : 3736
"Blank or comment" : 1098
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.