Skip to main content
Single Sign-On (SSO) allows users to authenticate with Cal.com using their organization’s identity provider instead of creating separate credentials. Cal.com supports both SAML and OIDC protocols.

Overview

SSO provides:
  • Centralized Authentication: Users log in through your identity provider
  • Enhanced Security: Leverage your organization’s security policies
  • Simplified Management: Centrally manage user access and permissions
  • Automatic Provisioning: Works with SCIM for user lifecycle management

Prerequisites

  • Cal.com Enterprise license
  • Organizations feature enabled
  • Separate PostgreSQL database for SAML/SSO data
  • Identity Provider (IdP) supporting SAML 2.0 or OIDC

Configuration

1. Environment Variables

Add the following to your .env file:
.env
# Required: Separate database for SSO/SAML data
SAML_DATABASE_URL=postgresql://postgres:@localhost:5450/cal-saml

# Required: Admin emails with SSO management access
SAML_ADMINS=[email protected],[email protected]

# Required: Application encryption key (32 bytes for AES256)
# Generate with: openssl rand -base64 24
CALENDSO_ENCRYPTION_KEY=your_encryption_key

# Optional: Client secret verifier for OAuth 2.0 flow
SAML_CLIENT_SECRET_VERIFIER=your_secret_verifier

# Optional: Enable hosted Cal.com features
NEXT_PUBLIC_HOSTED_CAL_FEATURES=1
Source: .env.example:46-55

2. Database Setup

Create a separate PostgreSQL database for SSO data:
# Create database
creatdb cal-saml

# Run migrations
DATABASE_URL="postgresql://postgres:@localhost:5450/cal-saml" yarn prisma migrate deploy

3. Jackson SSO Library

Cal.com uses BoxyHQ’s Jackson library for SSO implementation. Jackson Configuration:
const opts: JacksonOption = {
  externalUrl: WEBAPP_URL,
  samlPath: "/api/auth/saml/callback",
  samlAudience: "https://saml.cal.com",
  oidcPath: "/api/auth/oidc",
  scimPath: "/api/scim/v2.0",
  db: {
    engine: "sql",
    type: "postgres",
    url: samlDatabaseUrl,
    encryptionKey: process.env.CALENDSO_ENCRYPTION_KEY,
  },
  idpEnabled: true,
  clientSecretVerifier,
};
Source: packages/features/ee/sso/lib/jackson.ts:19-33

SSO Admin Access

Self-Hosted

For self-hosted deployments, SSO configuration is restricted to admins listed in SAML_ADMINS:
// Check if user is SSO admin
const isSAMLAdmin = (email: string) => {
  const samlAdmins = (process.env.SAML_ADMINS || "").split(",");
  return samlAdmins.some(
    admin => admin.toLowerCase() === email.toLowerCase()
  );
};
Source: packages/features/ee/sso/lib/saml.ts:20-30

Hosted Cal.com

For hosted deployments, SSO access is controlled by organization permissions:
  • Organization Owners: Full SSO configuration access
  • Organization Admins: Full SSO configuration access
  • Organization Members: No SSO configuration access
Source: packages/features/ee/sso/lib/saml.ts:32-81

SSO Login Flow

1. User Initiates Login

User enters email at login screen:
1. User visits /auth/login
2. Enters email address
3. Cal.com checks for SSO configuration
4. Redirects to IdP if SSO is enabled

2. Identity Provider Authentication

1. User redirects to IdP login page
2. User authenticates with IdP credentials
3. IdP generates SAML assertion/OIDC token
4. IdP redirects back to Cal.com callback URL

3. Cal.com Processes Response

1. Cal.com receives SAML assertion/OIDC token
2. Validates signature and attributes
3. Extracts user information
4. Creates or updates user account
5. Creates session and redirects to app
Source: packages/features/ee/sso/lib/sso.ts:26-83

Automatic User Provisioning

SSO can automatically provision users on first login:

Email Domain Matching

When ORGANIZATIONS_AUTOLINK=1 is enabled:
const domain = email.split("@")[1];
const organization = await organizationRepository
  .getVerifiedOrganizationByAutoAcceptEmailDomain(domain);

if (organization) {
  // Auto-provision user to organization
  await createUsersAndConnectToOrg({
    emailsToCreate: [email],
    identityProvider: IdentityProvider.SAML,
    identityProviderId: email,
    org: organization,
  });
}
Source: packages/features/ee/sso/lib/sso.ts:34-49

Organization Assignment

Users are automatically assigned to organizations based on:
  1. Email Domain: Matching verified organization domain
  2. Existing Membership: Current team memberships
  3. SSO Connection: Configured SSO tenant mapping
Source: packages/features/ee/sso/lib/sso.ts:26-83

Multi-Team SSO

Cal.com supports SSO across multiple teams within an organization:
// Check SSO connections for each team user is a member of
const promises = memberships.map(({ teamId }) =>
  connectionController.getConnections({
    tenant: `team-${teamId}`,
    product: "Cal.com",
  })
);

// Use first SSO connection found
const connectionResults = await Promise.allSettled(promises);
Source: packages/features/ee/sso/lib/sso.ts:56-70

SSO Tenants

Each team/organization has its own SSO tenant:
  • Tenant ID Format: team-{teamId}
  • Product ID: Cal.com
  • Audience: https://saml.cal.com
Source: packages/features/ee/sso/lib/saml.ts:10-18

Security Considerations

Client Secret Verification

For enhanced security during OAuth 2.0 flows:
.env
# Set a random secret for client verification
SAML_CLIENT_SECRET_VERIFIER=your_random_secret
Use this value as client_secret during the OAuth 2.0 flow. Source: .env.example:55

Encryption

All SSO credentials and sensitive data are encrypted using the CALENDSO_ENCRYPTION_KEY:
# Generate a secure 32-byte key
openssl rand -base64 24
Source: packages/features/ee/sso/lib/jackson.ts:29

Admin Restrictions

SSO configuration is restricted to:
  • Emails listed in SAML_ADMINS (self-hosted)
  • Organization Owners/Admins (hosted)
Source: packages/features/ee/sso/lib/saml.ts:32-81

Troubleshooting

SSO Not Available

Error: “To enable this feature, add value for SAML_DATABASE_URL and SAML_ADMINS to your .env Solution: Ensure environment variables are configured:
SAML_DATABASE_URL=postgresql://postgres:@localhost:5450/cal-saml
SAML_ADMINS=[email protected]
Source: packages/features/ee/sso/lib/saml.ts:35-39

Permission Denied

Error: “dont_have_permission” Solutions:
  • Self-hosted: Add your email to SAML_ADMINS
  • Hosted: Verify you have Owner or Admin role in the organization
Source: packages/features/ee/sso/lib/saml.ts:46-74

No SSO Connection Found

Error: “Could not find a SSO Identity Provider for your email. Please contact your admin to ensure you have been given access to Cal” Solutions:
  1. Verify SSO connection is configured for your team/organization
  2. Check that your email matches an existing membership
  3. Confirm the SSO tenant is correctly mapped
  4. Review SSO connection status in organization settings
Source: packages/features/ee/sso/lib/sso.ts:72-77

User Belongs to Different Organization

Error: “User belongs to another organization.” Solution: Users can only belong to one organization. Contact support to migrate the user. Source: packages/features/ee/dsync/lib/handleUserEvents.ts:81-83

API Endpoints

SSO uses the following API endpoints:
EndpointProtocolPurpose
/api/auth/saml/callbackSAML 2.0SAML assertion callback
/api/auth/oidcOIDCOpenID Connect authentication
/api/scim/v2.0SCIM 2.0User provisioning (see SCIM docs)
Source: packages/features/ee/sso/lib/jackson.ts:21-24

Best Practices

  1. Use Separate Database: Always use a dedicated database for SSO data to isolate sensitive authentication information
  2. Rotate Secrets: Regularly rotate SAML_CLIENT_SECRET_VERIFIER and CALENDSO_ENCRYPTION_KEY
  3. Limit Admins: Only add necessary users to SAML_ADMINS
  4. Test Thoroughly: Test SSO flow in staging before production deployment
  5. Monitor Logs: Enable logging for SSO events to track authentication issues
  6. Use SCIM: Combine SSO with SCIM for automated user lifecycle management

Build docs developers (and LLMs) love