SCIM
SCIM 2.0 provisioning endpoints.
This page documents the current Ruby port behavior. Ruby uses snake_case option names and auth.api method names; HTTP paths and JSON keys keep the upstream wire shape where implemented.
Some UI or provider-specific setup from upstream is app-provided in Ruby. The protocol endpoints below are implemented, but you must supply your own pages, callbacks, client objects, or provider metadata where noted by the option names.
Configure
require "better_auth"
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
base_url: ENV.fetch("BETTER_AUTH_URL", "http://localhost:3000"),
plugins: [
BetterAuth::Plugins.scim
]
)Usage
token = auth.api.generate_scim_token(headers: { "cookie" => admin_cookie }, body: { providerId: "okta", organizationId: organization_id })
user = auth.api.create_scim_user(headers: { "authorization" => "Bearer #{token[:scimToken]}" }, body: { userName: "ada@example.com" })Routes
| Method | Path | Ruby API method |
|---|---|---|
POST | /scim/generate-token | auth.api.generate_scim_token |
GET | /scim/list-provider-connections | auth.api.list_scim_provider_connections |
GET | /scim/get-provider-connection | auth.api.get_scim_provider_connection |
POST | /scim/delete-provider-connection | auth.api.delete_scim_provider_connection |
POST | /scim/v2/Users | auth.api.create_scim_user |
GET | /scim/v2/Users | auth.api.list_scim_users |
GET | /scim/v2/Users/:userId | auth.api.get_scim_user |
PUT | /scim/v2/Users/:userId | auth.api.update_scim_user |
PATCH | /scim/v2/Users/:userId | auth.api.patch_scim_user |
DELETE | /scim/v2/Users/:userId | auth.api.delete_scim_user |
GET | /scim/v2/ServiceProviderConfig | auth.api.get_scim_service_provider_config |
GET | /scim/v2/Schemas | auth.api.get_scim_schemas |
GET | /scim/v2/Schemas/:schemaId | auth.api.get_scim_schema |
GET | /scim/v2/ResourceTypes | auth.api.get_scim_resource_types |
GET | /scim/v2/ResourceTypes/:resourceTypeId | auth.api.get_scim_resource_type |
Filters
auth.api.list_scim_users and GET /scim/v2/Users support the upstream-compatible userName eq "value" filter. The filter value is matched against the canonicalized user email.
Other SCIM filter attributes and operators are not supported in the Ruby port. Filters such as externalId eq "id" and operators such as ne, co, sw, ew, and pr return a SCIM invalidFilter error instead of silently widening the result set.
Options
Current Ruby options accepted by BetterAuth::Plugins.scim:
store_scim_tokendefault_scimprovider_ownershiprequired_rolebefore_scim_token_generatedafter_scim_token_generated
store_scim_token defaults to "hashed" and accepts "plain", "hashed", "encrypted", { hash: ->(token) { ... } }, or { encrypt: ->(token) { ... }, decrypt: ->(stored) { ... } }.
provider_ownership: { enabled: true } stores the user that generated non-organization provider tokens and restricts provider connection management to that owner.
required_role controls which organization roles can generate, list, view, or delete organization-scoped SCIM providers. When omitted, Ruby follows upstream and allows admin plus the organization creator role.
default_scim accepts provider hashes for tests or static providers:
BetterAuth::Plugins.scim(
default_scim: [
{ providerId: "okta", scimToken: "secret-token", organizationId: "org-id" }
]
)Static default_scim providers are checked before database-backed providers. If a static provider and a database provider share the same providerId, the static provider takes precedence and a bearer token generated for the database provider is rejected.
Ruby behavior notes
Ruby canonicalizes SCIM email/userName values to lowercase before storing the user email and returning the SCIM user resource. When externalId is omitted, Ruby also stores the lowercase userName as the SCIM account id. Upstream preserves the original userName casing for that account id fallback.
Production databases should enforce both of these uniqueness invariants:
scimProvider.providerIdis globally unique.- SCIM account identity is unique by
(providerId, accountId).
Plugin Surface
BetterAuth::Plugins.scim exposes version and client metadata. The client descriptor uses the upstream id scim-client and points back to the server plugin id scim.
When combined with BetterAuth::Plugins.open_api, provider management routes are included in the generated schema, while SCIM protocol routes under /scim/v2/* are hidden to match upstream HIDE_METADATA.
Support Notes
- The examples above are based on Ruby plugin source and tests in
packages/better_auth. - If an upstream section is not represented here, treat it as not yet documented or not yet supported by the Ruby port until the matching Ruby implementation exists.