diff --git a/docs/build/smart-contracts/example-contracts/complex-account.mdx b/docs/build/smart-contracts/example-contracts/complex-account.mdx
index ff33f67ec..4030ca01c 100644
--- a/docs/build/smart-contracts/example-contracts/complex-account.mdx
+++ b/docs/build/smart-contracts/example-contracts/complex-account.mdx
@@ -453,3 +453,7 @@ assert_eq!(
AccError::NotEnoughSigners
);
```
+
+## Further Reading
+
+- [Delegate Auth example](./delegate-auth.mdx) — extends this example with CAP-71 auth delegation to registered delegate signers.
diff --git a/docs/build/smart-contracts/example-contracts/delegate-auth.mdx b/docs/build/smart-contracts/example-contracts/delegate-auth.mdx
new file mode 100644
index 000000000..5f449f9ea
--- /dev/null
+++ b/docs/build/smart-contracts/example-contracts/delegate-auth.mdx
@@ -0,0 +1,276 @@
+---
+title: Delegate Auth
+sidebar_label: Delegate Auth
+description: A custom account contract that uses CAP-71 auth delegation to forward __check_auth to registered delegate signers.
+sidebar_position: 18
+---
+
+
+ Delegate Auth
+
+
+
+
+
+This example shows **auth delegation**: a `ModularAccount` contract performs no signature verification itself. Instead, it stores a set of registered signer addresses and, when `__check_auth` is called, forwards the authorization context to whichever of those signers the user attached to the transaction. Each delegate runs its own `__check_auth` independently.
+
+Auth delegation was introduced in soroban-sdk v27 via [CAP-71](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0071.md). For a single-key account see the [Simple Account example](./simple-account.mdx), and for a multi-sig account with spend-limit policies see the [Complex Account example](./complex-account.mdx).
+
+:::danger
+
+Implementing a contract account requires a very good understanding of authentication and authorization and requires rigorous testing and review. The example here is _not_ a full-fledged account contract — use it as an API reference only.
+
+:::
+
+:::caution
+
+While contract accounts are supported by the Stellar protocol and Soroban SDK, the full client support (such as transaction simulation) is still under development.
+
+:::
+
+[][open-in-github-codespaces]
+
+[][open-in-code-anywhere]
+
+[open-in-github-codespaces]: https://github.com/codespaces/new?repo=stellar/soroban-examples&editor=web
+[open-in-code-anywhere]: https://app.codeanywhere.com/#https://github.com/stellar/soroban-examples
+
+## Run the Example
+
+1. Finish the [Setup] checklist to install the Stellar CLI, Rust target, and required environment variables.
+2. Clone the `soroban-examples` repository:
+
+```sh
+git clone https://github.com/stellar/soroban-examples
+```
+
+3. Run the tests from the `modular_account` directory:
+
+```sh
+cd modular_account
+make test
+```
+
+Expected output:
+
+```
+running 1 test
+test test::test ... ok
+```
+
+[setup]: ../getting-started/setup.mdx
+
+## Code
+
+```rust title="modular_account/src/lib.rs"
+#![no_std]
+
+use soroban_sdk::{
+ auth::{Context, CustomAccountInterface},
+ contract, contracterror, contractimpl, contracttype,
+ crypto::Hash,
+ Address, Env, Vec,
+};
+
+#[contracterror]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u32)]
+pub enum Error {
+ UnknownDelegate = 1,
+}
+
+#[contracttype]
+enum ModularAccountDataKey {
+ // Marks an address as a signer allowed to authenticate for the
+ // modular account.
+ Signer(Address),
+}
+
+#[contract]
+pub struct ModularAccount;
+
+#[contractimpl]
+impl ModularAccount {
+ // Registers the addresses allowed to authenticate for this account.
+ pub fn __constructor(env: Env, signers: Vec) {
+ for signer in signers.iter() {
+ env.storage()
+ .persistent()
+ .set(&ModularAccountDataKey::Signer(signer), &());
+ }
+ }
+}
+
+#[contractimpl]
+impl CustomAccountInterface for ModularAccount {
+ // The account verifies no signature of its own, so it carries no
+ // signature to check.
+ type Signature = ();
+ type Error = Error;
+
+ fn __check_auth(
+ env: Env,
+ _signature_payload: Hash<32>,
+ _signatures: (),
+ _auth_contexts: Vec,
+ ) -> Result<(), Error> {
+ // The signers the user attached to the auth entry for this
+ // account's authorization.
+ let delegates = env.custom_account().get_delegated_signers();
+
+ // With no delegates to forward to, the account would authenticate
+ // nothing and be effectively unauthenticated, so reject it.
+ if delegates.is_empty() {
+ return Err(Error::UnknownDelegate);
+ }
+
+ // Check if the delegates are accepted by the modular account.
+ for delegate in delegates.iter() {
+ if !env
+ .storage()
+ .persistent()
+ .has(&ModularAccountDataKey::Signer(delegate.clone()))
+ {
+ return Err(Error::UnknownDelegate);
+ }
+ }
+
+ // Forward the current authorization to each delegate.
+ for delegate in delegates.iter() {
+ env.custom_account().delegate_auth(&delegate);
+ }
+
+ Ok(())
+ }
+}
+
+mod test;
+```
+
+## How it Works
+
+### Storage layout
+
+`ModularAccountDataKey::Signer(Address)` uses one persistent storage entry per allowed signer. Using a per-key entry makes registration and revocation O(1) lookups rather than scanning a list. The `()` value signals presence.
+
+### Constructor
+
+```rust
+pub fn __constructor(env: Env, signers: Vec) {
+ for signer in signers.iter() {
+ env.storage()
+ .persistent()
+ .set(&ModularAccountDataKey::Signer(signer), &());
+ }
+}
+```
+
+Each allowed delegate address is persisted individually at deployment. A production account would also expose an admin function to add or remove signers after deployment.
+
+### `type Signature = ()`
+
+```rust
+type Signature = ();
+```
+
+`ModularAccount` verifies no signature of its own — it relies entirely on its delegates. Setting `Signature = ()` tells the Soroban host that no signature data needs to be passed to `__check_auth`. The user's wallet still builds a full `SorobanAddressCredentialsWithDelegates` auth entry (see the test), but the account-level signature field is empty.
+
+### `__check_auth`: get → verify → forward
+
+```rust
+let delegates = env.custom_account().get_delegated_signers();
+
+if delegates.is_empty() {
+ return Err(Error::UnknownDelegate);
+}
+
+for delegate in delegates.iter() {
+ if !env.storage().persistent().has(&ModularAccountDataKey::Signer(delegate.clone())) {
+ return Err(Error::UnknownDelegate);
+ }
+}
+
+for delegate in delegates.iter() {
+ env.custom_account().delegate_auth(&delegate);
+}
+```
+
+Two methods on `env.custom_account()` drive delegation. Both may only be called from within `__check_auth`; calling either outside of it panics.
+
+- **`get_delegated_signers() -> Vec`** returns the delegate addresses the user attached to the transaction's auth entry. These are unsanitized user input — the contract must verify each one is registered before forwarding.
+- **`delegate_auth(&address)`** forwards the current `__check_auth` authorization context to `address`. Unlike `require_auth`, this does not start a new contract invocation and does not require a separate auth entry for the delegate in the transaction. Delegation is nestable: a delegate may further delegate.
+
+The example first rejects an empty delegate list — since the account verifies no signature of its own, forwarding to nobody would leave it effectively unauthenticated. It then makes two passes: first it validates all delegates, then it forwards to each. This ensures that an invalid delegate causes the whole check to fail before any forwarding occurs.
+
+## Tests
+
+Open [`modular_account/src/test.rs`][test-rs]. The test defines two helper contracts:
+
+[test-rs]: https://github.com/stellar/soroban-examples/tree/main/modular_account/src/test.rs
+
+- **`DelegateAccount`** — a simple custom account with `type Signature = ()` that always approves, and stores the received `auth_contexts` in instance storage for later assertion.
+- **`Protected`** — a contract with one function that calls `account.require_auth()`.
+
+The test registers one `ModularAccount` with one `DelegateAccount` as its allowed signer, builds an `AddressWithDelegates` auth entry by hand, and calls `Protected::protected`:
+
+```rust
+env.set_auths(&[SorobanAuthorizationEntry {
+ credentials: SorobanCredentials::AddressWithDelegates(
+ SorobanAddressCredentialsWithDelegates {
+ address_credentials: SorobanAddressCredentials {
+ address: account_addr.clone(),
+ nonce: 1,
+ signature_expiration_ledger: 100,
+ // The account verifies no signature of its own.
+ signature: ScVal::Void,
+ },
+ delegates: std::vec![SorobanDelegateSignature {
+ address: delegate_addr,
+ signature: ScVal::Void,
+ nested_delegates: VecM::default(),
+ }]
+ .try_into()
+ .unwrap(),
+ },
+ ),
+ root_invocation: SorobanAuthorizedInvocation { /* ... */ },
+}]);
+
+ProtectedClient::new(&env, &protected).protected(&account);
+```
+
+After the call, the test asserts two things:
+
+1. `env.auths()` shows only the account authorizing `protected` — delegating to `DelegateAccount` is not recorded as a separate top-level authorization.
+2. `DelegateAccount`'s `ApprovedContexts` storage contains the same contract context, confirming the delegation actually reached it.
+
+:::note
+
+Testing delegated auth via `env.try_invoke_contract_check_auth` is not supported. Use `env.set_auths` with `SorobanAddressCredentialsWithDelegates` and a wrapper contract call instead, as shown in the test.
+
+:::
+
+## Build the Contract
+
+```sh
+stellar contract build
+```
+
+A `.wasm` file will be output in the `target` directory:
+
+```
+target/wasm32v1-none/release/soroban_modular_account_contract.wasm
+```
+
+## Further Reading
+
+- [Simple Account example](./simple-account.mdx) — the minimal single-key baseline.
+- [Complex Account example](./complex-account.mdx) — multisig and spend-limit policies.
+- [CAP-71 specification](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0071.md) — the protocol change that introduced auth delegation.
+- [`CustomAccount` API docs](https://docs.rs/soroban-sdk/latest/soroban_sdk/custom_account/struct.CustomAccount.html) — reference for `get_delegated_signers` and `delegate_auth`.
diff --git a/routes.txt b/routes.txt
index dc4813f77..afe489e60 100644
--- a/routes.txt
+++ b/routes.txt
@@ -165,6 +165,7 @@
/docs/build/smart-contracts/example-contracts/complex-account
/docs/build/smart-contracts/example-contracts/cross-contract-call
/docs/build/smart-contracts/example-contracts/custom-types
+/docs/build/smart-contracts/example-contracts/delegate-auth
/docs/build/smart-contracts/example-contracts/deployer
/docs/build/smart-contracts/example-contracts/errors
/docs/build/smart-contracts/example-contracts/events