# ExScim
SCIM 2.0 implementation in Elixir.
Based on the official specifications:
- [RFC 7643: SCIM Core Schema](https://www.rfc-editor.org/rfc/rfc7643)
- [RFC 7644: SCIM Protocol](https://www.rfc-editor.org/rfc/rfc7644)
- [RFC 6902: JSON Patch](https://www.rfc-editor.org/rfc/rfc6902)
The system is modular and adapter-based, so storage, mapping, authentication, and validation can be customized.
---
## Quickstart
Add the dependencies you need to `mix.exs`:
```elixir
{:ex_scim, path: "ex_scim"}
{:ex_scim_ecto, path: "ex_scim_ecto"} # optional: Ecto storage
{:ex_scim_phoenix, path: "ex_scim_phoenix"} # optional: Phoenix endpoints
{:ex_scim_client, path: "ex_scim_client"} # optional: HTTP client
````
Alternatively:
```elixir
{:ex_scim, git: "https://github.com/ExScim/ex_scim.git", sparse: "apps/ex_scim", branch: "main", override: true},
{:ex_scim_ecto, git: "https://github.com/ExScim/ex_scim.git", sparse: "apps/ex_scim_ecto", branch: "main", override: true}, # optional: Ecto storage
{:ex_scim_phoenix, git: "https://github.com/ExScim/ex_scim.git", sparse: "apps/ex_scim_phoenix", branch: "main", override: true}, # optional: Phoenix endpoints
{:ex_scim_client, git: "https://github.com/ExScim/ex_scim.git", sparse: "apps/ex_scim_client", branch: "main", override: true} # optional: HTTP client
```
Run the example provider app to see a working SCIM setup:
```bash
cd examples/provider
mix ecto.setup
mix phx.server
```
Endpoints will be available under `/scim/v2`.
---
## Architecture Overview
ExScim is split into four packages:
```
ex_scim/ # Core SCIM logic and operations
ex_scim_ecto/ # Database persistence via Ecto
ex_scim_phoenix/ # HTTP endpoints and Phoenix integration
ex_scim_client/ # HTTP client for consuming SCIM APIs
```
### Core Design
* **Adapters**: All major components are replaceable via behaviours:
* [`ExScim.Storage.Adapter`](./ex_scim/lib/ex_scim/storage/adapter.ex) – data persistence
* [`ExScim.Users.Mapper.Adapter`](./ex_scim/lib/ex_scim/users/mapper/adapter.ex) – domain ↔ SCIM mapping
* [`ExScim.Auth.AuthProvider.Adapter`](./ex_scim/lib/ex_scim/auth/auth_provider/adapter.ex) – authentication / authorization
* [`ExScim.Schema.Validator.Adapter`](./ex_scim/lib/ex_scim/schema/validator/adapter.ex) – schema validation
* [`ExScim.QueryFilter.Adapter`](./ex_scim/lib/ex_scim/query_filter/adapter.ex) – SCIM filter parsing ([RFC 7644 §3.4.2.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2.2))
* **Operations Layer**: Encapsulates business logic
* `ExScim.Operations.Users` – User CRUD and search
* `ExScim.Operations.Groups` – Group CRUD and membership
* `ExScim.Operations.Bulk` – Bulk operation processing ([RFC 7644 §3.7](https://www.rfc-editor.org/rfc/rfc7644#section-3.7))
* **Resource Transformation**: Clear separation between
* Application domain structs (e.g. `%User{}`)
* SCIM JSON representation ([RFC 7643](https://www.rfc-editor.org/rfc/rfc7643))
* Mapping handled through adapters
---
## Package Details
### ex\_scim – Core Library
* Operations for Users, Groups, and Bulk
* Unified storage interface
* SCIM filter/path parsers
* Resource handling (IDs, metadata)
* Schema validation and repository ([RFC 7643 §7](https://www.rfc-editor.org/rfc/rfc7643#section-7))
* RFC 7644-compliant error responses ([RFC 7644 §3.12](https://www.rfc-editor.org/rfc/rfc7644#section-3.12))
* Default user/group mappers
### ex\_scim\_ecto – Database Integration
* Ecto `StorageAdapter` implementation
* Converts SCIM filters to Ecto queries
* Works with PostgreSQL, MySQL, SQLite, etc.
### ex\_scim\_phoenix – HTTP API
* Controllers for Users, Groups, Me, Search, Bulk, Discovery
* Complete SCIM 2.0 router ([RFC 7644 §3](https://www.rfc-editor.org/rfc/rfc7644#section-3))
* Plugs for auth, content-type handling, logging
* HTTP error ↔ SCIM error mapping
### ex\_scim\_client – HTTP Client
* HTTP client for consuming SCIM APIs
* User and Group resource operations
* Filtering, sorting, pagination support
* Bulk operations and schema discovery
* Request builder with authentication
---
## Configuration Example
```elixir
config :ex_scim,
base_url: "https://your-domain.com",
# Storage
storage_strategy: ExScimEcto.StorageAdapter,
storage_repo: MyApp.Repo,
user_model: MyApp.Accounts.User,
group_model: MyApp.Accounts.Group,
# Resource mapping
user_resource_mapper: MyApp.Scim.UserMapper,
group_resource_mapper: MyApp.Scim.GroupMapper,
# Authentication
auth_provider_adapter: MyApp.Scim.AuthProvider,
# Schema validation
scim_validator: ExScim.Schema.Validator.DefaultValidator,
scim_schema_repository: ExScim.Schema.Repository.DefaultRepository,
# Bulk operations
bulk_supported: true,
bulk_max_operations: 1000,
bulk_max_payload_size: 1_048_576
```
---
## Phoenix Integration
Add SCIM routes to your Phoenix application:
```elixir
defmodule MyAppWeb.Router do
use Phoenix.Router
pipeline :scim_api do
plug :accepts, ["json", "scim+json"]
plug ExScimPhoenix.Plug.ScimContentType
plug ExScimPhoenix.Plug.ScimAuth
end
scope "/scim/v2" do
pipe_through :scim_api
use ExScimPhoenix.Router
end
end
```
---
## Custom Adapters
### Storage Adapter
```elixir
defmodule MyApp.CustomStorage do
@behaviour ExScim.Storage.Adapter
def get_user(id), do: # your implementation
def create_user(user_data), do: # your implementation
# ... other callbacks
end
```
### Resource Mapper
```elixir
defmodule MyApp.UserMapper do
@behaviour ExScim.Users.Mapper.Adapter
def from_scim(scim_data) do
%MyApp.User{
username: scim_data["userName"],
email: get_primary_email(scim_data["emails"])
}
end
def to_scim(%MyApp.User{} = user, _opts) do
%{
"schemas" => ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id" => user.id,
"userName" => user.username,
"emails" => format_emails(user.email)
}
end
end
```
---
## Example Provider
The [`examples/provider`](./examples/provider) app shows a complete SCIM setup:
* Phoenix router with SCIM routes
* Domain ↔ SCIM mappers
* Ecto schema for `User`
* SQLite database
* Custom auth provider (demo)
* User and Group support
Run it locally:
```bash
cd examples/provider
mix deps.get
mix ecto.setup
mix phx.server
```
---
## Development
Each package can be tested independently:
```bash
cd ex_scim && mix test
cd ex_scim_ecto && mix test
cd ex_scim_phoenix && mix test
cd ex_scim_client && mix test
```
Provider example:
```bash
cd examples/provider
mix ecto.setup
mix phx.server
```
---
## SCIM 2.0 Support
**Features**
* User and Group resources ([RFC 7643 §4](https://www.rfc-editor.org/rfc/rfc7643#section-4))
* REST API ([RFC 7644](https://www.rfc-editor.org/rfc/rfc7644))
* JSON Patch ([RFC 6902](https://www.rfc-editor.org/rfc/rfc6902))
* SCIM filter expressions ([RFC 7644 §3.4.2.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2.2))
* Bulk operations ([RFC 7644 §3.7](https://www.rfc-editor.org/rfc/rfc7644#section-3.7))
* Discovery endpoints: ServiceProviderConfig, ResourceTypes, Schemas ([RFC 7644 §4](https://www.rfc-editor.org/rfc/rfc7644#section-4))
* RFC-compliant error responses ([RFC 7644 §3.12](https://www.rfc-editor.org/rfc/rfc7644#section-3.12))
**Endpoints**
* `GET /Users` – list with filtering, sorting, pagination ([RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.2))
* `POST /Users` – create ([RFC 7644 §3.3](https://www.rfc-editor.org/rfc/rfc7644#section-3.3))
* `GET /Users/{id}` – fetch by ID ([RFC 7644 §3.4.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.1))
* `PUT /Users/{id}` – replace ([RFC 7644 §3.5.1](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.1))
* `PATCH /Users/{id}` – update ([RFC 7644 §3.5.2](https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2), [RFC 6902](https://www.rfc-editor.org/rfc/rfc6902))
* `DELETE /Users/{id}` – delete ([RFC 7644 §3.6](https://www.rfc-editor.org/rfc/rfc7644#section-3.6))
* Similar endpoints for Groups and Me ([RFC 7644 §3.11](https://www.rfc-editor.org/rfc/rfc7644#section-3.11))
* `POST /.search` – cross-resource search ([RFC 7644 §3.4.3](https://www.rfc-editor.org/rfc/rfc7644#section-3.4.3))
* `POST /Bulk` – bulk operations ([RFC 7644 §3.7](https://www.rfc-editor.org/rfc/rfc7644#section-3.7))
---
## Design Choices
* **Modular**: use only the packages you need (core, ecto, phoenix)
* **Extensible**: adapters for storage, mapping, auth, validation
* **Separated concerns**: persistence, HTTP, business logic
* **RFC compliance**: responses and errors follow spec
---
See the [examples/provider](./examples/provider) app for a full reference implementation.