@bettercone/ui
ComponentsEnterprise SSO

SAML Setup Wizard

Guided 5-step wizard for SAML 2.0 SSO configuration with automatic IdP detection and metadata parsing

Overview

Guided 5-step wizard for configuring SAML 2.0 SSO with preset IdP configurations, automatic XML metadata parsing, and visual progress tracking.

Features

  • 5-Step Guided Flow - Visual progress stepper with validation
  • 7 IdP Presets - Azure AD, Okta, Google Workspace, OneLogin, Auth0, JumpCloud, Custom
  • XML Metadata Parser - Auto-extracts SSO URL, certificate, entityID
  • Attribute Mapping - Map SAML assertions to user model
  • Connection Testing - Verify before completion

Installation

npm install @bettercone/ui

Usage

import { SAMLSetupWizard } from '@bettercone/ui'

export default function SetupSAML() {
  return (
    <SAMLSetupWizard
      organizationId="org_123abc"
      onSuccess={(config) => {
        console.log('SAML configured:', config)
      }}
    />
  )
}
import { SAMLSetupWizard } from '@bettercone/ui'
import { useRouter } from 'next/navigation'

export default function SetupSAML() {
  const router = useRouter()

  return (
    <SAMLSetupWizard
      organizationId="org_123abc"
      onSuccess={async (config) => {
        await fetch('/api/sso/saml/save', {
          method: 'POST',
          body: JSON.stringify(config),
        })
        toast.success('SAML SSO configured!')
        router.push('/settings/sso')
      }}
      onError={(error) => toast.error(error.message)}
      onCancel={() => router.back()}
    />
  )
}
import { SAMLSetupWizard } from '@bettercone/ui'

const initialConfig = {
  callbackUrl: 'https://app.acme.com/api/auth/sso/saml2/callback',
  entityId: 'https://app.acme.com',
  signatureAlgorithm: 'sha256' as const,
  wantAssertionsSigned: true,
  mapping: {
    email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
    name: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
  },
}

<SAMLSetupWizard
  organizationId="org_123abc"
  initialConfig={initialConfig}
/>

Wizard Steps

  1. Select IdP - Choose preset (Azure AD, Okta, Google, etc.) or Custom
  2. Upload Metadata - Paste XML or configure manually
  3. Configure - Set ACS URL, Entity ID, security options
  4. Attribute Mapping - Map SAML assertions to user fields
  5. Test & Complete - Verify connection and finalize

IdP Presets

ProviderAuto-Configuration
Azure AD (Entra ID)✅ Default algorithms, NameID format
Okta✅ Recommended SAML settings
Google Workspace✅ Google-specific configuration
OneLogin✅ OneLogin defaults
Auth0✅ Auth0 SAML settings
JumpCloud✅ JumpCloud configuration
CustomManual configuration required

XML Metadata Parsing

Paste your IdP's SAML metadata XML to auto-extract:

  • SSO Entry Point URL
  • X.509 Certificate (PEM formatted)
  • Entity ID / Audience
<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" 
                  entityID="https://idp.example.com/saml2/metadata">
  <IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <KeyDescriptor use="signing">
      <X509Certificate>MIIDdDCCAly...</X509Certificate>
    </KeyDescriptor>
    <SingleSignOnService Location="https://idp.example.com/saml2/sso"/>
  </IDPSSODescriptor>
</EntityDescriptor>

Props

interface SAMLSetupWizardProps {
  organizationId: string
  authClient?: AnyAuthClient
  initialConfig?: Partial<SAMLConfiguration>
  onSuccess?: (config: SAMLConfiguration) => void
  onError?: (error: Error) => void
  onCancel?: () => void
  className?: string
}

SAMLConfiguration Type

interface SAMLConfiguration {
  entryPoint: string
  cert: string
  callbackUrl: string
  audience?: string
  entityId?: string
  wantAssertionsSigned?: boolean
  signatureAlgorithm?: 'sha1' | 'sha256' | 'sha512'
  digestAlgorithm?: 'sha1' | 'sha256' | 'sha512'
  identifierFormat?: string
  mapping?: SAMLAttributeMapping
}

Attribute Mapping

interface SAMLAttributeMapping {
  id?: string
  email?: string
  emailVerified?: string
  name?: string
  firstName?: string
  lastName?: string
  image?: string
  extraFields?: Record<string, string>
}

IdP Examples

Metadata URL:

https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-06/federationmetadata.xml

Attribute Mapping:

const azureMapping = {
  email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
  name: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
  firstName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
  lastName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
}

Metadata URL:

https://{your-okta-domain}/app/{app-id}/sso/saml/metadata

Attribute Mapping:

const oktaMapping = {
  email: 'email',
  name: 'name',
  firstName: 'firstName',
  lastName: 'lastName',
}

SSO URL Format:

https://accounts.google.com/o/saml2/idp?idpid={idp-id}

Attribute Mapping:

const googleMapping = {
  email: 'email',
  name: 'name',
  firstName: 'first_name',
  lastName: 'last_name',
}

Validation

Each step validates before allowing progression:

  1. Step 1: IdP selected
  2. Step 2: Entry point and certificate provided
  3. Step 3: Callback URL exists
  4. Step 4: Email mapping configured
  5. Step 5: Connection test passed

Better Auth Setup

import { betterAuth } from "better-auth"
import { sso } from "better-auth/plugins"

export const auth = betterAuth({
  plugins: [
    sso({
      providers: {
        saml: {
          // SAML configuration added by wizard
        },
      },
    }),
  ],
})

Security Notes

Production Configuration:

  • Use SHA-256 or SHA-512 for signatures
  • Enable wantAssertionsSigned
  • Verify certificates from trusted sources
  • Use HTTPS for all URLs

Best Practices

const productionConfig: Partial<SAMLConfiguration> = {
  signatureAlgorithm: 'sha256',
  digestAlgorithm: 'sha256',
  wantAssertionsSigned: true,
  identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
}

<SAMLSetupWizard
  organizationId="org_acme"
  initialConfig={productionConfig}
/>

Troubleshooting

Metadata Parsing Issues

Ensure XML is valid SAML 2.0 metadata. If parsing fails, use manual configuration.

Certificate Format

Certificates must be in PEM format:

-----BEGIN CERTIFICATE-----
MIIDdDCCAlygAwIBAgIGAYqrJc3fMA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoT
...
-----END CERTIFICATE-----

Connection Test Failures

Common causes:

  • Incorrect SSO URL
  • Invalid/expired certificate
  • Mismatched Entity ID
  • Firewall blocking SAML requests

Resources