# `ExScim.Scope`
[🔗](https://github.com/ExScim/ex_scim/blob/main/lib/ex_scim/scope.ex#L1)

Represents the scope of a SCIM request: identity, authorization, and tenant context.

When `tenant_id` is `nil`, the system behaves as single-tenant (no isolation).

## Authorization Scopes

The following standard scopes are enforced by `ExScimPhoenix`:

| Scope | Endpoints | Actions |
|---|---|---|
| `scim:read` | `/Users`, `/Groups`, `/Schemas`, `/ResourceTypes`, `/ServiceProviderConfig` | GET (list, show, search) |
| `scim:create` | `/Users`, `/Groups`, `/Bulk` (POST operations) | POST |
| `scim:update` | `/Users`, `/Groups`, `/Bulk` (PUT/PATCH operations) | PUT, PATCH |
| `scim:delete` | `/Users`, `/Groups`, `/Bulk` (DELETE operations) | DELETE |

`/Me` uses its own set of fine-grained scopes:

| Scope | Action |
|---|---|
| `scim:me:read` | GET `/Me` |
| `scim:me:create` | POST `/Me` |
| `scim:me:update` | PUT `/Me`, PATCH `/Me` |
| `scim:me:delete` | DELETE `/Me` |

For bulk operations, scope is enforced per individual operation rather than on the
request as a whole. A caller with only `scim:create` may submit a bulk request
containing POST operations; any PUT, PATCH, or DELETE operations in the same payload
will return a `403` operation result.

### Example scope lists

Read-only client:
```elixir
scopes: ["scim:read"]
```

Provisioning client (create and update, but not delete):
```elixir
scopes: ["scim:read", "scim:create", "scim:update"]
```

Full-access admin client:
```elixir
scopes: ["scim:read", "scim:create", "scim:update", "scim:delete"]
```

# `t`

```elixir
@type t() :: %ExScim.Scope{
  display_name: String.t() | nil,
  id: String.t(),
  metadata: map(),
  scopes: [String.t()],
  tenant_id: String.t() | nil,
  username: String.t() | nil
}
```

# `has_all_scopes?`

```elixir
@spec has_all_scopes?(t(), [String.t()]) :: boolean()
```

Returns `true` if the scope has all of the given authorization scopes.

# `has_scope?`

```elixir
@spec has_scope?(t(), String.t()) :: boolean()
```

Returns `true` if the scope has the given authorization scope.

# `new`

```elixir
@spec new(map() | keyword()) :: {:ok, t()} | :error
```

Creates a new Scope from a map or keyword list.

Raises `ArgumentError` if required keys `:id` or `:scopes` are missing.

## Examples

    iex> Scope.new(%{id: "user_1", scopes: ["scim:read"]})
    {:ok, %Scope{id: "user_1", scopes: ["scim:read"], metadata: %{}}}

    iex> Scope.new(id: "client_1", scopes: ["scim:read", "scim:write"], tenant_id: "org_123")
    {:ok, %Scope{id: "client_1", scopes: ["scim:read", "scim:write"], tenant_id: "org_123", metadata: %{}}}

---

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