# What Is CASL and How It Powers Authorization in Akash Console

> Discover how CASL powers authorization in Akash Console. Learn about declarative JavaScript, role-based access control, and compile-time rules for robust security.

- Repository: [Akash Network/console](https://github.com/akash-network/console)
- Tags: deep-dive
- Published: 2026-02-24

---

**CASL is a declarative JavaScript authorization library that Akash Console uses to enforce role-based access control through compile-time rules, runtime permission checks, and automatic SQL query filtering.**

CASL (**C**an **A**ccess **S**ome **L**ibrary) is an isomorphic authorization library that lets developers define what actions users can perform on domain objects through simple, declarative rules. The `akash-network/console` repository implements CASL to enforce granular, role-based access control across its API layer and data access tier. This approach unifies business logic authorization with database query filtering, ensuring consistent permission checks throughout the application stack.

## Core Concepts of CASL Authorization

CASL operates on the concept of **abilities**—rules that specify which *actions* (e.g., `create`, `read`, `delete`) a user can perform on which *subjects* (domain objects like `Deployment` or `UserWallet`) under specific *conditions* (e.g., `userId: "${user.id}"`). These rules are compiled into a `MongoAbility` instance that can be queried at runtime or transformed into database predicates.

## Five Layers of CASL Implementation in Akash Console

Akash Console integrates CASL through five distinct architectural layers, each handling a specific phase of the authorization lifecycle.

### 1. Centralized Rule Definitions in AbilityService

Static role-based rules are declared as raw CASL rules and compiled using a lodash template. In [`apps/api/src/auth/services/ability/ability.service.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/ability/ability.service.ts), the `AbilityService` class maintains a `RULES` map for three distinct roles: **REGULAR_USER**, **REGULAR_PAYING_USER**, and **SUPER_USER**. These raw rules define permissible actions and subject-specific conditions, then get compiled into a Mongo-style ability via `createMongoAbility`.

### 2. Dynamic Ability Compilation Per Request

For every incoming request, `AbilityService#getAbilityFor` (lines 54-57) compiles the static rule template with the current user’s dynamic data—such as their specific `userId`—and returns a ready-to-use `Ability` instance tailored to that user’s session.

### 3. Execution Context Storage via AuthInterceptor

The generated ability must persist throughout the request lifecycle. In [`apps/api/src/auth/services/auth.interceptor.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/auth.interceptor.ts) (lines 90-97), the `AuthInterceptor` authenticates the user via JWT or API key, obtains the `UserOutput`, determines the appropriate role, and injects the compiled ability into `AuthService` for downstream consumption.

### 4. Runtime Enforcement with throwUnlessCan and the Protected Decorator

Business logic enforces permissions through `AuthService#throwUnlessCan` (lines 60-63), which invokes CASL’s `ability.can` method and throws a 403 `ForbiddenError` when checks fail. For declarative route protection, the `Protected` decorator (defined in [`apps/api/src/auth/services/auth.service.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/auth.service.ts), lines 66-79) extracts the injected ability and runs `throwUnlessCan` before the controller method executes.

### 5. SQL Query Filtering with DrizzleAbility

To prevent unauthorized data exposure at the database layer, `DrizzleAbility` in [`apps/api/src/lib/drizzle-ability/drizzle-ability.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/lib/drizzle-ability/drizzle-ability.ts) transforms CASL’s abstract syntax tree (AST) into SQL `WHERE` clauses. The `whereAccessibleBy` method (lines 44-47) generates `drizzle-orm` conditions that automatically filter queries to return only rows the user is permitted to access.

## End-to-End Authorization Flow

The complete authorization lifecycle in Akash Console follows this sequence:

1. An incoming request triggers the `AuthInterceptor`, which validates the user’s JWT or API key.
2. The interceptor calls `AbilityService.getAbilityFor(role, user)` to compile role-specific rules with the user’s unique identifiers, producing a **MongoAbility** instance.
3. The ability is stored in `AuthService` (`this.authService.ability`), making it available to all downstream services.
4. Controllers use the `@Protected([...])` decorator or services call `authService.throwUnlessCan(action, subject, conditions)` to validate permissions; CASL evaluates the rule tree and throws a 403 if access is denied.
5. When repositories query the database, they instantiate `DrizzleAbility` with the current ability and call `whereAccessibleBy` to append CASL-derived `WHERE` clauses, ensuring only accessible rows are returned.

## Practical Code Examples from the Source

### Defining Role-Based Rules

The following excerpt from [`apps/api/src/auth/services/ability/ability.service.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/ability/ability.service.ts) shows how static rules are declared for different user tiers:

```typescript
private readonly RULES: Record<Role, Array<RawRule & { enabledIf?: FeatureFlagValue }>> = {
  REGULAR_USER: [
    { action: ["create", "read", "sign"], subject: "UserWallet", conditions: { userId: "${user.id}" } },
    { action: "manage", subject: "WalletSetting", conditions: { userId: "${user.id}" } },
    // …additional rules
  ],
  REGULAR_PAYING_USER: [ /* same as REGULAR_USER plus extra privileges */ ],
  SUPER_USER: [{ action: "manage", subject: "all" }]
};

```

### Creating a Request-Specific Ability

Inside [`apps/api/src/auth/services/auth.interceptor.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/auth.interceptor.ts), the interceptor binds the compiled ability to the request context:

```typescript
if (user) {
  const role = this.getUserRole(user);
  this.authService.ability = this.abilityService.getAbilityFor(role, user);
}

```

### Enforcing Permissions in Services

Services validate operations before execution by calling `throwUnlessCan`:

```typescript
this.authService.throwUnlessCan('delete', 'Alert', { userId: currentUser.id });

```

### Protecting Controller Routes

The `@Protected` decorator provides declarative guards on API endpoints:

```typescript
@Protected([{ action: 'manage', subject: 'DeploymentSetting' }])
async updateSetting(@Body() dto: UpdateDto) {
  // Handler executes only if the user can manage DeploymentSettings
}

```

### Filtering Database Queries

Repositories use `DrizzleAbility` to apply authorization logic directly to SQL generation:

```typescript
const ability = this.authService.ability;
const drizzle = new DrizzleAbility(deploymentsTable, ability, 'read', 'Deployment');
const where = drizzle.whereAccessibleBy();
return db.select().from(deploymentsTable).where(where);

```

## Summary

- **CASL provides a single source of truth** for both business logic checks and database filtering in Akash Console, eliminating authorization drift between layers.
- **Declarative rules** defined in `AbilityService` use lodash templates to inject user-specific conditions into static role definitions.
- **Per-request abilities** are compiled, stored in execution context via `AuthInterceptor`, and enforced through `throwUnlessCan` or the `@Protected` decorator.
- **DrizzleAbility** bridges CASL’s declarative rules with SQL generation, automatically filtering queries to return only permitted rows.
- The architecture supports three distinct roles—`REGULAR_USER`, `REGULAR_PAYING_USER`, and `SUPER_USER`—with escalating privileges managed through a unified rule set.

## Frequently Asked Questions

### What does CASL stand for and why did Akash Console choose it?

CASL stands for **C**an **A**ccess **S**ome **L**ibrary. Akash Console selected CASL because its isomorphic, declarative API allows the same authorization rules to be defined once and applied consistently across both runtime permission checks and database query construction, reducing code duplication and security vulnerabilities.

### How does Akash Console convert CASL rules into SQL WHERE clauses?

The conversion happens in [`apps/api/src/lib/drizzle-ability/drizzle-ability.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/lib/drizzle-ability/drizzle-ability.ts). The `DrizzleAbility` class parses the CASL ability’s abstract syntax tree and translates conditions into `drizzle-orm` predicates via the `whereAccessibleBy` method. This allows the ORM to generate SQL that filters out rows the user cannot access before they ever leave the database.

### What are the three user roles defined in the Akash Console CASL configuration?

The `AbilityService` defines rules for **REGULAR_USER**, **REGULAR_PAYING_USER**, and **SUPER_USER**. Regular users can manage their own wallets and settings, paying users receive additional privileges, and super users possess `manage` permissions over all subjects without restriction.

### How does the @Protected decorator work with CASL abilities?

The `@Protected` decorator, implemented in [`apps/api/src/auth/services/auth.service.ts`](https://github.com/akash-network/console/blob/main/apps/api/src/auth/services/auth.service.ts), extracts the CASL ability stored in `AuthService` by the interceptor. Before the decorated controller method runs, it validates the user’s permissions against the declared rules using `throwUnlessCan`. If the check fails, it immediately returns an HTTP 403 Forbidden response, preventing unauthorized business logic execution.