# `Sigra.Plug.RequireMembership`
[🔗](https://github.com/sztheory/sigra/blob/v1.20.0/lib/sigra/plug/require_membership.ex#L1)

Halts the pipeline unless `conn.assigns[:current_scope]` has a non-nil
`active_organization` and (optionally) a membership role in the configured
`:roles` list.

Structural twin of `Sigra.Plug.RequireScopes` — same `init/1` validation
pattern, same `error_handler` delegation, same halt shape. Any divergence
from RequireScopes is a bug. Phase 14 D-05 / D-06 / D-07 / D-21.

## Options

  * `:error_handler` — **required**. Module implementing
    `Sigra.Plug.ErrorHandler`.

  * `:roles` — optional list of atoms. Must be a subset of the host's
    organization role universe. Default: `[]` (any active membership
    accepted — D-07). Validation behavior depends on `:organizations`:

      - **Without `:organizations`:** Validated at `init/1` against the
        library's canonical role universe (`[:owner, :admin, :member]`);
        raises `ArgumentError` on typos.

      - **With `:organizations`:** Validated at `init/1` against
        `organizations.__sigra_org_config__().roles`, which is the
        host's actual role list (Phase 14 D-05 / IN-03). This lets hosts
        extend roles (`:viewer`, `:billing`, etc.) via the
        `Sigra.Organizations` config without editing the library.

  * `:organizations` — optional. The host's `use Sigra.Organizations`
    module. When given, `init/1` reads the role universe from its
    `__sigra_org_config__/0` so custom roles are recognized (IN-03). If the
    org module is not yet compiled when the router is compiled, pass
    nothing and the plug falls back to the canonical universe.

Reads `scope.membership.role` from assigns. **Never re-queries the DB** —
the membership lookup was already performed by
`Sigra.Plug.LoadActiveOrganization` and stashed on the scope struct. Set
membership semantics (D-06): `[:owner]` means "owner only"; it does NOT
imply admin.

## Example

    plug Sigra.Plug.RequireAuthenticated, error_handler: MyAppWeb.AuthErrorHandler
    plug Sigra.Plug.LoadActiveOrganization,
      organizations: MyApp.Organizations,
      session_store: Sigra.SessionStores.Ecto
    plug Sigra.Plug.RequireMembership,
      error_handler: MyAppWeb.AuthErrorHandler,
      organizations: MyApp.Organizations,
      roles: [:owner, :admin]

# `call`
*since 0.8.0* 

Enforce membership presence and (optionally) role membership, halting via
the configured error handler on failure.

# `init`
*since 0.8.0* 

Initialize the plug with the given options.

Validates that `:error_handler` is present and that `:roles` (when given) is
a list of atoms drawn from the role universe. The role universe is the
host's `__sigra_org_config__/0` `:roles` when `:organizations` is passed,
otherwise `[:owner, :admin, :member]`. Raises `ArgumentError` with a
helpful message on typos.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
