Organization Management API

Comprehensive API for managing multi-tenant organizations including CRUD operations, member management, BYOO OAuth credentials, SMTP, custom domains, and branding.

Updated Dec 16, 2025
Edit on GitHub
organizations multi-tenant byoo members domains

Organization Management

Comprehensive API for managing multi-tenant organizations, including CRUD operations, member management, BYOO OAuth credentials, SMTP configuration, custom domains, branding, and end-user management.

Overview

Organizations are the core tenant entities in AuthOS. Each organization has:

  • Members: Users with roles (owner, admin, member)
  • Services: Applications that use AuthOS
  • BYOO Credentials: Custom OAuth provider credentials
  • SMTP Configuration: Custom email delivery settings
  • Custom Domain: White-label domain configuration
  • Branding: Logo and color customization
  • End-Users: Customers who authenticate with the organization’s services

Organizations must be approved by a Platform Owner before becoming active. Only active organizations can authenticate users.

Data Models

Organization Model

{
  "id": "uuid",
  "slug": "unique-identifier",
  "name": "Organization Name",
  "owner_user_id": "uuid",
  "status": "pending|active|suspended|rejected",
  "tier_id": "uuid",
  "max_services": 10,
  "max_users": 100,
  "custom_domain": "auth.example.com",
  "domain_verified": true,
  "smtp_host": "smtp.example.com",
  "smtp_port": 587,
  "smtp_username": "noreply@example.com",
  "smtp_from_email": "noreply@example.com",
  "smtp_from_name": "Example Team",
  "brand_logo_url": "https://cdn.example.com/logo.png",
  "brand_primary_color": "#FF5733",
  "created_at": "datetime",
  "updated_at": "datetime"
}

Membership Model

{
  "id": "uuid",
  "org_id": "uuid",
  "user_id": "uuid",
  "role": "owner|admin|member",
  "created_at": "datetime"
}

Organization Member Response

{
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "is_platform_owner": false,
    "created_at": "datetime"
  },
  "membership": {
    "id": "uuid",
    "org_id": "uuid",
    "user_id": "uuid",
    "role": "admin",
    "created_at": "datetime"
  }
}

Endpoints Summary

Method Path Description Permissions
POST /api/organizations Create new organization Public
GET /api/organizations List user’s organizations Member
GET /api/organizations/:org_slug Get organization details Member
PATCH /api/organizations/:org_slug Update organization Owner/Admin
DELETE /api/organizations/:org_slug Delete organization Owner
GET /api/organizations/:org_slug/members List members Member
PATCH /api/organizations/:org_slug/members/:user_id Update member role Owner
POST /api/organizations/:org_slug/members/:user_id Remove member Owner/Admin
POST /api/organizations/:org_slug/transfer-ownership Transfer ownership Owner
POST /api/organizations/:org_slug/smtp Configure SMTP Owner/Admin
GET /api/organizations/:org_slug/smtp Get SMTP config Owner/Admin
DELETE /api/organizations/:org_slug/smtp Delete SMTP config Owner/Admin
POST /api/organizations/:org_slug/domain Set custom domain Owner/Admin
POST /api/organizations/:org_slug/domain/verify Verify custom domain Owner/Admin
GET /api/organizations/:org_slug/domain Get domain config Member
DELETE /api/organizations/:org_slug/domain Delete custom domain Owner/Admin
PATCH /api/organizations/:org_slug/branding Update branding Owner/Admin
GET /api/organizations/:org_slug/branding Get branding Member
GET /api/organizations/:org_slug/branding/public Get public branding Public
POST /api/organizations/:org_slug/oauth-credentials/:provider Set OAuth credentials Owner/Admin
GET /api/organizations/:org_slug/oauth-credentials/:provider Get OAuth credentials Member
GET /api/organizations/:org_slug/users List end-users Member
GET /api/organizations/:org_slug/users/:user_id Get end-user details Member
DELETE /api/organizations/:org_slug/users/:user_id/sessions Revoke user sessions Owner/Admin

Organization CRUD Operations

POST /api/organizations

Create a new organization (pending status). The authenticated user becomes the owner.

Permissions: Authenticated User

Headers:

Header Value
Authorization Bearer {jwt}

Request Body:

Field Type Required Description
slug string Yes Unique URL-friendly identifier (3-50 chars, alphanumeric/hyphens/underscores)
name string Yes Organization display name (2-100 chars)

Example Request:

curl -X POST https://sso.example.com/api/organizations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -d '{
    "slug": "acme-corp",
    "name": "Acme Corporation"
  }'

Example Response (200 OK):

{
  "organization": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "slug": "acme-corp",
    "name": "Acme Corporation",
    "owner_user_id": "user-uuid",
    "status": "pending",
    "tier_id": "free-tier-uuid",
    "max_services": null,
    "max_users": null,
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-15T10:30:00Z"
  },
  "owner": {
    "id": "user-uuid",
    "email": "admin@acme.com",
    "is_platform_owner": false,
    "created_at": "2025-01-15T10:30:00Z"
  },
  "membership": {
    "id": "membership-uuid",
    "org_id": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": "user-uuid",
    "role": "owner",
    "created_at": "2025-01-15T10:30:00Z"
  },
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "550e8400-e29b-41d4-a716-446655440001"
}

Error Responses:

  • 400 Bad Request: Invalid slug/name format, slug already taken, or reserved slug
  • 401 Unauthorized: Missing or invalid JWT token
  • 500 Internal Server Error: Database error

Notes:

  • Requires JWT authentication; the authenticated user becomes the organization owner
  • Response includes access_token and refresh_token with organization context (org claim set)
  • No need to re-authenticate after creation; tokens are immediately usable
  • Organization starts in pending status and requires Platform Owner approval
  • Owner is automatically added as a member with owner role
  • Free tier is automatically assigned
  • Reserved slugs: api, auth, admin, platform, docs, www, mail

Slug Validation:

  • Length: 3-50 characters
  • Characters: Alphanumeric, hyphens, and underscores only
  • Cannot use reserved slugs

Name Validation:

  • Length: 2-100 characters
  • Cannot be empty or whitespace-only

GET /api/organizations

List organizations the authenticated user is a member of.

Permissions: Authenticated User

Headers:

Header Value
Authorization Bearer {jwt}

Query Parameters:

Parameter Type Required Description
page integer No Page number (default: 1, min: 1)
limit integer No Items per page (default: 20, min: 1, max: 100)
status string No Filter by status: pending, active, suspended, rejected

Example Request:

curl -X GET "https://sso.example.com/api/organizations?page=1&limit=20&status=active" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

[
  {
    "organization": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "acme-corp",
      "name": "Acme Corporation",
      "owner_user_id": "user-uuid",
      "status": "active",
      "tier_id": "tier-uuid",
      "max_services": null,
      "max_users": null,
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-01-15T10:30:00Z"
    },
    "membership_count": 5,
    "service_count": 3,
    "tier": {
      "id": "tier-uuid",
      "name": "Free",
      "default_max_services": 5,
      "default_max_users": 100
    }
  }
]

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 500 Internal Server Error: Database error

Notes:

  • Returns only organizations where user is a member
  • Includes organization statistics (member count, service count)
  • Results are paginated

GET /api/organizations/:org_slug

Get detailed information about a specific organization.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "organization": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "slug": "acme-corp",
    "name": "Acme Corporation",
    "owner_user_id": "user-uuid",
    "status": "active",
    "tier_id": "tier-uuid",
    "max_services": null,
    "max_users": null,
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-15T10:30:00Z"
  },
  "membership_count": 5,
  "service_count": 3,
  "tier": {
    "id": "tier-uuid",
    "name": "Free",
    "default_max_services": 5,
    "default_max_users": 100
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member of this organization
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

PATCH /api/organizations/:org_slug

Update organization details.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
name string No New organization name (2-100 chars)

Example Request:

curl -X PATCH https://sso.example.com/api/organizations/acme-corp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corporation International"
  }'

Example Response (200 OK):

{
  "organization": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "slug": "acme-corp",
    "name": "Acme Corporation International",
    "owner_user_id": "user-uuid",
    "status": "active",
    "tier_id": "tier-uuid",
    "max_services": null,
    "max_users": null,
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-01-15T11:00:00Z"
  },
  "membership_count": 5,
  "service_count": 3,
  "tier": {
    "id": "tier-uuid",
    "name": "Free",
    "default_max_services": 5,
    "default_max_users": 100
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 400 Bad Request: Invalid name format
  • 500 Internal Server Error: Database error

Notes:

  • Only the organization name can be updated (slug is immutable)
  • The updated_at timestamp is automatically updated

DELETE /api/organizations/:org_slug

Delete an organization and all associated data.

Permissions: Owner only

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not the owner
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • This is a destructive operation that cannot be undone
  • Cascading deletes remove: members, services, plans, subscriptions, invitations, OAuth credentials, SMTP config, domain config, branding
  • An audit log entry is created before deletion (best effort)

Member Management

GET /api/organizations/:org_slug/members

List all members of an organization.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Query Parameters:

Parameter Type Required Description
page integer No Page number (default: 1, min: 1)
limit integer No Items per page (default: 50, min: 1, max: 100)
role string No Filter by role: owner, admin, member

Example Request:

curl -X GET "https://sso.example.com/api/organizations/acme-corp/members?page=1&limit=50&role=admin" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "members": [
    {
      "user": {
        "id": "user-uuid-1",
        "email": "admin@acme.com",
        "is_platform_owner": false,
        "created_at": "2025-01-15T10:30:00Z"
      },
      "membership": {
        "id": "membership-uuid-1",
        "org_id": "org-uuid",
        "user_id": "user-uuid-1",
        "role": "owner",
        "created_at": "2025-01-15T10:30:00Z"
      }
    },
    {
      "user": {
        "id": "user-uuid-2",
        "email": "user@acme.com",
        "is_platform_owner": false,
        "created_at": "2025-01-16T14:20:00Z"
      },
      "membership": {
        "id": "membership-uuid-2",
        "org_id": "org-uuid",
        "user_id": "user-uuid-2",
        "role": "admin",
        "created_at": "2025-01-16T14:20:00Z"
      }
    }
  ],
  "total": 5,
  "limit": {
    "current": 5,
    "max": 100,
    "source": "Free"
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Returns user and membership details for each member
  • limit.source indicates where the limit comes from (tier name or “custom”)
  • Results are paginated

PATCH /api/organizations/:org_slug/members/:user_id

Update a member’s role.

Permissions: Owner only

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
user_id string User ID to update

Request Body:

Field Type Required Description
role string Yes New role: owner, admin, or member

Example Request:

curl -X PATCH https://sso.example.com/api/organizations/acme-corp/members/user-uuid-2 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin"
  }'

Example Response (200 OK):

{
  "user": {
    "id": "user-uuid-2",
    "email": "user@acme.com",
    "is_platform_owner": false,
    "created_at": "2025-01-16T14:20:00Z"
  },
  "membership": {
    "id": "membership-uuid-2",
    "org_id": "org-uuid",
    "user_id": "user-uuid-2",
    "role": "admin",
    "created_at": "2025-01-16T14:20:00Z"
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not the owner
  • 404 Not Found: Organization or member not found
  • 400 Bad Request: Invalid role or attempting to change own role
  • 500 Internal Server Error: Database error

Notes:

  • Cannot change your own role (prevents accidental owner lockout)
  • If setting role to owner, organization ownership is transferred
  • Previous owner is automatically demoted to admin
  • An audit log entry is created for role changes
  • Audit log includes additional entry for ownership transfers

POST /api/organizations/:org_slug/members/:user_id

Remove a member from an organization.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
user_id string User ID to remove

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/members/user-uuid-3 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner/admin, or admin attempting to remove owner/admin
  • 404 Not Found: Organization or member not found
  • 400 Bad Request: Attempting to remove yourself
  • 500 Internal Server Error: Database error

Notes:

  • Cannot remove yourself from the organization
  • Owner can remove any member
  • Admin can only remove members (not other admins or owners)
  • An audit log entry is created with removed user details

POST /api/organizations/:org_slug/transfer-ownership

Transfer organization ownership to another member.

Permissions: Owner only

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
new_owner_email string Yes Email of the new owner (must be an existing member)

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/transfer-ownership \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "new_owner_email": "newowner@acme.com"
  }'

Example Response (200 OK):

{
  "user": {
    "id": "user-uuid-new",
    "email": "newowner@acme.com",
    "is_platform_owner": false,
    "created_at": "2025-01-16T14:20:00Z"
  },
  "membership": {
    "id": "membership-uuid-new",
    "org_id": "org-uuid",
    "user_id": "user-uuid-new",
    "role": "owner",
    "created_at": "2025-01-16T14:20:00Z"
  }
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not the owner
  • 404 Not Found: Organization, user, or membership not found
  • 500 Internal Server Error: Database error

Notes:

  • New owner must already be a member of the organization
  • Previous owner is automatically demoted to admin role
  • Organization’s owner_user_id is updated
  • Transaction ensures atomic ownership transfer
  • This operation is permanent and cannot be undone

SMTP Configuration

Custom SMTP settings allow organizations to send emails from their own email infrastructure.

POST /api/organizations/:org_slug/smtp

Configure SMTP settings for an organization.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
host string Yes SMTP server hostname
port integer Yes SMTP server port (typically 25, 587, or 465)
username string Yes SMTP authentication username
password string Yes SMTP authentication password
from_email string Yes From email address
from_name string No From display name

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/smtp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "host": "smtp.sendgrid.net",
    "port": 587,
    "username": "apikey",
    "password": "SG.xxx",
    "from_email": "noreply@acme.com",
    "from_name": "Acme Team"
  }'

Example Response (200 OK):

{
  "message": "SMTP configuration saved successfully"
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Encryption or database error

Notes:

  • Password is encrypted using AES-GCM before storage
  • Requires ENCRYPTION_KEY environment variable to be set
  • Emails will be sent from this SMTP server instead of platform default
  • Test the configuration by triggering an email (e.g., invite a user)

GET /api/organizations/:org_slug/smtp

Get SMTP configuration (without password).

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/smtp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "host": "smtp.sendgrid.net",
  "port": 587,
  "username": "apikey",
  "from_email": "noreply@acme.com",
  "from_name": "Acme Team",
  "configured": true
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Password is never returned for security
  • configured is true if SMTP settings exist, false otherwise
  • Returns empty values if SMTP is not configured

DELETE /api/organizations/:org_slug/smtp

Delete SMTP configuration (revert to platform default).

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp/smtp \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "message": "SMTP configuration deleted successfully. Organization will now use platform-level SMTP."
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Clears all SMTP settings from the database
  • Organization will fall back to platform-wide SMTP configuration
  • Encrypted password is permanently deleted

Custom Domain & Branding

White-label your authentication experience with custom domains and visual branding.

POST /api/organizations/:org_slug/domain

Set a custom domain for the organization.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
domain string Yes Custom domain (e.g., auth.acme.com)

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/domain \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "auth.acme.com"
  }'

Example Response (200 OK):

{
  "verification_token": "550e8400-e29b-41d4-a716-446655440000",
  "verification_methods": [
    {
      "method": "DNS TXT Record",
      "instructions": "Add a TXT record to your domain's DNS settings",
      "record_type": "TXT",
      "record_name": "_sso-verification.auth.acme.com",
      "record_value": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "method": "HTTP File",
      "instructions": "Upload a file to http://auth.acme.com/.well-known/sso-verification.txt containing the verification token",
      "record_type": null,
      "record_name": null,
      "record_value": "550e8400-e29b-41d4-a716-446655440000"
    }
  ]
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 400 Bad Request: Invalid domain format or domain already in use
  • 500 Internal Server Error: Database error

Notes:

  • Domain must contain at least one dot and no spaces
  • Domain must be unique across all organizations
  • Domain is set to domain_verified: false until verified
  • Verification token is generated and stored
  • An audit log entry is created
  • Choose one verification method (DNS or HTTP)

DNS Verification:

  1. Add a TXT record with name _sso-verification.{domain}
  2. Set the value to the verification token
  3. Wait for DNS propagation (can take up to 48 hours)
  4. Call the verify endpoint

HTTP Verification:

  1. Create a file at http://{domain}/.well-known/sso-verification.txt
  2. File content should be the verification token (plain text)
  3. Ensure the file is publicly accessible
  4. Call the verify endpoint

POST /api/organizations/:org_slug/domain/verify

Verify custom domain ownership.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/domain/verify \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK) - Verified:

{
  "verified": true,
  "message": "Domain verified successfully via DNS TXT record"
}

Example Response (200 OK) - Not Verified:

{
  "verified": false,
  "message": "Domain verification failed. Please ensure the TXT record or HTTP file is correctly configured."
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 400 Bad Request: No domain configured or already verified
  • 500 Internal Server Error: Database error

Notes:

  • Checks both DNS TXT record and HTTP file
  • If either verification method succeeds, domain is marked as verified
  • Once verified, domain_verified is set to true
  • An audit log entry is created with verification method
  • If already verified, returns success immediately

GET /api/organizations/:org_slug/domain

Get custom domain configuration.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/domain \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "custom_domain": "auth.acme.com",
  "domain_verified": true
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Returns null for custom_domain if not configured
  • domain_verified is false until verification succeeds
  • All members can view domain configuration

DELETE /api/organizations/:org_slug/domain

Remove custom domain configuration.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp/domain \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (204 No Content):

No response body.

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Clears custom_domain, domain_verified, and domain_verification_token
  • Organization reverts to using platform default domain
  • An audit log entry is created (if domain was configured)
  • DNS/HTTP verification files can be removed after deletion

PATCH /api/organizations/:org_slug/branding

Update organization branding (logo and colors).

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Request Body:

Field Type Required Description
logo_url string No URL to organization logo (publicly accessible)
primary_color string No Hex color code (e.g., #FF5733 or #F57)

Example Request:

curl -X PATCH https://sso.example.com/api/organizations/acme-corp/branding \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "logo_url": "https://cdn.acme.com/logo.png",
    "primary_color": "#FF5733"
  }'

Example Response (200 OK):

{
  "logo_url": "https://cdn.acme.com/logo.png",
  "primary_color": "#FF5733"
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 400 Bad Request: Invalid color format
  • 500 Internal Server Error: Database error

Notes:

  • Both fields are optional - update only what you need
  • Set to null to clear a branding field
  • Color must be hex format: #RRGGBB or #RGB
  • Logo URL should be publicly accessible (CDN recommended)
  • An audit log entry is created with updated fields
  • Changes are reflected immediately on login pages

GET /api/organizations/:org_slug/branding

Get organization branding configuration.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/branding \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "logo_url": "https://cdn.acme.com/logo.png",
  "primary_color": "#FF5733"
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • Returns null for fields that haven’t been configured
  • All members can view branding configuration
  • Use this endpoint to preview branding in admin dashboards

GET /api/organizations/:org_slug/branding/public

Get organization branding (public, no authentication).

Permissions: Public (no authentication required)

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/branding/public

Example Response (200 OK):

{
  "logo_url": "https://cdn.acme.com/logo.png",
  "primary_color": "#FF5733"
}

Error Responses:

  • 404 Not Found: Organization not found
  • 500 Internal Server Error: Database error

Notes:

  • No authentication required - used by login pages
  • Returns null for unconfigured fields
  • Use this endpoint to display branding on public authentication pages
  • Ideal for white-labeling login/signup forms

BYOO OAuth Credentials

Bring Your Own OAuth (BYOO) allows organizations to use their own OAuth provider credentials for end-user authentication.

POST /api/organizations/:org_slug/oauth-credentials/:provider

Set or update OAuth credentials for a provider.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
provider string OAuth provider: github, google, or microsoft

Request Body:

Field Type Required Description
client_id string Yes OAuth application client ID
client_secret string Yes OAuth application client secret

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/oauth-credentials/github \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "Iv1.abcdef123456",
    "client_secret": "1234567890abcdefghij"
  }'

Example Response (200 OK):

{
  "provider": "github",
  "client_id": "Iv1.abcdef123456",
  "has_secret": true
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization not found
  • 400 Bad Request: Invalid provider
  • 500 Internal Server Error: Encryption or database error

Notes:

  • Valid providers: github, google, microsoft
  • Client secret is encrypted using AES-GCM before storage
  • Requires ENCRYPTION_KEY environment variable
  • If credentials already exist for the provider, they are updated (upsert)
  • End-users will authenticate using these credentials instead of platform defaults
  • Test by initiating a login flow for your service

Setting up OAuth Applications:

GitHub:

  1. Go to Settings > Developer settings > OAuth Apps
  2. Create new OAuth App
  3. Set callback URL to: https://your-sso-domain.com/auth/github/callback
  4. Copy Client ID and generate Client Secret

Google:

  1. Go to Google Cloud Console > APIs & Services > Credentials
  2. Create OAuth 2.0 Client ID
  3. Set redirect URI to: https://your-sso-domain.com/auth/google/callback
  4. Copy Client ID and Client Secret

Microsoft:

  1. Go to Azure Portal > App registrations
  2. Create new registration
  3. Set redirect URI to: https://your-sso-domain.com/auth/microsoft/callback
  4. Copy Application (client) ID
  5. Create client secret in Certificates & secrets

GET /api/organizations/:org_slug/oauth-credentials/:provider

Get OAuth credentials for a provider (client ID only).

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
provider string OAuth provider: github, google, or microsoft

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/oauth-credentials/github \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "provider": "github",
  "client_id": "Iv1.abcdef123456",
  "has_secret": true
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization or credentials not found
  • 400 Bad Request: Invalid provider
  • 500 Internal Server Error: Database error

Notes:

  • Client secret is never returned for security
  • has_secret is always true if credentials exist
  • All members can view OAuth credentials (but not the secret)
  • Use this to verify which providers have BYOO configured

End-User Management

Manage customers who authenticate with your organization’s services.

GET /api/organizations/:org_slug/users

List all end-users (customers) of the organization.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug

Query Parameters:

Parameter Type Required Description
page integer No Page number (default: 1, min: 1)
limit integer No Items per page (default: 50, min: 1, max: 100)
service_slug string No Filter by specific service

Example Request:

curl -X GET "https://sso.example.com/api/organizations/acme-corp/users?page=1&limit=50&service_slug=main-app" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "users": [
    {
      "user": {
        "id": "user-uuid-1",
        "email": "customer@example.com",
        "is_platform_owner": false,
        "created_at": "2025-01-15T10:30:00Z"
      },
      "subscriptions": [
        {
          "service_id": "service-uuid",
          "service_slug": "main-app",
          "service_name": "Main Application",
          "plan_id": "plan-uuid",
          "plan_name": "Pro",
          "status": "active",
          "current_period_end": "2025-02-15T10:30:00Z",
          "created_at": "2025-01-15T10:30:00Z"
        }
      ],
      "identities": [
        {
          "provider": "github",
          "provider_user_id": "12345678",
          "created_at": "2025-01-15T10:30:00Z"
        }
      ]
    }
  ],
  "total": 150,
  "page": 1,
  "limit": 50
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization or service not found
  • 500 Internal Server Error: Database error

Notes:

  • End-users are those who have authenticated with the organization’s services
  • Returns users with subscriptions and/or identities for the organization
  • Each user includes their subscriptions and linked identities
  • Filter by service to see users of a specific application
  • Results are paginated

GET /api/organizations/:org_slug/users/:user_id

Get detailed information about a specific end-user.

Permissions: Member

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
user_id string End-user ID

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/users/user-uuid-1 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "user": {
    "id": "user-uuid-1",
    "email": "customer@example.com",
    "is_platform_owner": false,
    "created_at": "2025-01-15T10:30:00Z"
  },
  "subscriptions": [
    {
      "service_id": "service-uuid",
      "service_slug": "main-app",
      "service_name": "Main Application",
      "plan_id": "plan-uuid",
      "plan_name": "Pro",
      "status": "active",
      "current_period_end": "2025-02-15T10:30:00Z",
      "created_at": "2025-01-15T10:30:00Z"
    }
  ],
  "identities": [
    {
      "provider": "github",
      "provider_user_id": "12345678",
      "created_at": "2025-01-15T10:30:00Z"
    },
    {
      "provider": "google",
      "provider_user_id": "987654321",
      "created_at": "2025-01-16T14:20:00Z"
    }
  ],
  "session_count": 2
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not a member
  • 404 Not Found: Organization or end-user not found
  • 500 Internal Server Error: Database error

Notes:

  • Only shows users who have subscriptions to this organization’s services
  • Includes all subscriptions across all services
  • Includes all linked OAuth identities
  • session_count shows active sessions for this user
  • Use this endpoint to get full customer profile

DELETE /api/organizations/:org_slug/users/:user_id/sessions

Revoke all active sessions for an end-user.

Permissions: Owner or Admin

Headers:

Header Value
Authorization Bearer {jwt}

Path Parameters:

Parameter Type Description
org_slug string Organization slug
user_id string End-user ID

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp/users/user-uuid-1/sessions \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response (200 OK):

{
  "message": "Sessions revoked successfully",
  "revoked_count": 3
}

Error Responses:

  • 401 Unauthorized: Invalid or missing JWT
  • 403 Forbidden: User is not an owner or admin
  • 404 Not Found: Organization or end-user not found
  • 500 Internal Server Error: Database error

Notes:

  • Revokes all active JWT sessions for the user
  • User must re-authenticate to access services
  • Use this for security purposes (e.g., suspected account compromise)
  • revoked_count shows how many sessions were deleted
  • Only affects sessions for this user across all services in the organization

Risk Engine Settings

Organizations can customize the behavior of the platform’s Risk Engine to match their security requirements.

GET /api/organizations/:org_slug/risk-settings

Retrieve the current risk engine configuration for an organization.

Permissions: Organization admin, owner, or platform owner

Headers:

Header Value Required
Authorization Bearer {jwt} Yes

Path Parameters:

Parameter Type Description
org_slug string Organization slug identifier

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/risk-settings \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response (200 OK):

{
  "id": "risk-rules-id-123",
  "org_id": "org-id-456",
  "enforcement_mode": "enforce",
  "low_threshold": 30,
  "medium_threshold": 70,
  "new_device_score": 20,
  "impossible_travel_score": 50,
  "velocity_threshold": 10,
  "velocity_score": 30,
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-01-15T10:00:00Z"
}

Field Descriptions:

Field Type Description
enforcement_mode string enforce or log_only (shadow mode)
low_threshold integer Risk score threshold for low-risk actions (0-100)
medium_threshold integer Risk score threshold for MFA challenge (0-100)
new_device_score integer Points added for new/unknown device
impossible_travel_score integer Points added for impossible travel detection
velocity_threshold integer Max login attempts within time window
velocity_score integer Points added for velocity rule violations

Enforcement Modes:

  • enforce: Risk engine actions are applied (block, MFA challenge, allow)
  • log_only: All logins succeed, but risk scores are logged for analysis

PUT /api/organizations/:org_slug/risk-settings

Update risk engine configuration for an organization.

Permissions: Organization admin, owner, or platform owner

Headers:

Header Value Required
Authorization Bearer {jwt} Yes
Content-Type application/json Yes

Path Parameters:

Parameter Type Description
org_slug string Organization slug identifier

Request Body:

Field Type Required Description
enforcement_mode string No enforce or log_only
low_threshold integer No Low risk threshold (0-100)
medium_threshold integer No Medium risk threshold (0-100)
new_device_score integer No New device risk score
impossible_travel_score integer No Impossible travel risk score
velocity_threshold integer No Velocity detection threshold
velocity_score integer No Velocity violation risk score

Example Request:

curl -X PUT https://sso.example.com/api/organizations/acme-corp/risk-settings \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "enforcement_mode": "enforce",
    "medium_threshold": 60,
    "new_device_score": 25
  }'

Success Response (200 OK):

{
  "success": true,
  "risk_settings": {
    "id": "risk-rules-id-123",
    "org_id": "org-id-456",
    "enforcement_mode": "enforce",
    "low_threshold": 30,
    "medium_threshold": 60,
    "new_device_score": 25,
    "impossible_travel_score": 50,
    "velocity_threshold": 10,
    "velocity_score": 30,
    "created_at": "2025-01-01T00:00:00Z",
    "updated_at": "2025-01-15T14:30:00Z"
  }
}

Validation Rules:

  • enforcement_mode must be enforce or log_only
  • Thresholds must be between 0 and 100
  • medium_threshold must be greater than low_threshold
  • Score values must be non-negative integers

Use Cases:

Testing Mode (Shadow Mode):

{
  "enforcement_mode": "log_only"
}

Enables monitoring without blocking users. Review risk assessments in login events before enabling enforcement.

Strict Security:

{
  "enforcement_mode": "enforce",
  "medium_threshold": 50,
  "new_device_score": 30,
  "impossible_travel_score": 60
}

Lower thresholds and higher scores for high-security environments.

Balanced Security:

{
  "enforcement_mode": "enforce",
  "medium_threshold": 70,
  "new_device_score": 20,
  "impossible_travel_score": 50
}

Default settings suitable for most organizations.


POST /api/organizations/:org_slug/risk-settings/reset

Reset risk engine settings to platform defaults.

Permissions: Organization admin, owner, or platform owner

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/risk-settings/reset \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response (200 OK): Returns the risk settings object with default values.

Default Values:

  • enforcement_mode: log_only
  • low_threshold: 30
  • medium_threshold: 70
  • new_device_score: 20
  • impossible_travel_score: 50
  • velocity_threshold: 10
  • velocity_score: 30

SIEM Configuration

Configure Security Information and Event Management (SIEM) integrations to stream audit logs and login events to external security platforms.

POST /api/organizations/:org_slug/siem-configs

Create a new SIEM configuration for log streaming.

Permissions: Organization admin or owner

Headers:

Header Value Required
Authorization Bearer {jwt} Yes
Content-Type application/json Yes

Path Parameters:

Parameter Type Description
org_slug string Organization slug identifier

Request Body:

Field Type Required Description
name string Yes Configuration name (e.g., “Production Datadog”)
provider_type string Yes Datadog, Splunk, Elastic, or Custom
endpoint_url string Yes HTTP endpoint for log delivery
api_key string No API key for authentication
auth_header string No Custom authorization header
batch_size integer No Events per batch (default: 100)

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/siem-configs \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Datadog",
    "provider_type": "Datadog",
    "endpoint_url": "https://http-intake.logs.datadoghq.com/v1/input",
    "api_key": "dd-api-key-abc123",
    "batch_size": 50
  }'

Success Response (201 Created):

{
  "id": "siem-config-id-789",
  "org_id": "org-id-456",
  "name": "Production Datadog",
  "provider_type": "Datadog",
  "endpoint_url": "https://http-intake.logs.datadoghq.com/v1/input",
  "batch_size": 50,
  "enabled": true,
  "last_successful_batch_at": null,
  "failure_count": 0,
  "created_at": "2025-01-15T10:00:00Z"
}

Supported Providers:

Provider Description Authentication
Datadog Datadog Log Management api_key in DD-API-KEY header
Splunk Splunk HEC (HTTP Event Collector) api_key in Authorization header
Elastic Elasticsearch api_key or auth_header
Custom Generic HTTP endpoint Custom auth_header

Event Types Streamed:

  • Login events (successful and failed attempts)
  • MFA audit logs (setup, verification, recovery code usage)
  • Organization audit logs (member changes, settings updates)
  • Platform audit logs (organization creation, deletion, suspension)

Security:

  • API keys are encrypted at rest using AES-GCM
  • Credentials never returned in API responses
  • HTTPS required for all endpoint URLs

GET /api/organizations/:org_slug/siem-configs

List all SIEM configurations for an organization.

Permissions: Organization admin or owner

Example Request:

curl -X GET https://sso.example.com/api/organizations/acme-corp/siem-configs \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response (200 OK):

{
  "siem_configs": [
    {
      "id": "siem-config-id-789",
      "org_id": "org-id-456",
      "name": "Production Datadog",
      "provider_type": "Datadog",
      "endpoint_url": "https://http-intake.logs.datadoghq.com/v1/input",
      "batch_size": 50,
      "enabled": true,
      "last_successful_batch_at": "2025-01-15T14:30:00Z",
      "failure_count": 0,
      "created_at": "2025-01-15T10:00:00Z"
    }
  ],
  "total": 1
}

Note: API keys and auth headers are never returned in responses for security.


PATCH /api/organizations/:org_slug/siem-configs/:config_id

Update an existing SIEM configuration.

Permissions: Organization admin or owner

Request Body:

Field Type Required Description
name string No Update configuration name
endpoint_url string No Update endpoint URL
api_key string No Update API key (null to remove)
auth_header string No Update auth header (null to remove)
batch_size integer No Update batch size
enabled boolean No Enable/disable log streaming

Example Request:

curl -X PATCH https://sso.example.com/api/organizations/acme-corp/siem-configs/siem-config-id-789 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": false
  }'

Success Response (200 OK): Returns the updated SIEM configuration.


DELETE /api/organizations/:org_slug/siem-configs/:config_id

Delete a SIEM configuration. This stops log streaming immediately.

Permissions: Organization admin or owner

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp/siem-configs/siem-config-id-789 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response: 204 No Content

Warning: This action cannot be undone. Historical logs are not affected, but new events will no longer be streamed.


POST /api/organizations/:org_slug/siem-configs/:config_id/test

Test SIEM configuration by sending a test event.

Permissions: Organization admin or owner

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/siem-configs/siem-config-id-789/test \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response (200 OK):

{
  "success": true,
  "message": "Test event delivered successfully",
  "response_status": 200,
  "response_time_ms": 145
}

Failure Response (200 OK):

{
  "success": false,
  "message": "Connection failed: timeout after 30s",
  "error": "Connection timeout"
}

Test Event Payload:

{
  "event_type": "siem_config_test",
  "timestamp": "2025-01-15T14:30:00Z",
  "organization_id": "org-id-456",
  "message": "Test event from AuthOS SIEM integration"
}

Use Cases:

  • Verify endpoint connectivity before enabling
  • Troubleshoot delivery failures
  • Validate authentication credentials
  • Check endpoint response time

SCIM Tokens

SCIM tokens enable automated user and group provisioning from identity providers.

POST /api/organizations/:org_slug/scim-tokens

Create a new SCIM token for automated provisioning.

Permissions: Organization admin or owner

Request Body:

Field Type Required Description
name string Yes Token name (e.g., “Okta SCIM Integration”)
expires_at string No ISO 8601 expiration timestamp

Example Request:

curl -X POST https://sso.example.com/api/organizations/acme-corp/scim-tokens \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Okta SCIM Integration",
    "expires_at": "2026-12-31T23:59:59Z"
  }'

Success Response (201 Created):

{
  "id": "scim-token-id-abc",
  "name": "Okta SCIM Integration",
  "token": "scim_live_abc123def456...",
  "prefix": "scim_live_abc1",
  "created_at": "2025-01-15T10:00:00Z",
  "expires_at": "2026-12-31T23:59:59Z"
}

Important: The full token is only returned once during creation. Store it securely.

Token Format: scim_live_ prefix + 32-byte random value

See SCIM 2.0 API Reference for SCIM endpoint documentation.


GET /api/organizations/:org_slug/scim-tokens

List all SCIM tokens for an organization.

Example Response:

[
  {
    "id": "scim-token-id-abc",
    "name": "Okta SCIM Integration",
    "prefix": "scim_live_abc1",
    "active": true,
    "created_at": "2025-01-15T10:00:00Z",
    "expires_at": "2026-12-31T23:59:59Z",
    "last_used_at": "2025-01-15T14:30:00Z"
  }
]

Note: Full token values are never returned after creation.


DELETE /api/organizations/:org_slug/scim-tokens/:token_id

Revoke and delete a SCIM token. This immediately invalidates the token.

Example Request:

curl -X DELETE https://sso.example.com/api/organizations/acme-corp/scim-tokens/scim-token-id-abc \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Success Response: 204 No Content


Security Considerations

Access Control:

  • Organization status must be active for most operations
  • Pending organizations can only manage members and invitations
  • Suspended organizations cannot authenticate users
  • Platform Owners bypass some restrictions

SMTP Security:

  • Passwords are encrypted at rest using AES-GCM
  • Never returned in GET requests
  • Requires ENCRYPTION_KEY environment variable

OAuth Credentials (BYOO):

  • Client secrets encrypted at rest using AES-GCM
  • Never returned in API responses
  • Used automatically for end-user authentication
  • Falls back to platform defaults if not configured

Custom Domain Verification:

  • Prevents domain hijacking
  • Two verification methods: DNS TXT and HTTP file
  • Domain must be unique across all organizations
  • Verification token is random UUID

Role Hierarchy:

  • Owner: Full control, can delete organization
  • Admin: Manage members (except owner), configure settings
  • Member: Read-only access to organization details

Audit Logging:

  • All member management actions logged
  • Domain and branding changes logged
  • SMTP configuration changes logged
  • Includes actor, target, and detailed change information

Rate Limiting:

  • Organization creation: 10 per hour per IP
  • Member operations: 60 per hour per user
  • SMTP operations: 20 per hour per organization
  • Domain verification: 10 per hour per organization

Data Isolation:

  • Organizations are completely isolated
  • Members cannot access other organizations’ data
  • End-users are scoped to their organization’s services
  • BYOO credentials are organization-specific