System for Cross-domain Identity Management schema definitions for user provisioning. Use when implementing or validating rfc 7643 scim schema protocol compliance.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill rfc-7643-scim-schema --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Rfc 7643 Scim Schema?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-rfc-7643-scim-schema)More formats (shields.io, HTML) on the badges page.
---
name: rfc-7643-scim-schema
description: System for Cross-domain Identity Management schema definitions for user provisioning. Use when implementing or validating rfc 7643 scim schema protocol compliance.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: rfc
tags: [scim, identity, provisioning, schema, multi-tenancy]
---
# RFC 7643 - SCIM Core Schema
You are an expert in implementing SCIM Core Schema as defined in RFC 7643. You create standards-compliant identity resources for user and group provisioning with multi-tenancy support.
## RFC Overview
| Property | Value |
| ---------- | -------------------------------------------------------- |
| RFC Number | 7643 |
| Title | System for Cross-domain Identity Management: Core Schema |
| Status | Proposed Standard |
| Published | September 2015 |
| Related | RFC 7642 (Definitions), RFC 7644 (Protocol) |
## SCIM Resource Model
```text
┌─────────────────────────────────────────────────────────────────┐
│ SCIM Resources │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Common Attributes │ │
│ │ id, externalId, meta │ │
│ └────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ┌────────▼─────┐ ┌───────▼──────┐ ┌─────▼───────┐ │
│ │ User │ │ Group │ │ Enterprise │ │
│ │ Resource │ │ Resource │ │ Extension │ │
│ │ │ │ │ │ │ │
│ │ userName │ │ displayName │ │ employeeNum │ │
│ │ name │ │ members[] │ │ department │ │
│ │ emails[] │ │ │ │ manager │ │
│ │ phoneNumbers │ │ │ │ division │ │
│ │ addresses[] │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
## Core Schema Implementation
### User Resource
```python
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, List, Any
from enum import Enum
import json
import re
import uuid
# SCIM Schema URNs
SCIM_USER_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User"
SCIM_ENTERPRISE_SCHEMA = "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
SCIM_GROUP_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:Group"
@dataclass
class SCIMName:
"""RFC 7643 Section 4.1.1: Name"""
formatted: Optional[str] = None
familyName: Optional[str] = None
givenName: Optional[str] = None
middleName: Optional[str] = None
honorificPrefix: Optional[str] = None
honorificSuffix: Optional[str] = None
@dataclass
class SCIMMultiValue:
"""Base for multi-valued attributes (RFC 7643 Section 2.4)"""
value: str
type: Optional[str] = None # e.g., "work", "home"
primary: bool = False
display: Optional[str] = None
def to_dict(self) -> dict:
d = {"value": self.value}
if self.type:
d["type"] = self.type
if self.primary:
d["primary"] = True
if self.display:
d["display"] = self.display
return d
@dataclass
class SCIMEmail(SCIMMultiValue):
"""Email address (RFC 7643 Section 4.1.2)"""
pass
@dataclass
class SCIMPhoneNumber(SCIMMultiValue):
"""Phone number (RFC 7643 Section 4.1.2)"""
pass
@dataclass
class SCIMAddress:
"""Physical address (RFC 7643 Section 4.1.2)"""
formatted: Optional[str] = None
streetAddress: Optional[str] = None
locality: Optional[str] = None
region: Optional[str] = None
postalCode: Optional[str] = None
country: Optional[str] = None
type: Optional[str] = None # "work", "home", etc.
primary: bool = False
@dataclass
class SCIMMeta:
"""Resource metadata (RFC 7643 Section 3.1)"""
resourceType: str
created: datetime
lastModified: datetime
location: Optional[str] = None
version: Optional[str] = None
def to_dict(self) -> dict:
return {
"resourceType": self.resourceType,
"created": self.created.isoformat() + "Z",
"lastModified": self.lastModified.isoformat() + "Z",
"location": self.location,
"version": self.version,
}
@dataclass
class SCIMEnterpriseUser:
"""Enterprise User Extension (RFC 7643 Section 4.3)"""
employeeNumber: Optional[str] = None
costCenter: Optional[str] = None
organization: Optional[str] = None
division: Optional[str] = None
department: Optional[str] = None
manager: Optional[dict] = None # {"value": "id", "$ref": "uri", "displayName": "name"}
@dataclass
class SCIMUser:
"""SCIM User Resource (RFC 7643 Section 4.1)"""
# Required
userName: str
# Common attributes
id: str = field(default_factory=lambda: str(uuid.uuid4()))
externalId: Optional[str] = None
meta: Optional[SCIMMeta] = None
# Name
name: Optional[SCIMName] = None
displayName: Optional[str] = None
nickName: Optional[str] = None
profileUrl: Optional[str] = None
title: Optional[str] = None
userType: Optional[str] = None
preferredLanguage: Optional[str] = None
locale: Optional[str] = None
timezone: Optional[str] = None
active: bool = True
# Multi-valued
emails: List[SCIMEmail] = field(default_factory=list)
phoneNumbers: List[SCIMPhoneNumber] = field(default_factory=list)
addresses: List[SCIMAddress] = field(default_factory=list)
groups: List[dict] = field(default_factory=list) # Read-only
roles: List[SCIMMultiValue] = field(default_factory=list)
entitlements: List[SCIMMultiValue] = field(default_factory=list)
# Enterprise extension
enterprise: Optional[SCIMEnterpriseUser] = None
# Multi-tenancy
tenant_id: Optional[str] = None
def to_dict(self) -> dict:
"""Serialize to SCIM JSON representation."""
schemas = [SCIM_USER_SCHEMA]
d = {
"schemas": schemas,
"id": self.id,
"userName": self.userName,
"active": self.active,
}
if self.externalId:
d["externalId"] = self.externalId
if self.meta:
d["meta"] = self.meta.to_dict()
if self.name:
d["name"] = {
k: v for k, v in {
"formatted": self.name.formatted,
"familyName": self.name.familyName,
"givenName": self.name.givenName,
"middleName": self.name.middleName,
"honorificPrefix": self.name.honorificPrefix,
"honorificSuffix": self.name.honorificSuffix,
}.items() if v
}
for attr in ["displayName", "nickName", "profileUrl", "title",
"userType", "preferredLanguage", "locale", "timezone"]:
value = getattr(self, attr)
if value:
d[attr] = value
if self.emails:
d["emails"] = [e.to_dict() for e in self.emails]
if self.phoneNumbers:
d["phoneNumbers"] = [p.to_dict() for p in self.phoneNumbers]
if self.addresses:
d["addresses"] = [
{k: v for k, v in {
"formatted": a.formatted,
"streetAddress": a.streetAddress,
"locality": a.locality,
"region": a.region,
"postalCode": a.postalCode,
"country": a.country,
"type": a.type,
"primary": a.primary if a.primary else None,
}.items() if v}
for a in self.addresses
]
if self.groups:
d["groups"] = self.groups
if self.enterprise:
schemas.append(SCIM_ENTERPRISE_SCHEMA)
d[SCIM_ENTERPRISE_SCHEMA] = {
k: v for k, v in {
"employeeNumber": self.enterprise.employeeNumber,
"costCenter": self.enterprise.costCenter,
"organization": self.enterprise.organization,
"division": self.enterprise.division,
"department": self.enterprise.department,
"manager": self.enterprise.manager,
}.items() if v
}
return d
@classmethod
def from_dict(cls, data: dict) -> "SCIMUser":
"""Deserialize from SCIM JSON."""
user = cls(
id=data.get("id", str(uuid.uuid4())),
externalId=data.get("externalId"),
userName=data["userName"],
displayName=data.get("displayName"),
nickName=data.get("nickName"),
profileUrl=data.get("profileUrl"),
title=data.get("title"),
userType=data.get("userType"),
preferredLanguage=data.get("preferredLanguage"),
locale=data.get("locale"),
timezone=data.get("timezone"),
active=data.get("active", True),
)
# Parse name
if "name" in data:
user.name = SCIMName(**data["name"])
# Parse emails
user.emails = [
SCIMEmail(
value=e["value"],
type=e.get("type"),
primary=e.get("primary", False),
display=e.get("display"),
)
for e in data.get("emails", [])
]
# Parse phone numbers
user.phoneNumbers = [
SCIMPhoneNumber(
value=p["value"],
type=p.get("type"),
primary=p.get("primary", False),
)
for p in data.get("phoneNumbers", [])
]
# Parse addresses
user.addresses = [
SCIMAddress(**a)
for a in data.get("addresses", [])
]
# Parse enterprise extension
if SCIM_ENTERPRISE_SCHEMA in data:
ext = data[SCIM_ENTERPRISE_SCHEMA]
user.enterprise = SCIMEnterpriseUser(
employeeNumber=ext.get("employeeNumber"),
costCenter=ext.get("costCenter"),
organization=ext.get("organization"),
division=ext.get("division"),
department=ext.get("department"),
manager=ext.get("manager"),
)
return user
```
### Group Resource
```python
@dataclass
class SCIMGroupMember:
"""Group member reference (RFC 7643 Section 4.2)"""
value: str # Member ID
ref: Optional[str] = None # $ref URI
display: Optional[str] = None
type: Optional[str] = None # "User" or "Group"
def to_dict(self) -> dict:
d = {"value": self.value}
if self.ref:
d["$ref"] = self.ref
if self.display:
d["display"] = self.display
if self.type:
d["type"] = self.type
return d
@dataclass
class SCIMGroup:
"""SCIM Group Resource (RFC 7643 Section 4.2)"""
displayName: str
id: str = field(default_factory=lambda: str(uuid.uuid4()))
externalId: Optional[str] = None
meta: Optional[SCIMMeta] = None
members: List[SCIMGroupMember] = field(default_factory=list)
# Multi-tenancy
tenant_id: Optional[str] = None
def to_dict(self) -> dict:
d = {
"schemas": [SCIM_GROUP_SCHEMA],
"id": self.id,
"displayName": self.displayName,
}
if self.externalId:
d["externalId"] = self.externalId
if self.meta:
d["meta"] = self.meta.to_dict()
if self.members:
d["members"] = [m.to_dict() for m in self.members]
return d
@classmethod
def from_dict(cls, data: dict) -> "SCIMGroup":
group = cls(
id=data.get("id", str(uuid.uuid4())),
externalId=data.get("externalId"),
displayName=data["displayName"],
)
group.members = [
SCIMGroupMember(
value=m["value"],
ref=m.get("$ref"),
display=m.get("display"),
type=m.get("type"),
)
for m in data.get("members", [])
]
return group
```
### Schema Discovery
```python
@dataclass
class SCIMSchemaAttribute:
"""SCIM Schema Attribute definition (RFC 7643 Section 7)"""
name: str
type: str # "string", "boolean", "decimal", "integer", "dateTime", "reference", "complex"
multiValued: bool = False
description: Optional[str] = None
required: bool = False
canonicalValues: Optional[List[str]] = None
caseExact: bool = False
mutability: str = "readWrite" # "readOnly", "readWrite", "immutable", "writeOnly"
returned: str = "default" # "always", "never", "default", "request"
uniqueness: str = "none" # "none", "server", "global"
referenceTypes: Optional[List[str]] = None
subAttributes: Optional[List["SCIMSchemaAttribute"]] = None
class SCIMSchemaDefinition:
"""SCIM Schema definitions for discovery endpoint."""
@staticmethod
def user_schema() -> dict:
"""Return User schema definition."""
return {
"id": SCIM_USER_SCHEMA,
"name": "User",
"description": "User Account",
"attributes": [
{
"name": "userName",
"type": "string",
"multiValued": False,
"required": True,
"caseExact": False,
"mutability": "readWrite",
"returned": "default",
"uniqueness": "server",
},
{
"name": "name",
"type": "complex",
"multiValued": False,
"required": False,
"subAttributes": [
{"name": "formatted", "type": "string"},
{"name": "familyName", "type": "string"},
{"name": "givenName", "type": "string"},
{"name": "middleName", "type": "string"},
{"name": "honorificPrefix", "type": "string"},
{"name": "honorificSuffix", "type": "string"},
],
},
{
"name": "emails",
"type": "complex",
"multiValued": True,
"required": False,
"subAttributes": [
{"name": "value", "type": "string"},
{"name": "type", "type": "string", "canonicalValues": ["work", "home", "other"]},
{"name": "primary", "type": "boolean"},
],
},
{
"name": "active",
"type": "boolean",
"multiValued": False,
"required": False,
"mutability": "readWrite",
"returned": "default",
},
],
"meta": {
"resourceType": "Schema",
"location": "/v2/Schemas/" + SCIM_USER_SCHEMA,
},
}
```
## Multi-Tenancy Patterns
### Tenant-Scoped SCIM Resources
```python
class MultiTenantSCIMStore:
"""SCIM resource store with tenant isolation."""
def __init__(self):
self.users: dict[str, dict[str, SCIMUser]] = {} # tenant_id -> user_id -> user
self.groups: dict[str, dict[str, SCIMGroup]] = {}
def _ensure_tenant(self, tenant_id: str):
if tenant_id not in self.users:
self.users[tenant_id] = {}
if tenant_id not in self.groups:
self.groups[tenant_id] = {}
def create_user(self, tenant_id: str, user: SCIMUser) -> SCIMUser:
"""Create user in tenant scope."""
self._ensure_tenant(tenant_id)
# Check username uniqueness within tenant
for existing in self.users[tenant_id].values():
if existing.userName.lower() == user.userName.lower():
raise SCIMConflictError("userName already exists")
user.tenant_id = tenant_id
user.meta = SCIMMeta(
resourceType="User",
created=datetime.utcnow(),
lastModified=datetime.utcnow(),
location=f"/scim/v2/Users/{user.id}",
version=f'W/"{uuid.uuid4()}"',
)
self.users[tenant_id][user.id] = user
return user
def get_user(self, tenant_id: str, user_id: str) -> Optional[SCIMUser]:
"""Get user with tenant isolation."""
self._ensure_tenant(tenant_id)
user = self.users[tenant_id].get(user_id)
# Extra validation
if user and user.tenant_id != tenant_id:
return None # Cross-tenant access denied
return user
def list_users(
self,
tenant_id: str,
filter_expr: Optional[str] = None,
start_index: int = 1,
count: int = 100,
) -> tuple[List[SCIMUser], int]:
"""List users with filtering and pagination."""
self._ensure_tenant(tenant_id)
users = list(self.users[tenant_id].values())
# Apply filter
if filter_expr:
users = self._apply_filter(users, filter_expr)
total = len(users)
# Apply pagination
start = start_index - 1 # SCIM is 1-indexed
users = users[start:start + count]
return users, total
def _apply_filter(self, users: List[SCIMUser], filter_expr: str) -> List[SCIMUser]:
"""Apply SCIM filter expression (RFC 7644 Section 3.4.2.2)."""
# Simple filter parsing - production would use proper parser
if filter_expr.startswith("userName eq "):
value = filter_expr.split('"')[1]
return [u for u in users if u.userName == value]
elif filter_expr.startswith("emails.value eq "):
value = filter_expr.split('"')[1]
return [u for u in users if any(e.value == value for e in u.emails)]
return users
class SCIMConflictError(Exception):
"""SCIM uniqueness conflict."""
pass
```
## Validation
```python
class SCIMValidator:
"""Validate SCIM resources against schema."""
@staticmethod
def validate_user(data: dict) -> List[str]:
"""Validate user resource data."""
errors = []
# Required attribute
if "userName" not in data:
errors.append("userName is required")
# Validate schemas
schemas = data.get("schemas", [])
if SCIM_USER_SCHEMA not in schemas:
errors.append(f"Missing required schema: {SCIM_USER_SCHEMA}")
# Validate emails format
for i, email in enumerate(data.get("emails", [])):
if "value" not in email:
errors.append(f"emails[{i}].value is required")
elif not re.match(r"[^@]+@[^@]+\.[^@]+", email["value"]):
errors.append(f"emails[{i}].value is not a valid email")
# Validate single primary
primary_emails = [e for e in data.get("emails", []) if e.get("primary")]
if len(primary_emails) > 1:
errors.append("Only one email can be primary")
return errors
```
## Related RFCs
| RFC | Title | Relationship |
| -------- | ---------------- | ------------------------- |
| RFC 7642 | SCIM Definitions | Concepts and requirements |
| RFC 7644 | SCIM Protocol | HTTP operations |
## Output Format
Provide:
- SCIM resource implementations
- Schema definitions
- Multi-tenant isolation patterns
- Validation logic
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!