Skip to content

What is aoothjs?

aoothjs is the authentication and authorization stack for the moost + atscript ecosystem. It ships six packages that split cleanly across two concerns — who you are (authn) and what you can do (authz) — and two integration layers — framework-agnostic core and moost glue.

This page sketches the shape of the stack and points you at the right package for each problem. When you are ready to write code, jump to Quick Start or Installation.

The 2x3 matrix

                  ┌────────────────────────────────┬─────────────────────────────────┐
                  │  Authentication (who)          │  Authorization (what)           │
┌─────────────────┼────────────────────────────────┼─────────────────────────────────┤
│  Core           │  @aooth/user                 │  @aooth/arbac-core            │
│  (no framework) │  @aooth/auth                 │  @aooth/arbac                 │
├─────────────────┼────────────────────────────────┼─────────────────────────────────┤
│  Moost glue     │  @aooth/auth-moost           │  @aooth/arbac-moost           │
└─────────────────┴────────────────────────────────┴─────────────────────────────────┘

@aooth/arbac is a thin builder + privilege-factory layer on top of @aooth/arbac-core. The other four packages have no internal split — *-moost packages depend on their core counterpart.

What each package owns

PackageConcernOwns
@aooth/userauthnCredential CRUD, password hashing (scrypt+pepper), password policies, TOTP/MFA primitives, lockout, trusted devices, pluggable UserStore.
@aooth/authauthnIssue/validate/refresh/revoke bearer credentials (sessions or JWT), refresh rotation with reuse detection, magic-link tokens, email/SMS contracts.
@aooth/arbac-coreauthzZero-dep RBAC evaluator — TArbacRole, Arbac.evaluate(), deny-wins, wildcard matching, dynamic scopes.
@aooth/arbacauthzFluent defineRole() builder, definePrivilege() + allowTable* factories, scope-merge helpers, type codegen.
@aooth/auth-moostauthn / moostAuthController, authGuardInterceptor, LoginWorkflow / RecoveryWorkflow / InviteWorkflow, @Public, @UserId, useAuth.
@aooth/arbac-moostauthz / moostarbacAuthorizeInterceptor, @ArbacResource / @ArbacAction, useArbac, AtscriptArbacUserProvider.

How they compose at runtime

A logged-in request to GET /tasks/:id walks the stack like this:

 HTTP request

     │  Bearer token / aooth_session cookie

 ┌─────────────────────────────────────────────────────────────┐
 │  authGuardInterceptor          (@aooth/auth-moost)        │
 │   └─ uses AuthCredential.validate()  (@aooth/auth)        │
 │        └─ JWT / Memory / Redis / atscript-db store          │
 └────────────────────┬────────────────────────────────────────┘
                      │ AuthContext { userId, claims }

 ┌─────────────────────────────────────────────────────────────┐
 │  arbacAuthorizeInterceptor     (@aooth/arbac-moost)       │
 │   └─ resolves @ArbacResource / @ArbacAction                 │
 │   └─ uses Arbac.evaluate(user, request)  (arbac-core)       │
 │        └─ user fetched via AtscriptArbacUserProvider        │
 │             └─ reads @arbac.role + @arbac.attribute        │
 └────────────────────┬────────────────────────────────────────┘
                      │ scopes set on event

                  handler runs
                  useArbac().getScopes()  →  apply to DB query

The two interceptors are independent — the auth guard never returns 403, and the arbac interceptor never returns 401. You can wire either one alone.

Why two layers (core vs moost)

Every *-moost package adapts a framework-agnostic core into moost's event chain — interceptors, decorators, DI tokens, the useAuth / useArbac composables. If your runtime is not moost (@wooksjs/event-cli, a bare HTTP server, a job worker), you stop at the core packages:

  • @aooth/user + @aooth/auth is a complete bearer-credential stack with no HTTP dependency.
  • @aooth/arbac + @aooth/arbac-core is a pure RBAC evaluator.

When you do use moost, the *-moost packages are the only places that touch @moostjs/event-http, defineBeforeInterceptor, or getMoostInfact. The split is deliberate — non-HTTP consumers should not pay for the HTTP integration.

The atscript line

aoothjs is designed to be driven from .as annotated types:

  • @aooth/user/atscript-db/model.as ships AoothUserCredentials — the base interface with username, password, account, mfa, trustedDevices.
  • @aooth/arbac-moost/atscript/models.as ships AoothArbacUserCredentials — extends AoothUserCredentials with @arbac.role roles: string[].
  • @aooth/auth/atscript-db/model.as ships AoothAuthCredential — the bearer-token row.

You extend them in your app's .as files with @meta.id, @db.table, and any custom columns (tenantId, departmentId, ...). syncSchema() materialises the tables. AtscriptArbacUserProvider reads the same annotations to compute the user's roles and attributes at request time.

See Using atscript-db Models.

When to use which package

Decision shortcut

Next steps

Released under the MIT License.