> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/calcom/cal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SAML Configuration

> Set up SAML 2.0 authentication for your Cal.com organization

Security Assertion Markup Language (SAML) 2.0 is an industry-standard protocol for single sign-on. Cal.com supports SAML authentication through integration with identity providers like Okta, Azure AD, Google Workspace, and others.

## Overview

SAML authentication provides:

* Standards-based SSO using SAML 2.0 protocol
* Integration with enterprise identity providers
* Secure assertion-based authentication
* Automatic user provisioning via SAML attributes

## Prerequisites

* Cal.com Enterprise license with SSO enabled
* Identity Provider supporting SAML 2.0
* Separate PostgreSQL database for SAML data
* Admin access to both Cal.com and your IdP

## Setup Guide

### 1. Configure Environment

Add SAML configuration to your `.env` file:

```bash .env theme={null}
# Required: Separate database for SAML data
SAML_DATABASE_URL=postgresql://postgres:@localhost:5450/cal-saml

# Required: Email addresses of SAML administrators
SAML_ADMINS=admin@company.com,sysadmin@company.com

# Required: Encryption key for sensitive data
# Generate with: openssl rand -base64 24
CALENDSO_ENCRYPTION_KEY=your_32_byte_encryption_key

# Optional: Client secret for OAuth 2.0 flows
SAML_CLIENT_SECRET_VERIFIER=your_random_secret

# Optional: Enable for hosted Cal.com features
NEXT_PUBLIC_HOSTED_CAL_FEATURES=1
```

Source: `.env.example:46-55`

### 2. Create SAML Database

Create and migrate the SAML database:

```bash theme={null}
# Create database
creatdb cal-saml

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

### 3. Retrieve SAML Metadata

Cal.com provides SAML Service Provider metadata:

**SAML Configuration Values:**

* **Entity ID / Audience**: `https://saml.cal.com`
* **Assertion Consumer Service (ACS) URL**: `https://your-domain.com/api/auth/saml/callback`
* **Single Logout URL**: `https://your-domain.com/api/auth/saml/logout`
* **Name ID Format**: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`

Source: `packages/features/ee/sso/lib/saml.ts:10-13`

### 4. Configure Identity Provider

Create a SAML application in your identity provider with the following settings:

#### Okta Configuration

1. Navigate to Applications → Create App Integration

2. Select SAML 2.0

3. Configure:
   * **Single sign-on URL**: `https://your-domain.com/api/auth/saml/callback`
   * **Audience URI**: `https://saml.cal.com`
   * **Name ID format**: EmailAddress
   * **Application username**: Email

4. Attribute Statements (optional):
   ```
   firstName  → user.firstName
   lastName   → user.lastName
   email      → user.email
   ```

5. Download the IdP metadata XML

#### Azure AD Configuration

1. Navigate to Enterprise Applications → New Application

2. Create a non-gallery application

3. Configure Single sign-on → SAML

4. Set:
   * **Identifier (Entity ID)**: `https://saml.cal.com`
   * **Reply URL (ACS)**: `https://your-domain.com/api/auth/saml/callback`
   * **Sign on URL**: `https://your-domain.com`

5. User Attributes & Claims:
   ```
   email       → user.mail
   firstName   → user.givenname
   lastName    → user.surname
   ```

6. Download Federation Metadata XML

#### Google Workspace Configuration

1. Navigate to Apps → Web and mobile apps → Add custom SAML app

2. Download IdP metadata

3. Configure Service Provider Details:
   * **ACS URL**: `https://your-domain.com/api/auth/saml/callback`
   * **Entity ID**: `https://saml.cal.com`
   * **Name ID format**: EMAIL
   * **Name ID**: Basic Information > Primary email

4. Attribute mapping:
   ```
   firstName   → Basic Information > First name
   lastName    → Basic Information > Last name
   email       → Basic Information > Primary email
   ```

### 5. Upload IdP Metadata to Cal.com

1. Log in to Cal.com as a SAML admin
2. Navigate to Settings → Security → Single Sign-On
3. Select your organization/team
4. Upload or paste your IdP metadata XML
5. Or manually configure:
   * **IdP Entity ID**: From IdP metadata
   * **SSO URL**: From IdP metadata
   * **Certificate**: X.509 certificate from IdP

## SAML Constants

Cal.com uses the following SAML constants:

```typescript theme={null}
export const samlTenantID = "Cal.com";
export const samlProductID = "Cal.com";
export const samlAudience = "https://saml.cal.com";
export const samlPath = "/api/auth/saml/callback";
export const clientSecretVerifier = process.env.SAML_CLIENT_SECRET_VERIFIER;
```

Source: `packages/features/ee/sso/lib/saml.ts:10-15`

## Tenant Structure

SAML connections are scoped per team/organization:

**Tenant Format**: `team-{teamId}`

```typescript theme={null}
export const tenantPrefix = "team-";

// Example: Team with ID 123
const tenant = `team-123`;
```

Source: `packages/features/ee/sso/lib/saml.ts:18`

This allows:

* Multiple teams to have different SAML configurations
* Isolated authentication per team
* Organization-level SAML that applies to all sub-teams

## User Provisioning

SAML authentication can automatically provision users:

### First-Time Login

When a user logs in via SAML for the first time:

```typescript theme={null}
// 1. Extract email from SAML assertion
const email = samlResponse.email;

// 2. Check for organization matching email domain
const domain = email.split("@")[1];
const organization = await organizationRepository
  .getVerifiedOrganizationByAutoAcceptEmailDomain(domain);

// 3. Create user and connect to organization
if (organization && ORGANIZATIONS_AUTOLINK) {
  await createUsersAndConnectToOrg({
    emailsToCreate: [email],
    identityProvider: IdentityProvider.SAML,
    identityProviderId: email,
    org: organization,
  });
}
```

Source: `packages/features/ee/sso/lib/sso.ts:34-49`

### Required Conditions

For automatic provisioning:

1. `ORGANIZATIONS_AUTOLINK=1` must be set
2. Organization must have verified the email domain
3. User email domain must match organization domain
4. User must not already belong to another organization

## Permission Management

### Self-Hosted Deployments

Only users listed in `SAML_ADMINS` can configure SAML:

```typescript theme={null}
const isSAMLAdmin = (email: string) => {
  const samlAdmins = (process.env.SAML_ADMINS || "").split(",");
  for (const admin of samlAdmins) {
    if (
      admin.toLowerCase() === email.toLowerCase() &&
      admin.toUpperCase() === email.toUpperCase()
    ) {
      return true;
    }
  }
  return false;
};
```

Source: `packages/features/ee/sso/lib/saml.ts:22-30`

### Hosted Deployments

SAML configuration requires organization-level permissions:

```typescript theme={null}
const permissionCheckService = new PermissionCheckService();
const hasPermission = await permissionCheckService.checkPermission({
  userId,
  teamId,
  permission: "organization.read",
  fallbackRoles: [MembershipRole.OWNER, MembershipRole.ADMIN],
});
```

Source: `packages/features/ee/sso/lib/saml.ts:51-64`

## Testing SAML Configuration

### 1. Verify SAML Connection

Test that SAML metadata is correctly configured:

```bash theme={null}
# Check connection exists
curl -X GET "https://your-domain.com/api/auth/saml/config?tenant=team-123"
```

### 2. Initiate Test Login

1. Open incognito browser window
2. Navigate to `/auth/login`
3. Enter email address that matches SAML domain
4. Verify redirect to IdP
5. Log in with IdP credentials
6. Verify successful redirect back to Cal.com
7. Confirm user session is created

### 3. Check SAML Response

Enable debug logging to inspect SAML assertions:

```bash .env theme={null}
# Add logging for SAML events
DEBUG=saml*
```

## Troubleshooting

### Invalid SAML Response

**Symptoms**: Login fails after IdP redirect

**Solutions**:

1. Verify ACS URL exactly matches: `https://your-domain.com/api/auth/saml/callback`
2. Check Entity ID matches: `https://saml.cal.com`
3. Ensure certificate is not expired
4. Verify clock sync between IdP and Cal.com servers

### User Not Found

**Error**: "Could not find a SSO Identity Provider for your email"

**Solutions**:

1. Verify SAML connection is configured for the user's team
2. Check user has membership in a team with SAML enabled
3. Confirm email in SAML assertion matches user's email
4. Review SAML admin permissions

Source: `packages/features/ee/sso/lib/sso.ts:72-77`

### Auto-Provisioning Not Working

**Solutions**:

1. Set `ORGANIZATIONS_AUTOLINK=1` in environment
2. Verify organization has verified the email domain
3. Check user email domain matches organization's domain
4. Ensure user doesn't already belong to another organization

Source: `packages/features/ee/sso/lib/sso.ts:32-54`

### Permission Denied

**Error**: "dont\_have\_permission"

**Solutions**:

* **Self-hosted**: Add email to `SAML_ADMINS` environment variable
* **Hosted**: Assign Owner or Admin role in organization

Source: `packages/features/ee/sso/lib/saml.ts:46-74`

### Database Connection Error

**Error**: Cannot connect to SAML database

**Solutions**:

1. Verify `SAML_DATABASE_URL` is correctly set
2. Ensure database exists and is accessible
3. Run migrations: `DATABASE_URL=$SAML_DATABASE_URL yarn prisma migrate deploy`
4. Check database credentials and network access

## SAML Attributes

Cal.com supports the following SAML attributes:

| Attribute   | Description          | Required |
| ----------- | -------------------- | -------- |
| `email`     | User's email address | Yes      |
| `firstName` | User's first name    | No       |
| `lastName`  | User's last name     | No       |
| `username`  | User's username      | No       |

Attributes are case-insensitive and can be mapped in your IdP configuration.

## Security Best Practices

1. **Certificate Validation**: Always validate SAML assertions with IdP certificate
2. **Encryption**: Use `CALENDSO_ENCRYPTION_KEY` to encrypt sensitive SAML data
3. **HTTPS Only**: Never use SAML over HTTP in production
4. **Short Session Lifetime**: Configure IdP to issue short-lived assertions
5. **Audit Logging**: Monitor SAML login attempts and failures
6. **Certificate Rotation**: Rotate SAML certificates before expiration
7. **Restrict Admins**: Limit `SAML_ADMINS` to necessary personnel only

## Advanced Configuration

### Custom SAML Attributes

Map additional SAML attributes to user fields:

```typescript theme={null}
// Custom attribute mapping in IdP
Attributes:
  department  → user.department
  role        → user.role
  phone       → user.phone
```

These can be used for:

* Custom routing logic
* Team assignment rules
* User metadata

### Multiple SAML Connections

Organizations can configure multiple SAML connections:

```typescript theme={null}
// Team A uses Okta
Tenant: team-123
IdP: Okta

// Team B uses Azure AD
Tenant: team-456
IdP: Azure AD
```

Users are routed to the correct IdP based on their team membership.

Source: `packages/features/ee/sso/lib/sso.ts:56-70`

## API Reference

### SAML Endpoints

| Endpoint                  | Method | Purpose                         |
| ------------------------- | ------ | ------------------------------- |
| `/api/auth/saml/callback` | POST   | SAML assertion consumer service |
| `/api/auth/saml/logout`   | POST   | Single logout service           |
| `/api/auth/saml/config`   | GET    | Retrieve SAML configuration     |
| `/api/auth/saml/metadata` | GET    | Service provider metadata XML   |

### Connection Types

```typescript theme={null}
export type SSOConnection = (SAMLSSORecord | OIDCSSORecord) & {
  type: string;
  acsUrl: string | null;
  entityId: string | null;
  callbackUrl: string | null;
};
```

Source: `packages/features/ee/sso/lib/saml.ts:83-88`

## Related Documentation

* [SSO Overview](/enterprise/sso)
* [SCIM Provisioning](/enterprise/scim)
* [Organizations Setup](/enterprise/organizations)
* [BoxyHQ SAML Jackson](https://boxyhq.com/docs/jackson/saml-flow)
