scim

package
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2025 License: Apache-2.0 Imports: 27 Imported by: 0

README

SCIM 2.0 Provisioning Plugin

Enterprise-grade SCIM 2.0 implementation for automated user and group provisioning from identity providers like Okta, Azure AD, OneLogin, and others.

Overview

The SCIM (System for Cross-domain Identity Management) 2.0 plugin enables enterprise customers to:

  • Automate User Provisioning: Create, update, and deactivate users automatically
  • Group Synchronization: Sync SCIM groups to AuthSome teams/roles
  • Real-time Updates: Immediate synchronization of identity changes
  • Bulk Operations: Efficiently provision multiple users at once
  • Custom Attribute Mapping: Flexible schema mapping for custom attributes
  • JIT Provisioning: Just-In-Time user creation on first login
  • Enterprise Integration: Works with Okta, Azure AD, OneLogin, Google Workspace, etc.

Architecture Modes

SCIM supports dual-mode operation to work with different deployment configurations:

App Mode (Multitenancy Only)
  • SCIM provisions users/groups directly into platform apps
  • Uses multitenancy app service (*app.Service)
  • Users are app members, groups are app teams
  • Simpler deployment without organization plugin
  • Token organization_id field contains the app ID
Organization Mode (With Organization Plugin)
  • SCIM provisions users/groups into user-created organizations
  • Uses organization plugin service (*organization.Service)
  • Users are organization members, groups are organization teams
  • Full 3-tier: App → Environment → Organization
  • Token includes app_id, environment_id, and organization_id

The plugin automatically detects which service is available and uses the appropriate mode.

Features

✅ SCIM 2.0 Standard Compliance
  • Full RFC 7643 and RFC 7644 compliance
  • Core User schema (RFC 7643 Section 4.1)
  • Enterprise User extension (RFC 7643 Section 4.3)
  • Group schema (RFC 7643 Section 4.2)
  • Service Provider Configuration endpoint
  • Resource Type and Schema discovery
🔐 Security
  • Bearer token authentication
  • Organization-scoped isolation
  • IP whitelisting support
  • Rate limiting per organization
  • Complete audit logging
  • Secure token generation and storage
📊 Operations Supported

User Operations:

  • POST /scim/v2/Users - Create user
  • GET /scim/v2/Users - List users with filtering
  • GET /scim/v2/Users/:id - Get user by ID
  • PUT /scim/v2/Users/:id - Replace user (full update)
  • PATCH /scim/v2/Users/:id - Update user (partial)
  • DELETE /scim/v2/Users/:id - Deactivate/delete user

Group Operations:

  • POST /scim/v2/Groups - Create group
  • GET /scim/v2/Groups - List groups
  • GET /scim/v2/Groups/:id - Get group by ID
  • PUT /scim/v2/Groups/:id - Replace group
  • PATCH /scim/v2/Groups/:id - Update group
  • DELETE /scim/v2/Groups/:id - Delete group

Bulk Operations:

  • POST /scim/v2/Bulk - Process multiple operations in a single request

Search:

  • POST /scim/v2/.search - Search across resources with filtering

Discovery:

  • GET /scim/v2/ServiceProviderConfig - Service provider capabilities
  • GET /scim/v2/ResourceTypes - Supported resource types
  • GET /scim/v2/Schemas - Supported schemas

Installation

1. Add Plugin to Your AuthSome Instance

App Mode (Multitenancy only):

package main

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/multiapp"
    "github.com/xraph/authsome/plugins/enterprise/scim"
)

func main() {
    // Create AuthSome instance
    auth := authsome.New(
        authsome.WithDatabase(db),
        authsome.WithForgeApp(app),
    )
    
    // Register multitenancy plugin (required for app mode)
    if err := auth.RegisterPlugin(multitenancy.NewPlugin()); err != nil {
        panic(err)
    }
    
    // Register SCIM plugin
    scimPlugin := scim.NewPlugin()
    if err := auth.RegisterPlugin(scimPlugin); err != nil {
        panic(err)
    }
    
    // Initialize AuthSome (this will initialize all plugins)
    if err := auth.Initialize(ctx); err != nil {
        panic(err)
    }
    
    // Mount routes
    if err := auth.Mount(router, "/api/auth"); err != nil {
        panic(err)
    }
}

Organization Mode (With organization plugin):

package main

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/multiapp"
    "github.com/xraph/authsome/plugins/organization"
    "github.com/xraph/authsome/plugins/enterprise/scim"
)

func main() {
    // Create AuthSome instance
    auth := authsome.New(
        authsome.WithDatabase(db),
        authsome.WithForgeApp(app),
    )
    
    // Register multitenancy plugin (for apps/environments)
    if err := auth.RegisterPlugin(multitenancy.NewPlugin()); err != nil {
        panic(err)
    }
    
    // Register organization plugin (required for organization mode)
    if err := auth.RegisterPlugin(organization.NewPlugin()); err != nil {
        panic(err)
    }
    
    // Register SCIM plugin
    scimPlugin := scim.NewPlugin()
    if err := auth.RegisterPlugin(scimPlugin); err != nil {
        panic(err)
    }
    
    // Initialize AuthSome (this will initialize all plugins)
    if err := auth.Initialize(ctx); err != nil {
        panic(err)
    }
    
    // Mount routes
    if err := auth.Mount(router, "/api/auth"); err != nil {
        panic(err)
    }
}
2. Configure Plugin
# config.yaml
auth:
  plugins:
    # Multitenancy plugin (required for app mode, or for apps/environments in org mode)
    multitenancy:
      enabled: true
      enableAppCreation: true
    
    # Organization plugin (optional - enables organization mode)
    organization:
      enabled: true
      enableUserCreation: true
    
    # SCIM plugin
    scim:
      enabled: true
      auth_method: "bearer"
      token_expiry: "90d"
      
      rate_limit:
        enabled: true
        requests_per_min: 600  # 10 req/sec
        burst_size: 100
      
      user_provisioning:
        enabled: true
        auto_activate: true
        send_welcome_email: false
        default_role: "member"
        prevent_duplicates: true
        soft_delete_on_deprovision: true
      
      group_sync:
        enabled: true
        sync_to_teams: true
        sync_to_roles: false
        create_missing_groups: true
      
      bulk_operations:
        enabled: true
        max_operations: 100
        max_payload_bytes: 1048576  # 1MB
      
      search:
        max_results: 1000
        default_results: 50
      
      security:
        require_https: true
        audit_all_operations: true
        mask_sensitive_data: true
        require_org_validation: true

Note: SCIM automatically detects which mode to use:

  • If only multitenancy plugin is loaded → App Mode (provisions to apps)
  • If organization plugin is also loaded → Organization Mode (provisions to user-created organizations)
3. Run Database Migrations

Migrations run automatically when the plugin is initialized. You can also run them manually:

if err := scimPlugin.Migrate(); err != nil {
    panic(err)
}

Usage

Creating a Provisioning Token

Before you can use SCIM, create a provisioning token for your identity provider. The token is scoped to the current app/environment/organization context:

App Mode:

  • Token is scoped to the app (organization_id = app_id)
  • Provisions users/groups directly into the app

Organization Mode:

  • Token is scoped to a specific organization within an app/environment
  • Provisions users/groups into the user-created organization
curl -X POST http://localhost:8080/api/admin/scim/tokens \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Okta Production",
    "description": "SCIM token for Okta production environment",
    "scopes": ["scim:read", "scim:write"],
    "expires_at": "2025-12-31T23:59:59Z"
  }'

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "id": "cm3abc123def456ghi789",
  "name": "Okta Production",
  "message": "Store this token securely. It will not be shown again."
}

⚠️ Important: Save the token immediately. It will not be displayed again.

Configuring Your Identity Provider
Okta
  1. Navigate to Applications > Applications in Okta Admin Console
  2. Click Browse App Catalog
  3. Search for SCIM 2.0 Test App (Header Auth)
  4. Click Add Integration
  5. Configure:
    • SCIM 2.0 Base URL: https://your-domain.com/scim/v2
    • Unique identifier field for users: userName
    • Supported provisioning actions: Check all
    • Authentication Mode: HTTP Header
    • Authorization: Bearer YOUR_SCIM_TOKEN
Azure AD
  1. Navigate to Azure Active Directory > Enterprise Applications
  2. Click New Application > Create your own application
  3. Select Integrate any other application you don't find in the gallery (Non-gallery)
  4. Go to Provisioning > Automatic
  5. Configure:
    • Tenant URL: https://your-domain.com/scim/v2
    • Secret Token: YOUR_SCIM_TOKEN
  6. Test connection and save
OneLogin
  1. Navigate to Applications > Custom Connectors
  2. Click New Connector
  3. Select SCIM 2.0
  4. Configure:
    • SCIM Base URL: https://your-domain.com/scim/v2
    • SCIM Bearer Token: YOUR_SCIM_TOKEN
    • SCIM Version: 2.0
  5. Enable provisioning features
Example: Provisioning a User

When you assign a user in your IdP, it will automatically create the user in AuthSome:

SCIM Request (from IdP):

POST /scim/v2/Users HTTP/1.1
Host: your-domain.com
Authorization: Bearer YOUR_SCIM_TOKEN
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "bjensen@example.com",
  "name": {
    "givenName": "Barbara",
    "familyName": "Jensen"
  },
  "emails": [{
    "value": "bjensen@example.com",
    "type": "work",
    "primary": true
  }],
  "displayName": "Barbara Jensen",
  "active": true,
  "externalId": "okta_user_12345"
}

Response:

HTTP/1.1 201 Created
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "cm3xyz789abc123def456",
  "externalId": "okta_user_12345",
  "userName": "bjensen@example.com",
  "name": {
    "givenName": "Barbara",
    "familyName": "Jensen",
    "formatted": "Barbara Jensen"
  },
  "emails": [{
    "value": "bjensen@example.com",
    "type": "work",
    "primary": true
  }],
  "displayName": "Barbara Jensen",
  "active": true,
  "meta": {
    "resourceType": "User",
    "created": "2024-01-15T10:30:00Z",
    "lastModified": "2024-01-15T10:30:00Z",
    "location": "/scim/v2/Users/cm3xyz789abc123def456"
  }
}
Example: Updating a User

SCIM Request (PATCH):

PATCH /scim/v2/Users/cm3xyz789abc123def456 HTTP/1.1
Host: your-domain.com
Authorization: Bearer YOUR_SCIM_TOKEN
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "path": "active",
      "value": false
    }
  ]
}
Example: Bulk Provisioning
POST /scim/v2/Bulk HTTP/1.1
Host: your-domain.com
Authorization: Bearer YOUR_SCIM_TOKEN
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
  "failOnErrors": 1,
  "Operations": [
    {
      "method": "POST",
      "path": "/Users",
      "bulkId": "qwerty",
      "data": {
        "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
        "userName": "alice@example.com",
        "name": {
          "givenName": "Alice",
          "familyName": "Smith"
        },
        "emails": [{
          "value": "alice@example.com",
          "type": "work"
        }]
      }
    },
    {
      "method": "POST",
      "path": "/Users",
      "bulkId": "ytrewq",
      "data": {
        "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
        "userName": "bob@example.com",
        "name": {
          "givenName": "Bob",
          "familyName": "Johnson"
        },
        "emails": [{
          "value": "bob@example.com",
          "type": "work"
        }]
      }
    }
  ]
}

Attribute Mapping

The plugin supports flexible attribute mapping to adapt to your schema:

Default Mappings
SCIM Attribute AuthSome Field
userName email
emails[0].value email
name.givenName name (first part)
name.familyName name (last part)
displayName name
active email_verified
externalId metadata.scim_external_id
Enterprise Extension Mappings
SCIM Attribute AuthSome Field
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber metadata.employee_number
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department metadata.department
urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value metadata.manager_id
Custom Mappings

Configure custom attribute mappings:

attribute_mapping:
  enabled: true
  custom_mapping:
    "customAttribute1": "metadata.custom_field_1"
    "customAttribute2": "metadata.custom_field_2"

Group Synchronization

SCIM groups can be automatically synced to AuthSome teams or roles:

Configuration
group_sync:
  enabled: true
  sync_to_teams: true           # Sync to teams
  sync_to_roles: false          # Or sync to roles
  create_missing_groups: true   # Auto-create teams/roles
  delete_empty_groups: false    # Keep empty groups
Example: Creating a Group
POST /scim/v2/Groups HTTP/1.1
Host: your-domain.com
Authorization: Bearer YOUR_SCIM_TOKEN
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "displayName": "Engineering",
  "externalId": "okta_group_engineering",
  "members": [
    {
      "value": "cm3xyz789abc123def456",
      "display": "Barbara Jensen"
    }
  ]
}
SCIM-Managed Team Tracking

Teams created via SCIM provisioning are automatically marked with special tracking fields to distinguish them from manually-created teams:

  • provisionedBy: Set to "scim" for SCIM-created teams
  • externalID: Stores the external system's identifier (e.g., Okta group ID)
Behavior

Manual Modifications:

  • SCIM-managed teams can still be updated or deleted via regular team APIs
  • Operations on SCIM-managed teams return warnings in the response
  • Changes made manually may be overwritten by the identity provider

Warning Response Example:

When updating a SCIM-managed team via the regular team API:

{
  "data": {
    "id": "cm3xyz789abc123def456",
    "name": "Engineering",
    "description": "Engineering team",
    "provisionedBy": "scim",
    "externalID": "okta_group_engineering"
  },
  "warnings": [
    {
      "code": "scim_managed_team",
      "message": "This team is managed via SCIM provisioning. Manual changes may be overwritten by the identity provider."
    }
  ]
}

Team Response Fields:

All teams now include provisioning information in their responses:

{
  "id": "cm3xyz789abc123def456",
  "name": "Engineering",
  "description": "Team description",
  "provisionedBy": "scim",          // Only present for SCIM-managed teams
  "externalID": "okta_group_123",   // Only present for SCIM-managed teams
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z"
}

Best Practices:

  1. Identity Provider as Source of Truth: When using SCIM, treat the identity provider as the authoritative source for team management
  2. Manual Changes: Use manual updates only for emergency situations or temporary fixes
  3. Monitoring: Watch for warning responses when modifying teams to identify potential conflicts
  4. Audit Trail: Review SCIM provisioning logs to track all changes made via identity provider
SCIM-Managed Team Memberships

Similar to teams, team memberships created via SCIM are tracked with a provisioning field:

  • provisionedBy: Set to "scim" for SCIM-added members
Team Member Tracking

When SCIM adds a user to a group (team), the membership relationship is marked as SCIM-managed:

{
  "id": "cm3xyz789abc123def456",
  "teamID": "cm3team123",
  "memberID": "cm3member456",
  "provisionedBy": "scim",        // Indicates SCIM-managed membership
  "joinedAt": "2024-01-15T10:30:00Z",
  "createdAt": "2024-01-15T10:30:00Z"
}

Use Cases:

  1. Membership Audit: Identify which team memberships are controlled by identity provider
  2. Access Reviews: Distinguish between manually-granted and SCIM-provisioned access
  3. Compliance: Track provisioned access for regulatory requirements
  4. Conflict Detection: Services can check provisionedBy before manual member removal

Example Service Check:

// Check if team membership is SCIM-managed before removal
teamMember, err := teamService.GetTeamMember(ctx, teamID, memberID)
if err != nil {
    return err
}

if teamMember.ProvisionedBy != nil && *teamMember.ProvisionedBy == "scim" {
    log.Warn("Attempting to remove SCIM-managed team member",
        "team", teamID,
        "member", memberID)
    // Optionally return warning to user
}

Important Notes:

  • Team membership removal via regular APIs is allowed even for SCIM-managed members
  • Identity provider will re-provision the member on next sync if they're still in the group
  • For complete removal, remove the user from the group in the identity provider

Monitoring & Audit

Viewing Provisioning Logs
curl -X GET "http://localhost:8080/api/scim-admin/logs?start_date=2024-01-01&limit=50" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN"
Provisioning Statistics
curl -X GET "http://localhost:8080/api/scim-admin/stats?start_date=2024-01-01&end_date=2024-01-31" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Response:

{
  "total_operations": 1250,
  "successful_operations": 1238,
  "failed_operations": 12,
  "success_rate": 99.04,
  "operations_by_type": {
    "CREATE_USER": 500,
    "UPDATE_USER": 650,
    "DELETE_USER": 100
  },
  "average_duration_ms": 125.5
}

Webhooks

Send provisioning events to external systems:

webhooks:
  enabled: true
  notify_on_create: true
  notify_on_update: true
  notify_on_delete: true
  notify_on_group_sync: true
  webhook_urls:
    - "https://your-webhook-endpoint.com/scim-events"
  retry_attempts: 3
  timeout_seconds: 10

Troubleshooting

Common Issues
1. "Invalid or expired token"

Cause: Bearer token is invalid, expired, or revoked.

Solution: Generate a new provisioning token and update your IdP configuration.

2. "Rate limit exceeded"

Cause: Too many requests in a short period.

Solution:

  • Increase rate_limit.requests_per_min in config
  • Implement exponential backoff in your IdP
  • Use bulk operations for multiple users
3. "User with email already exists"

Cause: Duplicate email address.

Solution:

  • Set user_provisioning.prevent_duplicates: false to allow duplicates
  • Or ensure unique emails in your IdP
4. "Group synchronization failed"

Cause: Group sync is disabled or team/role doesn't exist.

Solution:

  • Enable group sync in configuration
  • Set group_sync.create_missing_groups: true
Testing SCIM Endpoints

Use the SCIM 2.0 Test Tool:

# Test Service Provider Config
curl http://localhost:8080/scim/v2/ServiceProviderConfig \
  -H "Authorization: Bearer YOUR_SCIM_TOKEN"

# Test User Listing
curl http://localhost:8080/scim/v2/Users \
  -H "Authorization: Bearer YOUR_SCIM_TOKEN"

# Test User Creation
curl -X POST http://localhost:8080/scim/v2/Users \
  -H "Authorization: Bearer YOUR_SCIM_TOKEN" \
  -H "Content-Type: application/scim+json" \
  -d '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"userName":"test@example.com"}'

Performance

Benchmarks
  • User creation: ~100ms p99 (including database write)
  • User lookup: ~10ms p99 (cached)
  • Bulk operations: ~500ms for 100 users
  • Rate limit: 600 requests/min per organization (configurable)
Optimization Tips
  1. Enable Bulk Operations: Use bulk endpoint for provisioning multiple users
  2. Increase Rate Limits: Adjust based on your needs
  3. Use Caching: Redis caching for attribute lookups
  4. Index Database: Ensure indexes on email, external_id

Security Best Practices

  1. Use HTTPS: Always use HTTPS in production
  2. Rotate Tokens: Regularly rotate provisioning tokens
  3. IP Whitelist: Restrict access to known IdP IPs
  4. Audit Logs: Monitor provisioning logs for suspicious activity
  5. Least Privilege: Use minimal scopes for tokens
  6. Soft Delete: Enable soft delete to prevent accidental data loss

Support

For issues, feature requests, or questions:

License

This plugin is part of the AuthSome framework and follows the same license.


Made with ❤️ by the AuthSome Team

Documentation

Index

Examples

Constants

View Source
const (
	PluginID      = "scim"
	PluginName    = "SCIM 2.0 Provisioning"
	PluginVersion = "1.0.0"
)
View Source
const (
	SchemaCore            = "urn:ietf:params:scim:schemas:core:2.0:User"
	SchemaEnterprise      = "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
	SchemaGroup           = "urn:ietf:params:scim:schemas:core:2.0:Group"
	SchemaServiceProvider = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"
	SchemaResourceType    = "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
	SchemaSchema          = "urn:ietf:params:scim:schemas:core:2.0:Schema"
	SchemaListResponse    = "urn:ietf:params:scim:api:messages:2.0:ListResponse"
	SchemaError           = "urn:ietf:params:scim:api:messages:2.0:Error"
	SchemaBulkRequest     = "urn:ietf:params:scim:api:messages:2.0:BulkRequest"
	SchemaBulkResponse    = "urn:ietf:params:scim:api:messages:2.0:BulkResponse"
	SchemaPatchOp         = "urn:ietf:params:scim:api:messages:2.0:PatchOp"
)

SCIM 2.0 Schema URNs (RFC 7643)

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

type Address struct {
	Formatted     string `json:"formatted,omitempty"`
	StreetAddress string `json:"streetAddress,omitempty"`
	Locality      string `json:"locality,omitempty"`
	Region        string `json:"region,omitempty"`
	PostalCode    string `json:"postalCode,omitempty"`
	Country       string `json:"country,omitempty"`
	Type          string `json:"type,omitempty"` // work, home, other
	Primary       bool   `json:"primary,omitempty"`
}

Address represents a physical mailing address (RFC 7643 Section 4.1.2)

type Attribute

type Attribute struct {
	Name            string      `json:"name"`
	Type            string      `json:"type"` // string, boolean, decimal, integer, dateTime, reference, complex, binary
	MultiValued     bool        `json:"multiValued"`
	Description     string      `json:"description,omitempty"`
	Required        bool        `json:"required"`
	CanonicalValues []string    `json:"canonicalValues,omitempty"`
	CaseExact       bool        `json:"caseExact"`
	Mutability      string      `json:"mutability"` // readOnly, readWrite, immutable, writeOnly
	Returned        string      `json:"returned"`   // always, never, default, request
	Uniqueness      string      `json:"uniqueness"` // none, server, global
	SubAttributes   []Attribute `json:"subAttributes,omitempty"`
	ReferenceTypes  []string    `json:"referenceTypes,omitempty"`
}

Attribute represents a schema attribute (RFC 7643 Section 7)

type AttributeMapping

type AttributeMapping struct {
	ID             xid.ID                 `bun:"id,pk,type:varchar(20)"`
	AppID          xid.ID                 `bun:"app_id,type:varchar(20),notnull"`                                    // Platform app
	EnvironmentID  xid.ID                 `bun:"environment_id,type:varchar(20),notnull"`                            // Target environment
	OrganizationID xid.ID                 `bun:"organization_id,type:varchar(20),notnull,unique:org_mapping_unique"` // User-created organization
	Mappings       map[string]string      `bun:"mappings,type:jsonb,notnull"`                                        // SCIM attr -> AuthSome field
	Metadata       map[string]interface{} `bun:"metadata,type:jsonb"`
	CreatedAt      time.Time              `bun:"created_at,notnull"`
	UpdatedAt      time.Time              `bun:"updated_at,notnull"`
}

AttributeMapping represents custom attribute mappings per organization Updated for 3-tier architecture: App → Environment → Organization

type AttributeMappingConfig

type AttributeMappingConfig struct {
	Enabled       bool              `json:"enabled" yaml:"enabled"`
	CustomMapping map[string]string `json:"custom_mapping" yaml:"custom_mapping"` // Map SCIM attribute to AuthSome field

	// Standard SCIM User schema mappings (RFC 7643)
	UserNameField    string `json:"username_field" yaml:"username_field"`         // Default: "userName"
	EmailField       string `json:"email_field" yaml:"email_field"`               // Default: "emails[0].value"
	GivenNameField   string `json:"given_name_field" yaml:"given_name_field"`     // Default: "name.givenName"
	FamilyNameField  string `json:"family_name_field" yaml:"family_name_field"`   // Default: "name.familyName"
	DisplayNameField string `json:"display_name_field" yaml:"display_name_field"` // Default: "displayName"
	ActiveField      string `json:"active_field" yaml:"active_field"`             // Default: "active"

	// Enterprise schema extension (urn:ietf:params:scim:schemas:extension:enterprise:2.0:User)
	EmployeeNumberField string `json:"employee_number_field" yaml:"employee_number_field"` // Default: "employeeNumber"
	DepartmentField     string `json:"department_field" yaml:"department_field"`           // Default: "department"
	ManagerField        string `json:"manager_field" yaml:"manager_field"`                 // Default: "manager.value"
}

AttributeMappingConfig configures custom attribute mapping

type AttributeMappingsResponse

type AttributeMappingsResponse struct {
	ID       string            `json:"id"`
	Mappings map[string]string `json:"mappings"`
}

AttributeMappingsResponse is the response for attribute mappings

type AuthenticationScheme

type AuthenticationScheme struct {
	Type             string `json:"type"` // oauth, oauth2, oauthbearertoken, httpbasic, httpdigest
	Name             string `json:"name"`
	Description      string `json:"description"`
	SpecURI          string `json:"specUri,omitempty"`
	DocumentationURI string `json:"documentationUri,omitempty"`
	Primary          bool   `json:"primary,omitempty"`
}

AuthenticationScheme represents an authentication scheme (RFC 7643 Section 5)

type BulkOperation

type BulkOperation struct {
	Method  string      `json:"method"` // POST, PUT, PATCH, DELETE
	BulkID  string      `json:"bulkId,omitempty"`
	Version string      `json:"version,omitempty"`
	Path    string      `json:"path"`
	Data    interface{} `json:"data,omitempty"`
}

BulkOperation represents a single bulk operation (RFC 7644 Section 3.7)

type BulkOperationResult

type BulkOperationResult struct {
	Method   string      `json:"method"`
	BulkID   string      `json:"bulkId,omitempty"`
	Version  string      `json:"version,omitempty"`
	Location string      `json:"location,omitempty"`
	Status   int         `json:"status"`
	Response interface{} `json:"response,omitempty"`
}

BulkOperationResult represents a single bulk operation result (RFC 7644 Section 3.7)

type BulkOperationsConfig

type BulkOperationsConfig struct {
	Enabled         bool `json:"enabled" yaml:"enabled"`
	MaxOperations   int  `json:"max_operations" yaml:"max_operations"`       // Max operations per bulk request
	MaxPayloadBytes int  `json:"max_payload_bytes" yaml:"max_payload_bytes"` // Max payload size in bytes
}

BulkOperationsConfig configures bulk operation limits

type BulkRequest

type BulkRequest struct {
	Schemas      []string        `json:"schemas"`
	FailOnErrors int             `json:"failOnErrors,omitempty"`
	Operations   []BulkOperation `json:"Operations"`
}

BulkRequest represents a bulk operation request (RFC 7644 Section 3.7)

type BulkResponse

type BulkResponse struct {
	Schemas    []string              `json:"schemas"`
	Operations []BulkOperationResult `json:"Operations"`
}

BulkResponse represents a bulk operation response (RFC 7644 Section 3.7)

type BulkSupport

type BulkSupport struct {
	Supported      bool `json:"supported"`
	MaxOperations  int  `json:"maxOperations"`
	MaxPayloadSize int  `json:"maxPayloadSize"`
}

BulkSupport indicates bulk operation support (RFC 7643 Section 5)

type Config

type Config struct {
	// Service configuration
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Authentication
	AuthMethod  string        `json:"auth_method" yaml:"auth_method"` // "bearer" or "oauth2"
	TokenExpiry time.Duration `json:"token_expiry" yaml:"token_expiry"`

	// Rate limiting
	RateLimit RateLimitConfig `json:"rate_limit" yaml:"rate_limit"`

	// User provisioning
	UserProvisioning UserProvisioningConfig `json:"user_provisioning" yaml:"user_provisioning"`

	// Group synchronization
	GroupSync GroupSyncConfig `json:"group_sync" yaml:"group_sync"`

	// Attribute mapping
	AttributeMapping AttributeMappingConfig `json:"attribute_mapping" yaml:"attribute_mapping"`

	// JIT provisioning
	JITProvisioning JITProvisioningConfig `json:"jit_provisioning" yaml:"jit_provisioning"`

	// Webhooks
	Webhooks WebhookConfig `json:"webhooks" yaml:"webhooks"`

	// Bulk operations
	BulkOperations BulkOperationsConfig `json:"bulk_operations" yaml:"bulk_operations"`

	// Filtering and search
	Search SearchConfig `json:"search" yaml:"search"`

	// Compliance and security
	Security SecurityConfig `json:"security" yaml:"security"`
}

Config holds the SCIM plugin configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns the default SCIM configuration

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

type CreateTokenRequest

type CreateTokenRequest struct {
	Name        string     `json:"name" validate:"required"`
	Description string     `json:"description"`
	Scopes      []string   `json:"scopes" validate:"required,min=1"`
	ExpiresAt   *time.Time `json:"expiresAt"`
}

CreateTokenRequest is the request body for creating a provisioning token

type Email

type Email struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // work, home, other
	Primary bool   `json:"primary,omitempty"`
}

Email represents an email address (RFC 7643 Section 4.1.2)

type EnterpriseUser

type EnterpriseUser struct {
	EmployeeNumber string            `json:"employeeNumber,omitempty"`
	CostCenter     string            `json:"costCenter,omitempty"`
	Organization   string            `json:"organization,omitempty"`
	Division       string            `json:"division,omitempty"`
	Department     string            `json:"department,omitempty"`
	Manager        *ManagerReference `json:"manager,omitempty"`
}

EnterpriseUser represents enterprise user extension (RFC 7643 Section 4.3)

type Entitlement

type Entitlement struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"`
	Primary bool   `json:"primary,omitempty"`
}

Entitlement represents an entitlement (RFC 7643 Section 4.1.2)

type ErrorResponse

type ErrorResponse struct {
	Schemas  []string `json:"schemas"`
	Status   int      `json:"status"`
	ScimType string   `json:"scimType,omitempty"` // invalidFilter, tooMany, uniqueness, mutability, invalidSyntax, invalidPath, invalidValue, invalidVers, sensitive, notTarget
	Detail   string   `json:"detail,omitempty"`
}

ErrorResponse represents a SCIM error response (RFC 7644 Section 3.12)

type FilterSupport

type FilterSupport struct {
	Supported  bool `json:"supported"`
	MaxResults int  `json:"maxResults"`
}

FilterSupport indicates filter support (RFC 7643 Section 5)

type GroupMapping

type GroupMapping struct {
	ID             xid.ID    `bun:"id,pk,type:varchar(20)"`
	AppID          xid.ID    `bun:"app_id,type:varchar(20),notnull"`          // Platform app
	EnvironmentID  xid.ID    `bun:"environment_id,type:varchar(20),notnull"`  // Target environment
	OrganizationID xid.ID    `bun:"organization_id,type:varchar(20),notnull"` // User-created organization
	SCIMGroupID    string    `bun:"scim_group_id,notnull"`
	SCIMGroupName  string    `bun:"scim_group_name,notnull"`
	MappingType    string    `bun:"mapping_type,notnull"`               // team, role (in user-created organization)
	TargetID       xid.ID    `bun:"target_id,type:varchar(20),notnull"` // Team ID or Role ID in user organization
	CreatedAt      time.Time `bun:"created_at,notnull"`
	UpdatedAt      time.Time `bun:"updated_at,notnull"`
}

GroupMapping represents SCIM group to user-created organization team/role mapping Updated for 3-tier architecture: App → Environment → Organization

type GroupReference

type GroupReference struct {
	Value   string `json:"value"` // Group ID
	Ref     string `json:"$ref,omitempty"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // direct, indirect
}

GroupReference represents a group membership (RFC 7643 Section 4.1.2)

type GroupSyncConfig

type GroupSyncConfig struct {
	Enabled             bool              `json:"enabled" yaml:"enabled"`
	SyncToTeams         bool              `json:"sync_to_teams" yaml:"sync_to_teams"`                 // Sync SCIM groups to teams
	SyncToRoles         bool              `json:"sync_to_roles" yaml:"sync_to_roles"`                 // Sync SCIM groups to roles
	GroupMapping        map[string]string `json:"group_mapping" yaml:"group_mapping"`                 // Map SCIM group ID to team/role ID
	CreateMissingGroups bool              `json:"create_missing_groups" yaml:"create_missing_groups"` // Auto-create teams/roles
	DeleteEmptyGroups   bool              `json:"delete_empty_groups" yaml:"delete_empty_groups"`     // Delete teams/roles with no members
}

GroupSyncConfig configures group synchronization with teams/roles

type GroupsResponse

type GroupsResponse struct {
	Groups []SCIMGroup `json:"groups"`
	Total  int         `json:"total"`
}

GroupsResponse wraps group list response for clarity

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler handles SCIM HTTP requests

func NewHandler

func NewHandler(service *Service, config *Config) *Handler

NewHandler creates a new SCIM handler

func (*Handler) BulkOperation

func (h *Handler) BulkOperation(c forge.Context) error

BulkOperation handles bulk operations

func (*Handler) CreateGroup

func (h *Handler) CreateGroup(c forge.Context) error

CreateGroup creates a new group

func (*Handler) CreateProvisioningToken

func (h *Handler) CreateProvisioningToken(c forge.Context) error

CreateProvisioningToken creates a new provisioning token

func (*Handler) CreateUser

func (h *Handler) CreateUser(c forge.Context) error

CreateUser creates a new user

Example

Example: SCIM User creation request

package main

import ()

func main() {
	// POST /scim/v2/Users
	// Authorization: Bearer <token>
	// Content-Type: application/scim+json
	//
	// {
	//   "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
	//   "userName": "bjensen@example.com",
	//   "name": {
	//     "givenName": "Barbara",
	//     "familyName": "Jensen"
	//   },
	//   "emails": [{
	//     "value": "bjensen@example.com",
	//     "type": "work",
	//     "primary": true
	//   }],
	//   "active": true
	// }
}

func (*Handler) DeleteGroup

func (h *Handler) DeleteGroup(c forge.Context) error

DeleteGroup deletes a group

func (*Handler) DeleteUser

func (h *Handler) DeleteUser(c forge.Context) error

DeleteUser deletes a user

func (*Handler) GetAttributeMappings

func (h *Handler) GetAttributeMappings(c forge.Context) error

GetAttributeMappings gets attribute mappings

func (*Handler) GetGroup

func (h *Handler) GetGroup(c forge.Context) error

GetGroup retrieves a specific group

func (*Handler) GetProvisioningLogs

func (h *Handler) GetProvisioningLogs(c forge.Context) error

GetProvisioningLogs gets provisioning logs

func (*Handler) GetProvisioningStats

func (h *Handler) GetProvisioningStats(c forge.Context) error

GetProvisioningStats gets provisioning statistics

func (*Handler) GetResourceType

func (h *Handler) GetResourceType(c forge.Context) error

GetResourceType returns a specific resource type

func (*Handler) GetResourceTypes

func (h *Handler) GetResourceTypes(c forge.Context) error

GetResourceTypes returns all supported resource types

func (*Handler) GetSchema

func (h *Handler) GetSchema(c forge.Context) error

GetSchema returns a specific schema

func (*Handler) GetSchemas

func (h *Handler) GetSchemas(c forge.Context) error

GetSchemas returns all supported schemas

func (*Handler) GetServiceProviderConfig

func (h *Handler) GetServiceProviderConfig(c forge.Context) error

GetServiceProviderConfig returns the service provider configuration

func (*Handler) GetUser

func (h *Handler) GetUser(c forge.Context) error

GetUser retrieves a specific user

func (*Handler) ListGroups

func (h *Handler) ListGroups(c forge.Context) error

ListGroups lists groups

func (*Handler) ListProvisioningTokens

func (h *Handler) ListProvisioningTokens(c forge.Context) error

ListProvisioningTokens lists provisioning tokens

func (*Handler) ListUsers

func (h *Handler) ListUsers(c forge.Context) error

ListUsers lists users with filtering and pagination

func (*Handler) ReplaceGroup

func (h *Handler) ReplaceGroup(c forge.Context) error

ReplaceGroup replaces a group (PUT)

func (*Handler) ReplaceUser

func (h *Handler) ReplaceUser(c forge.Context) error

ReplaceUser replaces a user (PUT)

func (*Handler) RevokeProvisioningToken

func (h *Handler) RevokeProvisioningToken(c forge.Context) error

RevokeProvisioningToken revokes a provisioning token

func (*Handler) Search

func (h *Handler) Search(c forge.Context) error

Search handles the /.search endpoint

func (*Handler) UpdateAttributeMappings

func (h *Handler) UpdateAttributeMappings(c forge.Context) error

UpdateAttributeMappings updates attribute mappings

func (*Handler) UpdateGroup

func (h *Handler) UpdateGroup(c forge.Context) error

UpdateGroup updates a group (PATCH)

func (*Handler) UpdateUser

func (h *Handler) UpdateUser(c forge.Context) error

UpdateUser updates a user (PATCH)

type IM

type IM struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // aim, gtalk, icq, xmpp, msn, skype, qq, yahoo
	Primary bool   `json:"primary,omitempty"`
}

IM represents an instant messaging address (RFC 7643 Section 4.1.2)

type JITProvisioningConfig

type JITProvisioningConfig struct {
	Enabled            bool     `json:"enabled" yaml:"enabled"`
	CreateOnFirstLogin bool     `json:"create_on_first_login" yaml:"create_on_first_login"` // Create user on first SSO login
	UpdateOnLogin      bool     `json:"update_on_login" yaml:"update_on_login"`             // Update user attributes on each login
	RequiredAttributes []string `json:"required_attributes" yaml:"required_attributes"`
}

JITProvisioningConfig configures Just-In-Time provisioning

type ListResponse

type ListResponse struct {
	Schemas      []string      `json:"schemas"`
	TotalResults int           `json:"totalResults"`
	StartIndex   int           `json:"startIndex"`
	ItemsPerPage int           `json:"itemsPerPage"`
	Resources    []interface{} `json:"Resources"`
}

ListResponse represents a SCIM list response (RFC 7644 Section 3.4.2)

type LogsResponse

type LogsResponse struct {
	Logs  []ProvisioningLog `json:"logs"`
	Total int               `json:"total"`
	Page  int               `json:"page"`
	Limit int               `json:"limit"`
}

LogsResponse represents a list of provisioning logs

type ManagerReference

type ManagerReference struct {
	Value       string `json:"value"` // Manager's ID
	Ref         string `json:"$ref,omitempty"`
	DisplayName string `json:"displayName,omitempty"`
}

ManagerReference represents a manager reference (RFC 7643 Section 4.3.1)

type MemberReference

type MemberReference struct {
	Value   string `json:"value"` // User ID
	Ref     string `json:"$ref,omitempty"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // User or Group
}

MemberReference represents a group member (RFC 7643 Section 4.2)

type MessageResponse

type MessageResponse = responses.MessageResponse

Response types - use shared responses from core

type Meta

type Meta struct {
	ResourceType string    `json:"resourceType"`
	Created      time.Time `json:"created"`
	LastModified time.Time `json:"lastModified"`
	Location     string    `json:"location"`
	Version      string    `json:"version,omitempty"`
}

Meta contains resource metadata (RFC 7643 Section 3.1)

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics collects SCIM plugin metrics using Go's built-in expvar These metrics are automatically exposed via the /debug/vars endpoint

func GetMetrics

func GetMetrics() *Metrics

GetMetrics returns the singleton metrics instance

func (*Metrics) DecrementActiveRequests

func (m *Metrics) DecrementActiveRequests()

DecrementActiveRequests decrements the active request counter

func (*Metrics) GetStats

func (m *Metrics) GetStats() map[string]interface{}

GetStats returns current statistics

func (*Metrics) IncrementActiveRequests

func (m *Metrics) IncrementActiveRequests()

IncrementActiveRequests increments the active request counter

func (*Metrics) RecordBulkOperation

func (m *Metrics) RecordBulkOperation(operationCount int)

RecordBulkOperation records a bulk operation

func (*Metrics) RecordError

func (m *Metrics) RecordError(errorType string)

RecordError records an error by type

func (*Metrics) RecordGroupOperation

func (m *Metrics) RecordGroupOperation(operation string)

RecordGroupOperation records a group operation

func (*Metrics) RecordOperation

func (m *Metrics) RecordOperation(operation, status, orgID string)

RecordOperation records a SCIM operation

func (*Metrics) RecordRateLimitHit

func (m *Metrics) RecordRateLimitHit()

RecordRateLimitHit records a rate limit hit

func (*Metrics) RecordRequestDuration

func (m *Metrics) RecordRequestDuration(endpoint string, duration time.Duration)

RecordRequestDuration records the duration of a SCIM request

func (*Metrics) RecordTokenCreation

func (m *Metrics) RecordTokenCreation()

RecordTokenCreation records a token creation

func (*Metrics) RecordTokenRevocation

func (m *Metrics) RecordTokenRevocation()

RecordTokenRevocation records a token revocation

func (*Metrics) RecordTokenValidation

func (m *Metrics) RecordTokenValidation(success bool)

RecordTokenValidation records a token validation attempt

func (*Metrics) RecordUserOperation

func (m *Metrics) RecordUserOperation(operation string)

RecordUserOperation records a user provisioning operation

func (*Metrics) RecordWebhook

func (m *Metrics) RecordWebhook(success bool, retried bool)

RecordWebhook records a webhook operation

func (*Metrics) Reset

func (m *Metrics) Reset()

Reset resets all metrics (useful for testing)

type Name

type Name struct {
	Formatted       string `json:"formatted,omitempty"`
	FamilyName      string `json:"familyName,omitempty"`
	GivenName       string `json:"givenName,omitempty"`
	MiddleName      string `json:"middleName,omitempty"`
	HonorificPrefix string `json:"honorificPrefix,omitempty"`
	HonorificSuffix string `json:"honorificSuffix,omitempty"`
}

Name represents a user's name (RFC 7643 Section 4.1.1)

type PatchOp

type PatchOp struct {
	Schemas    []string         `json:"schemas"`
	Operations []PatchOperation `json:"Operations"`
}

PatchOp represents a PATCH operation (RFC 7644 Section 3.5.2)

type PatchOperation

type PatchOperation struct {
	Op    string      `json:"op"` // add, remove, replace
	Path  string      `json:"path,omitempty"`
	Value interface{} `json:"value,omitempty"`
}

PatchOperation represents a single patch operation (RFC 7644 Section 3.5.2)

type PhoneNumber

type PhoneNumber struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // work, home, mobile, fax, pager, other
	Primary bool   `json:"primary,omitempty"`
}

PhoneNumber represents a phone number (RFC 7643 Section 4.1.2)

type Photo

type Photo struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"` // photo, thumbnail
	Primary bool   `json:"primary,omitempty"`
}

Photo represents a photo URL (RFC 7643 Section 4.1.2)

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

Plugin implements the SCIM 2.0 provisioning plugin for enterprise identity providers

Example (Basic)

Example: Basic SCIM plugin integration

package main

import (
	"context"

	"github.com/xraph/authsome"
	"github.com/xraph/authsome/plugins/enterprise/scim"
)

func main() {
	// Create AuthSome instance
	auth := authsome.New(
	// Configure with valid options
	)

	// Register SCIM plugin
	scimPlugin := scim.NewPlugin()
	auth.RegisterPlugin(scimPlugin)

	// Initialize (runs migrations)
	ctx := context.Background()
	auth.Initialize(ctx)

	// Mount routes
	// auth.Mount(router, "/api/auth")

	// SCIM endpoints are now available at:
	// - /api/auth/scim/v2/Users
	// - /api/auth/scim/v2/Groups
	// - /api/auth/scim/v2/Bulk
}

func NewPlugin

func NewPlugin() *Plugin

NewPlugin creates a new SCIM plugin instance

func (*Plugin) AuthMiddleware

func (p *Plugin) AuthMiddleware() func(func(forge.Context) error) func(forge.Context) error

AuthMiddleware validates SCIM bearer tokens

func (*Plugin) Description

func (p *Plugin) Description() string

Description returns the plugin description (optional, for documentation)

func (*Plugin) Health

func (p *Plugin) Health(ctx context.Context) error

Health checks plugin health

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique plugin identifier

func (*Plugin) IPWhitelistMiddleware

func (p *Plugin) IPWhitelistMiddleware() func(func(forge.Context) error) func(forge.Context) error

IPWhitelistMiddleware enforces IP whitelisting if configured

func (*Plugin) Init

func (p *Plugin) Init(auth core.Authsome) error

Init initializes the plugin with dependencies from the Auth instance

func (*Plugin) LoggingMiddleware

func (p *Plugin) LoggingMiddleware() func(func(forge.Context) error) func(forge.Context) error

LoggingMiddleware logs SCIM operations for audit

func (*Plugin) Migrate

func (p *Plugin) Migrate() error

Migrate runs database migrations for SCIM-specific tables

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the human-readable plugin name (optional, for dashboard display)

func (*Plugin) OrgResolutionMiddleware

func (p *Plugin) OrgResolutionMiddleware() func(func(forge.Context) error) func(forge.Context) error

OrgResolutionMiddleware ensures organization context is set (3-tier architecture)

func (*Plugin) RateLimitMiddleware

func (p *Plugin) RateLimitMiddleware() func(func(forge.Context) error) func(forge.Context) error

RateLimitMiddleware implements rate limiting for SCIM endpoints

func (*Plugin) RegisterHooks

func (p *Plugin) RegisterHooks(hooks *hooks.HookRegistry) error

RegisterHooks registers lifecycle hooks for SCIM events

func (*Plugin) RegisterRoutes

func (p *Plugin) RegisterRoutes(router forge.Router) error

RegisterRoutes registers SCIM 2.0 compliant HTTP routes

func (*Plugin) RegisterServiceDecorators

func (p *Plugin) RegisterServiceDecorators(services *registry.ServiceRegistry) error

RegisterServiceDecorators allows SCIM plugin to enhance core services

func (*Plugin) RequireAdminMiddleware

func (p *Plugin) RequireAdminMiddleware() func(func(forge.Context) error) func(forge.Context) error

RequireAdminMiddleware ensures the request is from an admin

func (*Plugin) SecurityHeadersMiddleware

func (p *Plugin) SecurityHeadersMiddleware() func(func(forge.Context) error) func(forge.Context) error

SecurityHeadersMiddleware adds security headers to SCIM responses

func (*Plugin) Service

func (p *Plugin) Service() *Service

Service returns the SCIM service for programmatic access

func (*Plugin) Shutdown

func (p *Plugin) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the plugin

func (*Plugin) Version

func (p *Plugin) Version() string

Version returns the plugin version (optional, for compatibility checks)

type ProvisioningLog

type ProvisioningLog struct {
	ID             xid.ID                 `bun:"id,pk,type:varchar(20)"`
	AppID          xid.ID                 `bun:"app_id,type:varchar(20),notnull"`          // Platform app
	EnvironmentID  xid.ID                 `bun:"environment_id,type:varchar(20),notnull"`  // Target environment
	OrganizationID xid.ID                 `bun:"organization_id,type:varchar(20),notnull"` // User-created organization
	TokenID        xid.ID                 `bun:"token_id,type:varchar(20)"`
	Operation      string                 `bun:"operation,notnull"`     // CREATE_USER, UPDATE_USER, DELETE_USER, etc.
	ResourceType   string                 `bun:"resource_type,notnull"` // User, Group
	ResourceID     string                 `bun:"resource_id"`
	ExternalID     string                 `bun:"external_id"`
	Method         string                 `bun:"method,notnull"` // POST, PUT, PATCH, DELETE
	Path           string                 `bun:"path,notnull"`
	StatusCode     int                    `bun:"status_code,notnull"`
	Success        bool                   `bun:"success,notnull"`
	ErrorMessage   string                 `bun:"error_message"`
	RequestBody    map[string]interface{} `bun:"request_body,type:jsonb"`
	ResponseBody   map[string]interface{} `bun:"response_body,type:jsonb"`
	IPAddress      string                 `bun:"ip_address"`
	UserAgent      string                 `bun:"user_agent"`
	DurationMS     int                    `bun:"duration_ms"`
	CreatedAt      time.Time              `bun:"created_at,notnull"`
}

ProvisioningLog represents a log entry for provisioning operations Updated for 3-tier architecture: App → Environment → Organization

type ProvisioningToken

type ProvisioningToken struct {
	ID             xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID          xid.ID     `bun:"app_id,type:varchar(20),notnull"`          // Platform app
	EnvironmentID  xid.ID     `bun:"environment_id,type:varchar(20),notnull"`  // Target environment (dev, prod, etc.)
	OrganizationID xid.ID     `bun:"organization_id,type:varchar(20),notnull"` // User-created organization
	Name           string     `bun:"name,notnull"`
	Description    string     `bun:"description"`
	TokenHash      string     `bun:"token_hash,notnull,unique"` // bcrypt hash
	TokenPrefix    string     `bun:"token_prefix,notnull"`      // First 8 chars for identification
	Scopes         []string   `bun:"scopes,type:text[],notnull"`
	ExpiresAt      *time.Time `bun:"expires_at"`
	LastUsedAt     *time.Time `bun:"last_used_at"`
	CreatedBy      xid.ID     `bun:"created_by,type:varchar(20)"`
	CreatedAt      time.Time  `bun:"created_at,notnull"`
	UpdatedAt      time.Time  `bun:"updated_at,notnull"`
	RevokedAt      *time.Time `bun:"revoked_at"`
}

ProvisioningToken represents a SCIM provisioning token (Bearer token) Updated for 3-tier architecture: App → Environment → Organization

type ProvisioningTokenInfo

type ProvisioningTokenInfo struct {
	ID          string     `json:"id"`
	Name        string     `json:"name"`
	Description string     `json:"description"`
	Scopes      []string   `json:"scopes"`
	ExpiresAt   *time.Time `json:"expiresAt"`
	LastUsedAt  *time.Time `json:"lastUsedAt"`
	CreatedAt   time.Time  `json:"createdAt"`
	RevokedAt   *time.Time `json:"revokedAt,omitempty"`
}

ProvisioningTokenInfo contains token metadata without the actual token

type RateLimitConfig

type RateLimitConfig struct {
	Enabled        bool `json:"enabled" yaml:"enabled"`
	RequestsPerMin int  `json:"requests_per_min" yaml:"requests_per_min"`
	BurstSize      int  `json:"burst_size" yaml:"burst_size"`
}

RateLimitConfig configures rate limiting for SCIM endpoints

type Repository

type Repository struct {
	// contains filtered or unexported fields
}

Repository handles SCIM data persistence

func NewRepository

func NewRepository(db *bun.DB) *Repository

NewRepository creates a new SCIM repository

func (*Repository) CountProvisioningLogs

func (r *Repository) CountProvisioningLogs(ctx context.Context, appID, envID, orgID xid.ID, filters map[string]interface{}) (int, error)

CountProvisioningLogs counts provisioning logs with filtering

func (*Repository) CountProvisioningTokens

func (r *Repository) CountProvisioningTokens(ctx context.Context, appID, envID, orgID xid.ID) (int, error)

CountProvisioningTokens counts active tokens for an organization Updated for 3-tier architecture

func (*Repository) CreateAttributeMapping

func (r *Repository) CreateAttributeMapping(ctx context.Context, mapping *AttributeMapping) error

CreateAttributeMapping creates a new attribute mapping

func (*Repository) CreateGroupMapping

func (r *Repository) CreateGroupMapping(ctx context.Context, mapping *GroupMapping) error

CreateGroupMapping creates a new group mapping

func (*Repository) CreateProvisioningLog

func (r *Repository) CreateProvisioningLog(ctx context.Context, log *ProvisioningLog) error

CreateProvisioningLog creates a new provisioning log entry

func (*Repository) CreateProvisioningToken

func (r *Repository) CreateProvisioningToken(ctx context.Context, token *ProvisioningToken) error

CreateProvisioningToken creates a new provisioning token

func (*Repository) DeleteGroupMapping

func (r *Repository) DeleteGroupMapping(ctx context.Context, id xid.ID) error

DeleteGroupMapping deletes a group mapping

func (*Repository) FindAttributeMappingByOrganization

func (r *Repository) FindAttributeMappingByOrganization(ctx context.Context, appID, envID, orgID xid.ID) (*AttributeMapping, error)

FindAttributeMappingByOrgID finds attribute mapping by organization ID

func (*Repository) FindGroupMapping

func (r *Repository) FindGroupMapping(ctx context.Context, appID, envID, orgID xid.ID, scimGroupID string) (*GroupMapping, error)

FindGroupMapping finds a group mapping by SCIM group ID

func (*Repository) FindGroupMappingBySCIMID

func (r *Repository) FindGroupMappingBySCIMID(ctx context.Context, appID, envID, orgID xid.ID, scimGroupID string) (*GroupMapping, error)

FindGroupMappingBySCIMID finds a group mapping by SCIM group ID Updated for 3-tier architecture

func (*Repository) FindGroupMappingByTargetID

func (r *Repository) FindGroupMappingByTargetID(ctx context.Context, targetID xid.ID) (*GroupMapping, error)

FindGroupMappingByTargetID finds a group mapping by target team ID

func (*Repository) FindProvisioningTokenByID

func (r *Repository) FindProvisioningTokenByID(ctx context.Context, id xid.ID) (*ProvisioningToken, error)

FindProvisioningTokenByID finds a token by ID

func (*Repository) FindProvisioningTokenByPrefix

func (r *Repository) FindProvisioningTokenByPrefix(ctx context.Context, prefix string) (*ProvisioningToken, error)

FindProvisioningTokenByPrefix finds a token by its prefix

func (*Repository) GetAttributeMapping

func (r *Repository) GetAttributeMapping(ctx context.Context, appID, envID, orgID xid.ID) (*AttributeMapping, error)

GetAttributeMapping gets attribute mapping for an organization

func (*Repository) GetProvisioningStats

func (r *Repository) GetProvisioningStats(ctx context.Context, appID, envID, orgID xid.ID, startDate, endDate time.Time) (map[string]interface{}, error)

GetProvisioningStats returns provisioning statistics

func (*Repository) ListGroupMappings

func (r *Repository) ListGroupMappings(ctx context.Context, appID, envID, orgID xid.ID) ([]*GroupMapping, error)

ListGroupMappings lists all group mappings for an organization

func (*Repository) ListProvisioningLogs

func (r *Repository) ListProvisioningLogs(ctx context.Context, appID, envID, orgID xid.ID, filters map[string]interface{}, limit, offset int) ([]*ProvisioningLog, error)

ListProvisioningLogs lists provisioning logs with filtering Updated for 3-tier architecture

func (*Repository) ListProvisioningTokens

func (r *Repository) ListProvisioningTokens(ctx context.Context, appID, envID, orgID xid.ID, limit, offset int) ([]*ProvisioningToken, error)

ListProvisioningTokens lists all provisioning tokens for an organization Updated for 3-tier architecture: App → Environment → Organization

func (*Repository) Migrate

func (r *Repository) Migrate(ctx context.Context) error

Migrate runs database migrations

func (*Repository) Ping

func (r *Repository) Ping(ctx context.Context) error

Ping checks database connectivity

func (*Repository) RevokeProvisioningToken

func (r *Repository) RevokeProvisioningToken(ctx context.Context, id xid.ID) error

RevokeProvisioningToken revokes a provisioning token

func (*Repository) UpdateAttributeMapping

func (r *Repository) UpdateAttributeMapping(ctx context.Context, mapping *AttributeMapping) error

UpdateAttributeMapping updates attribute mapping

func (*Repository) UpdateGroupMapping

func (r *Repository) UpdateGroupMapping(ctx context.Context, mapping *GroupMapping) error

UpdateGroupMapping updates a group mapping

func (*Repository) UpdateProvisioningToken

func (r *Repository) UpdateProvisioningToken(ctx context.Context, token *ProvisioningToken) error

UpdateProvisioningToken updates a provisioning token

func (*Repository) UpdateTeamMemberProvisioningInfo added in v0.0.2

func (r *Repository) UpdateTeamMemberProvisioningInfo(ctx context.Context, teamID, memberID xid.ID, provisionedBy *string) error

UpdateTeamMemberProvisioningInfo updates team member provisioning tracking field This method updates both app team members and organization team members

func (*Repository) UpdateTeamProvisioningInfo added in v0.0.2

func (r *Repository) UpdateTeamProvisioningInfo(ctx context.Context, teamID xid.ID, provisionedBy, externalID *string) error

UpdateTeamProvisioningInfo updates team provisioning tracking fields This method updates both app teams and organization teams

type ResourceType

type ResourceType struct {
	Schemas          []string          `json:"schemas"`
	ID               string            `json:"id"`
	Name             string            `json:"name"`
	Endpoint         string            `json:"endpoint"`
	Description      string            `json:"description,omitempty"`
	Schema           string            `json:"schema"`
	SchemaExtensions []SchemaExtension `json:"schemaExtensions,omitempty"`
	Meta             *Meta             `json:"meta"`
}

ResourceType represents a resource type (RFC 7643 Section 6)

type Role

type Role struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"`
	Primary bool   `json:"primary,omitempty"`
}

Role represents a role (RFC 7643 Section 4.1.2)

type SCIMAttributeMappingsResponse

type SCIMAttributeMappingsResponse struct {
	Mappings map[string]string `json:"mappings" example:"userName:email,displayName:name"`
}

SCIMAttributeMappingsResponse represents attribute mappings response

type SCIMErrorResponse

type SCIMErrorResponse struct {
	Error string `json:"error" example:"Error message"`
}

SCIMErrorResponse represents an error response for admin endpoints

type SCIMGroup

type SCIMGroup struct {
	Schemas     []string          `json:"schemas"`
	ID          string            `json:"id"`
	ExternalID  string            `json:"externalId,omitempty"`
	Meta        *Meta             `json:"meta"`
	DisplayName string            `json:"displayName"`
	Members     []MemberReference `json:"members,omitempty"`
}

SCIMGroup represents a SCIM 2.0 Group resource (RFC 7643 Section 4.2)

type SCIMLogInfo

type SCIMLogInfo struct {
	ID           string    `json:"id" example:"01HZ..."`
	Operation    string    `json:"operation" example:"CREATE_USER"`
	ResourceType string    `json:"resource_type" example:"User"`
	ResourceID   string    `json:"resource_id" example:"01HZ..."`
	Method       string    `json:"method" example:"POST"`
	Path         string    `json:"path" example:"/scim/v2/Users"`
	StatusCode   int       `json:"status_code" example:"201"`
	Success      bool      `json:"success" example:"true"`
	ErrorMessage string    `json:"error_message"`
	CreatedAt    time.Time `json:"created_at"`
	DurationMS   int       `json:"duration_ms" example:"45"`
}

SCIMLogInfo represents a single log entry

type SCIMLogsResponse

type SCIMLogsResponse struct {
	Logs   []SCIMLogInfo `json:"logs"`
	Total  int           `json:"total" example:"100"`
	Limit  int           `json:"limit" example:"50"`
	Offset int           `json:"offset" example:"0"`
}

SCIMLogsResponse represents provisioning logs response

type SCIMOrgService

type SCIMOrgService interface {
	// Member operations
	AddMember(ctx context.Context, orgID, userID xid.ID, role string) (interface{}, error)
	IsUserMember(ctx context.Context, orgID, userID xid.ID) (bool, error)
	ListMembers(ctx context.Context, orgID xid.ID, limit, offset int) ([]interface{}, error)

	// Team operations
	CreateTeam(ctx context.Context, orgID xid.ID, req interface{}) (interface{}, error)
	GetTeam(ctx context.Context, id xid.ID) (interface{}, error)
	ListTeams(ctx context.Context, orgID xid.ID, limit, offset int) ([]interface{}, error)
	UpdateTeam(ctx context.Context, id xid.ID, req interface{}) (interface{}, error)
	DeleteTeam(ctx context.Context, id xid.ID) error
	AddTeamMember(ctx context.Context, teamID, memberID xid.ID, role string) error
	RemoveTeamMember(ctx context.Context, teamID, memberID xid.ID) error
	ListTeamMembers(ctx context.Context, teamID xid.ID) ([]interface{}, error)

	// Get member ID from user ID (for team operations)
	GetMemberIDByUserID(ctx context.Context, orgID, userID xid.ID) (xid.ID, error)
}

SCIMOrgService defines a unified interface for organization/app operations Supports both app mode (multitenancy) and organization mode (organization plugin)

type SCIMStatsResponse

type SCIMStatsResponse struct {
	SCIMMetrics map[string]interface{} `json:"scim_metrics"`
}

SCIMStatsResponse represents provisioning statistics response

type SCIMStatusResponse

type SCIMStatusResponse struct {
	Message string `json:"message" example:"Operation successful"`
}

SCIMStatusResponse represents a status response

type SCIMTokenInfo

type SCIMTokenInfo struct {
	ID          string     `json:"id" example:"01HZ..."`
	Name        string     `json:"name" example:"Production SCIM Token"`
	Description string     `json:"description" example:"Token for Okta provisioning"`
	Scopes      []string   `json:"scopes" example:"users,groups"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
	LastUsedAt  *time.Time `json:"last_used_at"`
	ExpiresAt   *time.Time `json:"expires_at"`
	RevokedAt   *time.Time `json:"revoked_at"`
}

SCIMTokenInfo represents token information (without sensitive data)

type SCIMTokenListResponse

type SCIMTokenListResponse struct {
	Tokens []SCIMTokenInfo `json:"tokens"`
	Total  int             `json:"total" example:"5"`
	Limit  int             `json:"limit" example:"50"`
	Offset int             `json:"offset" example:"0"`
}

SCIMTokenListResponse represents a list of tokens response

type SCIMTokenResponse

type SCIMTokenResponse struct {
	Token   string `json:"token" example:"scim_abc123"`
	ID      string `json:"id" example:"01HZ"`
	Name    string `json:"name" example:"Production SCIM Token"`
	Message string `json:"message" example:"Store this token securely"`
}

SCIMTokenResponse represents a token creation response

type SCIMUser

type SCIMUser struct {
	// Common attributes
	Schemas    []string `json:"schemas"`
	ID         string   `json:"id"`
	ExternalID string   `json:"externalId,omitempty"`
	Meta       *Meta    `json:"meta"`

	// Core User Schema attributes
	UserName          string `json:"userName"`
	Name              *Name  `json:"name,omitempty"`
	DisplayName       string `json:"displayName,omitempty"`
	NickName          string `json:"nickName,omitempty"`
	ProfileURL        string `json:"profileUrl,omitempty"`
	Title             string `json:"title,omitempty"`
	UserType          string `json:"userType,omitempty"`
	PreferredLanguage string `json:"preferredLanguage,omitempty"`
	Locale            string `json:"locale,omitempty"`
	Timezone          string `json:"timezone,omitempty"`
	Active            bool   `json:"active"`
	Password          string `json:"password,omitempty"`

	// Multi-valued attributes
	Emails           []Email           `json:"emails,omitempty"`
	PhoneNumbers     []PhoneNumber     `json:"phoneNumbers,omitempty"`
	IMs              []IM              `json:"ims,omitempty"`
	Photos           []Photo           `json:"photos,omitempty"`
	Addresses        []Address         `json:"addresses,omitempty"`
	Groups           []GroupReference  `json:"groups,omitempty"`
	Entitlements     []Entitlement     `json:"entitlements,omitempty"`
	Roles            []Role            `json:"roles,omitempty"`
	X509Certificates []X509Certificate `json:"x509Certificates,omitempty"`

	// Enterprise extension
	EnterpriseUser *EnterpriseUser `json:"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User,omitempty"`
}

SCIMUser represents a SCIM 2.0 User resource (RFC 7643 Section 4.1)

type Schema

type Schema struct {
	ID          string      `json:"id"`
	Name        string      `json:"name,omitempty"`
	Description string      `json:"description,omitempty"`
	Attributes  []Attribute `json:"attributes"`
	Meta        *Meta       `json:"meta,omitempty"`
}

Schema represents a SCIM schema (RFC 7643 Section 7)

type SchemaExtension

type SchemaExtension struct {
	Schema   string `json:"schema"`
	Required bool   `json:"required"`
}

SchemaExtension represents a schema extension (RFC 7643 Section 6)

type SearchConfig

type SearchConfig struct {
	MaxResults     int      `json:"max_results" yaml:"max_results"`         // Max results per page
	DefaultResults int      `json:"default_results" yaml:"default_results"` // Default page size
	AllowedFilters []string `json:"allowed_filters" yaml:"allowed_filters"` // Allowed filter attributes
	AllowedSortBy  []string `json:"allowed_sort_by" yaml:"allowed_sort_by"` // Allowed sort attributes
}

SearchConfig configures search and filtering behavior

type SearchRequest

type SearchRequest struct {
	Schemas            []string `json:"schemas"`
	Attributes         []string `json:"attributes,omitempty"`
	ExcludedAttributes []string `json:"excludedAttributes,omitempty"`
	Filter             string   `json:"filter,omitempty"`
	SortBy             string   `json:"sortBy,omitempty"`
	SortOrder          string   `json:"sortOrder,omitempty"` // ascending, descending
	StartIndex         int      `json:"startIndex,omitempty"`
	Count              int      `json:"count,omitempty"`
}

SearchRequest represents a SCIM search request (RFC 7644 Section 3.4.3)

type SecurityConfig

type SecurityConfig struct {
	RequireHTTPS         bool     `json:"require_https" yaml:"require_https"`
	IPWhitelist          []string `json:"ip_whitelist" yaml:"ip_whitelist"`
	AuditAllOperations   bool     `json:"audit_all_operations" yaml:"audit_all_operations"`
	MaskSensitiveData    bool     `json:"mask_sensitive_data" yaml:"mask_sensitive_data"`       // Mask emails, phones in logs
	RequireOrgValidation bool     `json:"require_org_validation" yaml:"require_org_validation"` // Validate org access
}

SecurityConfig configures security and compliance features

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides SCIM provisioning business logic

func NewService

func NewService(cfg ServiceConfig) *Service

NewService creates a new SCIM service

func (*Service) CreateGroup

func (s *Service) CreateGroup(ctx context.Context, scimGroup *SCIMGroup, orgID xid.ID) (*SCIMGroup, error)

CreateGroup creates a new group (maps to team/role)

func (*Service) CreateProvisioningLog

func (s *Service) CreateProvisioningLog(ctx context.Context, log *ProvisioningLog) error

CreateProvisioningLog creates a new provisioning log entry

func (*Service) CreateProvisioningToken

func (s *Service) CreateProvisioningToken(ctx context.Context, appID, envID, orgID xid.ID, name, description string, scopes []string, expiresAt *time.Time) (string, *ProvisioningToken, error)

CreateProvisioningToken creates a new SCIM provisioning token Updated for 3-tier architecture: App → Environment → Organization

Example

Example: Creating a provisioning token

package main

import ()

func main() {
	// Get SCIM service
	// scimService := scimPlugin.Service()

	// Create token for Okta integration (3-tier architecture)
	// appID := xid.New()
	// envID := xid.New()
	// orgID := xid.New()
	// token, provToken, err := scimService.CreateProvisioningToken(
	// 	ctx,
	// 	appID,                                     // App ID
	// 	envID,                                     // Environment ID
	// 	orgID,                                     // Organization ID
	// 	"Okta Production",                         // Token name
	// 	"SCIM token for Okta prod environment",   // Description
	// 	[]string{"scim:read", "scim:write"},      // Scopes
	// 	&expiresAt,                                // Expiration
	// )

	// Store token securely (shown only once)
	// fmt.Printf("Token: %s\n", token)
	// fmt.Printf("Token ID: %s\n", provToken.ID)
}

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, scimUser *SCIMUser, orgID xid.ID) (*SCIMUser, error)

CreateUser provisions a new user via SCIM

func (*Service) DeleteGroup

func (s *Service) DeleteGroup(ctx context.Context, id, orgID xid.ID) error

DeleteGroup deletes a group

func (*Service) DeleteUser

func (s *Service) DeleteUser(ctx context.Context, id, orgID xid.ID) error

DeleteUser de-provisions a user

func (*Service) GetAttributeMappings

func (s *Service) GetAttributeMappings(ctx context.Context, appID, envID, orgID xid.ID) (map[string]string, error)

GetAttributeMappings retrieves attribute mappings for an organization Updated for 3-tier architecture: App → Environment → Organization

func (*Service) GetGroup

func (s *Service) GetGroup(ctx context.Context, id, orgID xid.ID) (*SCIMGroup, error)

GetGroup retrieves a group by ID

func (*Service) GetProvisioningLogs

func (s *Service) GetProvisioningLogs(ctx context.Context, appID, envID, orgID xid.ID, action string, limit, offset int) ([]*ProvisioningLog, int, error)

GetProvisioningLogs retrieves provisioning logs with filtering Updated for 3-tier architecture

func (*Service) GetUser

func (s *Service) GetUser(ctx context.Context, id, orgID xid.ID) (*SCIMUser, error)

GetUser retrieves a user by ID

func (*Service) Health

func (s *Service) Health(ctx context.Context) error

Health checks service health

func (*Service) InitializeOrgSCIMConfig

func (s *Service) InitializeOrgSCIMConfig(ctx context.Context, appID, envID, orgID xid.ID) error

InitializeOrgSCIMConfig initializes default SCIM config for an organization Updated for 3-tier architecture: App → Environment → Organization

func (*Service) ListGroups

func (s *Service) ListGroups(ctx context.Context, orgID xid.ID, filter string, startIndex, count int) (*ListResponse, error)

ListGroups lists groups with filtering and pagination

func (*Service) ListProvisioningTokens

func (s *Service) ListProvisioningTokens(ctx context.Context, appID, envID, orgID xid.ID, limit, offset int) ([]*ProvisioningToken, int, error)

ListProvisioningTokens lists all provisioning tokens for an organization Updated for 3-tier architecture

func (*Service) ListUsers

func (s *Service) ListUsers(ctx context.Context, orgID xid.ID, filter string, startIndex, count int) (*ListResponse, error)

ListUsers lists users with filtering and pagination

func (*Service) Migrate

func (s *Service) Migrate(ctx context.Context) error

Migrate runs database migrations

func (*Service) ProcessBulkOperation

func (s *Service) ProcessBulkOperation(ctx context.Context, bulkReq *BulkRequest, orgID xid.ID) (*BulkResponse, error)

ProcessBulkOperation processes a bulk operation request

func (*Service) ReplaceGroup

func (s *Service) ReplaceGroup(ctx context.Context, id, orgID xid.ID, scimGroup *SCIMGroup) (*SCIMGroup, error)

ReplaceGroup replaces a group via PUT

func (*Service) ReplaceUser

func (s *Service) ReplaceUser(ctx context.Context, id, orgID xid.ID, scimUser *SCIMUser) (*SCIMUser, error)

ReplaceUser replaces a user via SCIM PUT

func (*Service) RevokeProvisioningToken

func (s *Service) RevokeProvisioningToken(ctx context.Context, tokenID string) error

RevokeProvisioningToken revokes a provisioning token

func (*Service) SendProvisioningWebhook

func (s *Service) SendProvisioningWebhook(ctx context.Context, event string, data map[string]interface{}) error

SendProvisioningWebhook sends a provisioning webhook

func (*Service) Shutdown

func (s *Service) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the service

func (*Service) UpdateAttributeMappings

func (s *Service) UpdateAttributeMappings(ctx context.Context, appID, envID, orgID xid.ID, mappings map[string]string) error

UpdateAttributeMappings updates attribute mappings for an organization Updated for 3-tier architecture: App → Environment → Organization

func (*Service) UpdateGroup

func (s *Service) UpdateGroup(ctx context.Context, id, orgID xid.ID, patch *PatchOp) (*SCIMGroup, error)

UpdateGroup updates a group via PATCH

func (*Service) UpdateUser

func (s *Service) UpdateUser(ctx context.Context, id, orgID xid.ID, patch *PatchOp) (*SCIMUser, error)

UpdateUser updates a user via SCIM PATCH

func (*Service) ValidateProvisioningToken

func (s *Service) ValidateProvisioningToken(ctx context.Context, token string) (*ProvisioningToken, error)

ValidateProvisioningToken validates a bearer token

type ServiceConfig

type ServiceConfig struct {
	Config         *Config
	Repository     *Repository
	UserService    user.ServiceInterface // Use interface to support decorated services
	OrgService     interface{}           // Can be *app.ServiceImpl or *orgplugin.ServiceImpl
	AuditService   *audit.Service
	WebhookService *webhook.Service
}

ServiceConfig holds service dependencies

type ServiceProviderConfig

type ServiceProviderConfig struct {
	Schemas               []string               `json:"schemas"`
	DocumentationURI      string                 `json:"documentationUri,omitempty"`
	Patch                 *Supported             `json:"patch"`
	Bulk                  *BulkSupport           `json:"bulk"`
	Filter                *FilterSupport         `json:"filter"`
	ChangePassword        *Supported             `json:"changePassword"`
	Sort                  *Supported             `json:"sort"`
	Etag                  *Supported             `json:"etag"`
	AuthenticationSchemes []AuthenticationScheme `json:"authenticationSchemes"`
	Meta                  *Meta                  `json:"meta"`
}

ServiceProviderConfig represents the service provider configuration (RFC 7643 Section 5)

type StatsResponse

type StatsResponse struct {
	TotalOperations int               `json:"totalOperations"`
	SuccessCount    int               `json:"successCount"`
	FailureCount    int               `json:"failureCount"`
	SuccessRate     float64           `json:"successRate"`
	ByOperation     map[string]int    `json:"byOperation"`
	ByResourceType  map[string]int    `json:"byResourceType"`
	ByStatus        map[string]int    `json:"byStatus"`
	Recent          []ProvisioningLog `json:"recent"`
	StartDate       *time.Time        `json:"startDate,omitempty"`
	EndDate         *time.Time        `json:"endDate,omitempty"`
}

StatsResponse represents provisioning statistics

type StatusResponse

type StatusResponse = responses.StatusResponse

type SuccessResponse

type SuccessResponse = responses.SuccessResponse

type Supported

type Supported struct {
	Supported bool `json:"supported"`
}

Supported indicates feature support (RFC 7643 Section 5)

type TokenListResponse

type TokenListResponse struct {
	Tokens []ProvisioningTokenInfo `json:"tokens"`
	Total  int                     `json:"total"`
}

TokenListResponse represents a list of provisioning tokens (without actual token values)

type TokenResponse

type TokenResponse struct {
	Token   string `json:"token"`
	ID      string `json:"id"`
	Name    string `json:"name"`
	Message string `json:"message"`
}

TokenResponse is the response for token creation

type UpdateAttributeMappingsRequest

type UpdateAttributeMappingsRequest struct {
	Mappings map[string]string `json:"mappings" validate:"required"`
}

UpdateAttributeMappingsRequest is the request body for updating attribute mappings

type UserProvisioningConfig

type UserProvisioningConfig struct {
	Enabled                 bool     `json:"enabled" yaml:"enabled"`
	AutoActivate            bool     `json:"auto_activate" yaml:"auto_activate"`           // Activate users immediately
	SendWelcomeEmail        bool     `json:"send_welcome_email" yaml:"send_welcome_email"` // Send welcome email on creation
	DefaultRole             string   `json:"default_role" yaml:"default_role"`             // Default role for provisioned users
	RequiredAttributes      []string `json:"required_attributes" yaml:"required_attributes"`
	PreventDuplicates       bool     `json:"prevent_duplicates" yaml:"prevent_duplicates"`                 // Prevent duplicate emails
	SoftDeleteOnDeProvision bool     `json:"soft_delete_on_deprovision" yaml:"soft_delete_on_deprovision"` // Soft delete vs hard delete
}

UserProvisioningConfig configures user provisioning behavior

type UsersResponse

type UsersResponse struct {
	Users []SCIMUser `json:"users"`
	Total int        `json:"total"`
}

UsersResponse wraps user list response for clarity

type WebhookConfig

type WebhookConfig struct {
	Enabled           bool     `json:"enabled" yaml:"enabled"`
	NotifyOnCreate    bool     `json:"notify_on_create" yaml:"notify_on_create"`
	NotifyOnUpdate    bool     `json:"notify_on_update" yaml:"notify_on_update"`
	NotifyOnDelete    bool     `json:"notify_on_delete" yaml:"notify_on_delete"`
	NotifyOnGroupSync bool     `json:"notify_on_group_sync" yaml:"notify_on_group_sync"`
	WebhookURLs       []string `json:"webhook_urls" yaml:"webhook_urls"`
	RetryAttempts     int      `json:"retry_attempts" yaml:"retry_attempts"`
	TimeoutSeconds    int      `json:"timeout_seconds" yaml:"timeout_seconds"`
}

WebhookConfig configures provisioning event webhooks

type X509Certificate

type X509Certificate struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"`
	Primary bool   `json:"primary,omitempty"`
}

X509Certificate represents an X.509 certificate (RFC 7643 Section 4.1.2)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL