# SCIM without the pain

If you sell to enterprises, you're going to hear the acronym **SCIM** a lot. SCIM (System for Cross-domain Identity Management) is the standard IdPs (Okta, Entra/Azure, OneLogin, etc.) use to _provision and deprovision users automatically_.

Someone joins their company? They're added to your app. They leave? Access is revoked. It's clean, auditable, and it keeps your customer's IT team happy.

The catch: implementing SCIM from scratch means juggling many endpoints, subtle differences between each IdP (like Entra sending strings instead of booleans depending on when the account was created), and long feedback loops with customer admins.

That's exactly why we built SCIM into **PropelAuth BYO**.

## Why SCIM in BYO feels different

### One route to rule them all

The SCIM spec defines a handful of endpoints (`/Users`, `/Groups`, `/Schema`, etc.) that you'll need to implement. Each one has its own quirks and edge cases, and different IdPs behave differently.

With BYO you stand up a single **catch-all** route (e.g. `/api/scim/*`) and forward requests to the sidecar. We parse the request and tell you if an action is required (like **LinkUser** on first-time provisioning, allowing you to provide your own ID or reject the request, or **DisableUser** on deprovision). If there's no action required, we hand back a response body + status that you can return directly to the IdP. You keep control of your data model without building the whole spec.

### You define the data you want (and how it's mapped)

Let's say you want to collect a custom attribute from your customer like `favorite_sport`. Where does that live in the SCIM payload?

Unfortunately, while the SCIM spec defines a core schema, it's not as prescriptive when it comes to custom attributes (and the folks that wrote the SCIM spec didn't think about how important the `favorite_sport` field would be to your business).

BYO lets you **declare the schema you want** and map incoming IdP fields to it. For example, to capture a user's favorite sport, we define the property in our schema:

```json
{
    "userSchema": [
        // ...
        {
            "outputField": "favorite_sport",
            "inputPath": "favoriteSport",
            "displayName": "Favorite Sport",
            "description": "The user's favorite Sport",
            "propertyType": {
                "dataType": "String"
            }
        }
    ]
}
```

Once mapped, whenever SCIM requests arrive, BYO will look for `favoriteSport` in the incoming payload, extract it, and store it under `favorite_sport` in its normalized view of the user. That means that property is available both in SCIM request handling and when you ask for a user later via `getScimUser`.

In other words: you will always get a normalized shape from the sidecar.

Oh, and it works retroactively as well. So you can update your mappings at any time and calls to `getScimUser` will reflect the new schema immediately.

### Fallback Paths: Because customers rarely follow directions perfectly

Maybe your guide says "send `favoriteSport` at the top level," but the customer ships `fav_sport`, `FavoriteSport`, or `urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:favorite_sport`. Instead of going back and forth trying to get on the same page, add **fallback paths** in the dashboard so BYO will look in the other places and still populate `favorite_sport`. Update once, fix it for the entire connection.

### Fast reads from inside your infra

Sometimes you just want to know what the IdP thinks about a user right now. Maybe you're doing an authorization check for a sensitive operation and need to know the groups the user is in. Maybe you just want to display the user's name in your product. Maybe you need to know if the user is still active.

Because BYO is a **self-hosted sidecar** that runs in _your_ cloud next to _your_ app, calling `getScimUser` to fetch the customer's authoritative view of a user is a low-latency internal hop - not a cross-internet round-trip. You can use this in middleware, on `/whoami` routes, or anywhere you'd consider querying your own user database.

### Know when important data is missing

Some attributes are business-critical (manager email, org role). Mark them **Warn if missing** and the dashboard will flag users that arrived without those values. Your onboarding or support team gets a clear count of warnings and examples to fix.

### Built for operators _and_ developers

As with everything in BYO, we designed SCIM support to make life easier for both your engineering team and the folks who will be onboarding and supporting customers. This means it's not just an API, but we also provide:

- **Dashboard for onboarding & support.** See each connection's users/groups, the exact payloads the IdP sent, and your current mappings - then adjust without redeploying.
- **Programmatic everything.** The same normalized properties are returned in SCIM request handling (`parsedUserData`) and via `getScimUser`, so you can enforce policy consistently in code.
- **Fix it yourself, without the back-and-forth.** Update mappings, add fallbacks, and re-check users immediately - no waiting on the customer to reconfigure.

## A quick mental model

1. Your catch-all `/api/scim/*` forwards to BYO.
2. BYO validates and normalizes the request.
3. If an action is required (Link/Disable/Enable/Delete), you perform it in your system, then confirm; otherwise, just return BYO's response.
4. At any time, call `getScimUser` to read the customer-source truth for a user from inside your own infra.

If you already have authentication that works, BYO's SCIM support lets you say "yes" to enterprise asks without rewriting your model or your roadmap. Add the mappings, keep your control, and give customers the provisioning story they expect.
