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

# SSO / SAML

Configure Single Sign-On with SAML 2.0 for enterprise documentation access control.

## Overview

HolyDocs supports SSO via SAML 2.0 for enterprise organizations. SSO allows your team members to authenticate to the documentation dashboard and protected doc sites using your company's identity provider (IdP).

## Requirements

SSO/SAML is available on **Business** and **Enterprise** plans.

| Plan | SSO/SAML |
|---|---|
| Free | Not available |
| Starter | Not available |
| Pro | Not available |
| Business | Available |
| Enterprise | Available |

## Supported Identity Providers

HolyDocs SSO works with any SAML 2.0 compliant identity provider:

**Okta** SAML 2.0
  **Azure AD** SAML 2.0
  **Google Workspace** SAML 2.0
  **OneLogin** SAML 2.0
  **Auth0** SAML 2.0
  **JumpCloud** SAML 2.0

### Provider-Specific Setup Guides

**Okta**

1. In the Okta admin console, go to **Applications > Create App Integration**
    2. Select **SAML 2.0** and click Next
    3. Set the **Single sign-on URL** to: `https://app.holydocs.com/api/auth/saml/callback`
    4. Set the **Audience URI (SP Entity ID)** to: `https://app.holydocs.com`
    5. Under **Attribute Statements**, add:
       - `email` → `user.email`
       - `firstName` → `user.firstName`
       - `lastName` → `user.lastName`
    6. Under **Group Attribute Statements**, add:
       - `groups` → Matches regex `.*` (or filter to specific groups)
    7. Click **Finish** and copy the **Metadata URL** from the Sign On tab
    8. Paste the Metadata URL into HolyDocs SSO settings
  **Azure AD (Entra ID)**

1. In the Azure portal, go to **Enterprise Applications > New Application**
    2. Click **Create your own application**, name it "HolyDocs", select **Integrate any other application**
    3. Go to **Single sign-on > SAML** and click **Edit** on Basic SAML Configuration
    4. Set **Identifier (Entity ID)** to: `https://app.holydocs.com`
    5. Set **Reply URL (ACS URL)** to: `https://app.holydocs.com/api/auth/saml/callback`
    6. Under **Attributes & Claims**, configure:
       - `email` → `user.mail`
       - `firstName` → `user.givenname`
       - `lastName` → `user.surname`
       - `groups` → Add a group claim with "Groups assigned to the application"
    7. Download the **Federation Metadata XML** from the SAML Signing Certificate section
    8. Upload the XML file in HolyDocs SSO settings (or paste the App Federation Metadata URL)
  **Google Workspace**

1. In the Google Admin console, go to **Apps > Web and mobile apps > Add App > Add custom SAML app**
    2. Name the app "HolyDocs" and click **Continue**
    3. Copy the **SSO URL** and **Certificate** from the Google IdP Information page
    4. On the Service Provider Details page, set:
       - **ACS URL**: `https://app.holydocs.com/api/auth/saml/callback`
       - **Entity ID**: `https://app.holydocs.com`
       - **Name ID format**: `EMAIL`
    5. On the Attribute Mapping page, add:
       - `email` → Primary email
       - `firstName` → First name
       - `lastName` → Last name
    6. Click **Finish** and turn the app **ON** for your organizational units
    7. In HolyDocs, paste the SSO URL and upload the certificate

## Setting Up SSO

**Open SSO Settings**

In the dashboard, go to **Settings > Security > SSO**.
  **Configure Your IdP**

Provide your IdP with the following HolyDocs SAML settings:

    - **ACS URL**: `https://app.holydocs.com/api/auth/saml/callback`
    - **Entity ID**: `https://app.holydocs.com`
    - **Name ID Format**: `email`
  **Enter IdP Metadata**

Paste your IdP's metadata URL or XML into the HolyDocs SSO configuration:

    ```
    https://your-idp.com/app/metadata/holydocs
    ```
  **Map Attributes**

Configure attribute mapping:

    | IdP Attribute | HolyDocs Field |
    |---|---|
    | `email` | User email |
    | `firstName` | First name |
    | `lastName` | Last name |
    | `groups` | Content access groups |
  **Test and Enable**

Use the **Test Connection** button to verify the SSO flow. Once confirmed, enable SSO for your organization.

## Doc Site Authentication

SSO also powers authentication for protected documentation sites. When `auth.enabled` is set in `docs.json`, readers must authenticate before accessing protected pages:

```json
{
  "auth": {
    "enabled": true,
    "provider": "clerk",
    "loginUrl": "https://accounts.yourcompany.com/sign-in",
    "publicPaths": ["/", "/introduction", "/quickstart"]
  }
}
```

### Authentication Flow

1. Reader visits a protected page
2. HolyDocs checks for a valid JWT in the request
3. If no valid token, the reader is redirected to the login URL
4. After authentication, the reader is redirected back with a JWT
5. Subsequent requests include the JWT for session validation

Renderer auth uses raw `crypto.subtle` JWT verification (no heavyweight JWT library on the edge) for performance. JWKS public keys are cached in KV for 1 hour.

## Custom JWT Provider

For any third-party identity provider that issues OIDC-compatible JWTs (Auth0, Okta, AWS Cognito, your own IdP, etc.), use the `custom` provider with a JWKS URL:

```json
{
  "auth": {
    "enabled": true,
    "provider": "custom",
    "jwksUrl": "https://your-idp.com/.well-known/jwks.json",
    "claimsMapping": {
      "groups": "custom:groups",
      "email": "email"
    }
  }
}
```

### Claims Mapping

The `claimsMapping` object tells HolyDocs where to find specific fields in the JWT payload. This is necessary because different identity providers use different claim names:

| HolyDocs Field | Description | Common JWT Claims |
|---|---|---|
| `email` | User's email address | `email`, `mail`, `preferred_username` |
| `groups` | Content access groups | `groups`, `roles`, `custom:groups`, `cognito:groups` |
| `name` | Display name (optional) | `name`, `display_name`, `nickname` |

Example for Auth0:

```json
{
  "auth": {
    "provider": "custom",
    "jwksUrl": "https://your-tenant.auth0.com/.well-known/jwks.json",
    "claimsMapping": {
      "email": "email",
      "groups": "https://yourapp.com/roles"
    }
  }
}
```

Example for AWS Cognito:

```json
{
  "auth": {
    "provider": "custom",
    "jwksUrl": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX/.well-known/jwks.json",
    "claimsMapping": {
      "email": "email",
      "groups": "cognito:groups"
    }
  }
}
```

## Testing SSO

Before enabling SSO for all users, thoroughly test the integration:

**Use the Test Connection button**

In **Settings > Security > SSO**, click **Test Connection**. This initiates a SAML flow in a new window and reports the parsed attributes back to you. Verify that `email`, `firstName`, `lastName`, and `groups` are all mapped correctly.
  **Test with a non-admin user**

SSO configuration is done by admins, but you should test with a regular user account to ensure the flow works for all team members. Check that group assignments propagate correctly.
  **Verify content access groups**

If your docs use group-based content access, test that users with different group memberships see the correct pages. A user in the "engineering" group should see engineering docs but not "finance" docs.
  **Test the doc site auth flow**

Visit a protected page on your documentation site in an incognito window. You should be redirected to your IdP login page. After authentication, you should be redirected back to the original page with access granted.
  **Check edge cases**

- What happens when a user's session expires?
    - What happens when a user is removed from a group in your IdP?
    - What happens when a user visits a page they do not have access to?

Do not enable "Require SSO for all users" until testing is complete. If SSO is misconfigured and required, all users (including admins) will be locked out. HolyDocs support can disable SSO for your organization if this happens.

## Group-Based Content Access

SSO groups can be used to control which documentation pages are visible to which users. Map IdP groups to content access rules in `docs.json`:

```json
{
  "auth": {
    "enabled": true,
    "provider": "custom",
    "jwksUrl": "https://your-idp.com/.well-known/jwks.json",
    "claimsMapping": { "groups": "groups" },
    "accessControl": {
      "rules": [
        { "paths": ["/internal/*"], "groups": ["employees"] },
        { "paths": ["/api/admin/*"], "groups": ["engineering", "platform"] },
        { "paths": ["/beta/*"], "groups": ["beta-testers"] }
      ]
    }
  }
}
```

Paths support glob patterns. A user must belong to at least one of the listed groups to access matching pages. Pages not covered by any rule are accessible to all authenticated users.

## Security Notes

- Auth-enabled doc sites skip page caching entirely to prevent content leakage
- Auth-enabled projects also skip AI page caching for the same reason
- JWT tokens are validated on every request at the edge (Cloudflare Worker)
- JWKS keys are fetched once and cached in KV for 1 hour
- SAML assertions are validated using the IdP's X.509 certificate
- All auth endpoints use HTTPS exclusively — HTTP requests are rejected
- Failed authentication attempts are logged and visible in the audit trail (Enterprise plan)