# How Does the Authorization Module Work with Akash's Custom Modules?

> Understand how Akash's custom modules integrate with the Cosmos SDK x/authz module to manage scoped spending permissions and automate deposit validation for efficient payments and cleanup.

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

---

**Akash's custom modules integrate with the Cosmos SDK `x/authz` module through a thin `AuthzKeeper` wrapper interface that delegates scoped spending permissions via custom `DepositAuthorization` grants, enabling automated deposit validation, consumption during payments, and cleanup on account closure.**

The `akash-network/node` repository implements a sophisticated authorization pattern that allows the **Escrow**, **Deployment**, and **Market** modules to leverage Cosmos SDK's granular permission system without direct dependencies on the underlying `x/authz` keeper. This architecture uses a custom authorization type to manage deposit flows while maintaining clean module boundaries.

## Architectural Overview of Authz Integration

Akash's authorization architecture centers on a wrapper interface that isolates custom modules from the Cosmos SDK's concrete implementation. This design enables the system to grant time-bound, spend-limited permissions that are automatically validated during deployment creation and consumed during payment processing.

### The AuthzKeeper Interface Abstraction

The `AuthzKeeper` interface defined in [`x/escrow/keeper/external.go`](https://github.com/akash-network/node/blob/main/x/escrow/keeper/external.go) provides the contract between Akash's custom modules and the Cosmos authorization system:

```go
type AuthzKeeper interface {
    DeleteGrant(ctx context.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) error
    GetAuthorization(ctx context.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (authz.Authorization, *time.Time)
    SaveGrant(ctx context.Context, grantee sdk.AccAddress, granter sdk.AccAddress, authorization authz.Authorization, expiration *time.Time) error
    IterateGrants(ctx context.Context, handler func(granterAddr sdk.AccAddress, granteeAddr sdk.AccAddress, grant authz.Grant) bool)
    GetGranteeGrantsByMsgType(ctx context.Context, grantee sdk.AccAddress, msgType string, onGrant authzkeeper.OnGrantFn)
}

```

This abstraction allows the **Escrow** module to remain agnostic of the concrete `x/authz` keeper implementation while supporting mock implementations for unit testing.

### Custom DepositAuthorization Grant Type

The system utilizes a custom authorization type located in `pkg/akt.dev/go/node/escrow/v1`. The `DepositAuthorization` implements the `authz.Authorization` interface and carries:

- A **spend limit** (`sdk.Coins`) defining the maximum transferable amount
- A **scope** identifier (`DepositScopeDeployment`, `DepositScopeMarket`, etc.) restricting usage to specific module contexts
- The `TryAccept` method that validates and consumes partial grants during payment processing

## Authorization Flow Across Custom Modules

The integration follows a distinct lifecycle: grants are created during deployment initialization, consumed incrementally during payment withdrawals, and revoked when resources are decommissioned.

### Step 1: Deployment Creation and Deposit Authorization

When a user creates a deployment via `CreateDeployment` in [`x/deployment/handler/server.go`](https://github.com/akash-network/node/blob/main/x/deployment/handler/server.go), the system delegates deposit validation to the escrow module:

```go
// x/deployment/handler/server.go – CreateDeployment handler
deposits, err := ms.escrow.AuthorizeDeposits(ctx, msg) // authz validation occurs here
if err != nil {
    return nil, err
}
...
if err := ms.escrow.AccountCreate(ctx, deployment.ID.ToEscrowAccountID(), owner, deposits); err != nil {
    return &types.MsgCreateDeploymentResponse{}, err
}

```

The `AuthorizeDeposits` function in [`x/escrow/keeper/keeper.go`](https://github.com/akash-network/node/blob/main/x/escrow/keeper/keeper.go) examines each deposit source. For `SourceBalance`, it verifies the owner's spendable coins. For `SourceAuthz`, it queries existing grants via `GetAuthorization` and may create new grants via `SaveGrant`:

```go
// x/escrow/keeper/keeper.go – AuthorizeDeposits logic
for _, source := range dep.Sources {
    switch source {
    case deposit.SourceBalance:
        // Verify direct spendable balance
    case deposit.SourceAuthz:
        // Fetch or create authz grant
        authz, _ := k.authzKeeper.GetAuthorization(sctx, owner, granter, ev1.MsgTypeDeposit)
        if authz == nil {
            newAuthz := ev1.NewDepositAuthorization(
                ev1.DepositAuthorizationScopes{ev1.DepositScopeDeployment}, 
                spendable,
            )
            k.authzKeeper.SaveGrant(sctx, owner, granter, newAuthz, nil)
        }
    }
}

```

### Step 2: Payment Processing and Grant Consumption

During payment withdrawal, the escrow keeper retrieves the authorization, validates the remaining spend limit, and atomically updates the grant. The `TryAccept` method handles partial consumption logic:

```go
// x/escrow/keeper/keeper.go – PaymentWithdraw excerpt
authz, exp := k.authzKeeper.GetAuthorization(ctx, owner, granter, ev1.MsgTypeDeposit)
depositAuthz, ok := authz.(ev1.Authorization)
if !ok { 
    return fmt.Errorf("invalid authz type") 
}

resp, err := depositAuthz.TryAccept(ctx, msg, true) // Reduces SpendLimit
if err != nil { 
    return err 
}

k.authzKeeper.SaveGrant(ctx, owner, granter, resp.Updated, exp) // Persist remaining allowance

```

This ensures that delegated permissions are decrementally consumed as providers withdraw payments, preventing over-spending beyond the original grant.

### Step 3: Account Closure and Permission Cleanup

When a deployment closes or an account terminates, the system must revoke lingering permissions to prevent stale access. The `AccountClose` function in [`x/escrow/keeper/keeper.go`](https://github.com/akash-network/node/blob/main/x/escrow/keeper/keeper.go) calls `DeleteGrant` to remove the authorization:

```go
// x/escrow/keeper/keeper.go – AccountClose
if err := k.authzKeeper.DeleteGrant(ctx, owner, granter, ev1.MsgTypeDeposit); err != nil {
    return err
}

```

This cleanup guarantees that closed deployments cannot incur future charges against the owner's delegated balances.

## Handling Authorization During Chain Upgrades

The [`upgrades/software/v1.0.0/upgrade.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.0.0/upgrade.go) file contains migration logic that iterates over existing authz grants, replacing outdated `DepositAuthorization` schemas with updated versions. This ensures that delegated permissions remain valid across protocol upgrades without requiring users to re-authorize manually.

The upgrade handler uses `IterateGrants` to locate all escrow-related authorizations and `SaveGrant` to persist the migrated structures with updated type URLs and scope definitions.

## Summary

- **AuthzKeeper Interface**: A thin wrapper in [`x/escrow/keeper/external.go`](https://github.com/akash-network/node/blob/main/x/escrow/keeper/external.go) abstracts the Cosmos SDK `x/authz` module, enabling clean dependency injection and testing.
- **DepositAuthorization**: A custom grant type in `pkg/akt.dev/go/node/escrow/v1` that carries spend limits and scopes, implementing `TryAccept` for partial consumption.
- **Automatic Grant Lifecycle**: Deployments trigger `AuthorizeDeposits` to validate or create grants, payments consume them via `GetAuthorization` and `SaveGrant`, and closures invoke `DeleteGrant` for cleanup.
- **Upgrade Compatibility**: The v1.0.0 upgrade handler migrates legacy authorization schemas to maintain grant validity across chain upgrades.

## Frequently Asked Questions

### How does the Deployment module verify deposits without direct authz dependencies?

The Deployment module delegates all deposit validation to the Escrow module's `AuthorizeDeposits` function. This function acts as the single integration point with the `AuthzKeeper` interface, checking whether the deposit source is the owner's direct balance (`SourceBalance`) or an existing authorization grant (`SourceAuthz`).

### What happens to unused authorization grants when a deployment closes?

The Escrow keeper's `AccountClose` function automatically invokes `DeleteGrant` on the `AuthzKeeper` interface, immediately revoking the `DepositAuthorization` associated with the deployment. This prevents any future withdrawals against the owner's account using that specific grant.

### Can authorization grants be partially consumed across multiple payments?

Yes. The `DepositAuthorization` type implements the `TryAccept` method, which validates the requested amount against the remaining `SpendLimit` and returns an updated authorization with the reduced balance. The escrow keeper saves this updated grant via `SaveGrant`, allowing the remaining allowance to be used for future payments until fully exhausted.

### Where is the authorization logic configured during application startup?

The concrete Cosmos SDK `authz` keeper is injected into the Escrow module via the `AuthzKeeper` interface during app initialization in [`app/types/app.go`](https://github.com/akash-network/node/blob/main/app/types/app.go). This wiring occurs around lines 281-283, where the application sets `app.Keepers.Cosmos.Authz` and passes it to the escrow keeper constructor.