plugins/modular-sso/skills/modular-sso/SKILL.md
Implements complete SSO and authentication flows using Scalekit. Handles modular SSO, IdP-initiated login, user session management, and enterprise customer onboarding. Use when adding authentication, SSO, SAML, OIDC, or user login to applications.
npx skillsauth add scalekit-inc/claude-code-authstack modular-ssoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Choose your authentication mode:
This skill covers Modular SSO for applications with existing user management.
Copy this checklist and track progress:
Authentication Integration Progress:
- [ ] Step 1: Configure Modular Auth mode
- [ ] Step 2: Install and configure Scalekit SDK
- [ ] Step 3: Implement authorization URL generation
- [ ] Step 4: Handle IdP-initiated SSO (RECOMMENDED)
- [ ] Step 5: Process authentication callback
- [ ] Step 6: Validate tokens and extract user profile
- [ ] Step 7: Test SSO integration
- [ ] Step 8: Set up customer onboarding flow
Action: Configure environment for Modular SSO:
Result: System ready for modular integration.
Choose the SDK for the project's tech stack:
Node.js:
npm install @scalekit-sdk/node
Python:
pip install scalekit-sdk-python
Go:
go get github.com/scalekit-inc/scalekit-sdk-go
Java:
<dependency>
<groupId>com.scalekit</groupId>
<artifactId>scalekit-sdk-java</artifactId>
</dependency>
Add these credentials to .env file (fetch from Dashboard > Developers > Settings > API credentials):
SCALEKIT_ENVIRONMENT_URL=<environment-url>
SCALEKIT_CLIENT_ID=<client-id>
SCALEKIT_CLIENT_SECRET=<client-secret>
Create authorization URL to redirect users to their identity provider.
Use ONE of these identifiers (evaluated in precedence order):
Node.js:
const scalekit = new ScalekitClient(
process.env.SCALEKIT_ENVIRONMENT_URL,
process.env.SCALEKIT_CLIENT_ID,
process.env.SCALEKIT_CLIENT_SECRET
);
const options = {
organizationId: 'org_15421144869927830', // OR
connectionId: 'conn_15696105471768821', // OR
loginHint: '[email protected]'
};
const authUrl = scalekit.getAuthorizationUrl(
'https://yourapp.com/auth/callback',
options
);
// Redirect user to authUrl
Python:
from scalekit import ScalekitClient, AuthorizationUrlOptions
scalekit = ScalekitClient(
os.getenv('SCALEKIT_ENVIRONMENT_URL'),
os.getenv('SCALEKIT_CLIENT_ID'),
os.getenv('SCALEKIT_CLIENT_SECRET')
)
options = AuthorizationUrlOptions()
options.organization_id = 'org_15421144869927830'
auth_url = scalekit.get_authorization_url(
redirect_uri='https://yourapp.com/auth/callback',
options=options
)
Direct URL (no SDK):
<SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?
response_type=code&
client_id=<CLIENT_ID>&
redirect_uri=<CALLBACK_URL>&
scope=openid profile email&
organization_id=<ORG_ID>
CRITICAL: Implement this to support users who start login from their identity provider portal.
IdP-initiated SSO converts potentially insecure flows into secure SP-initiated flows, protecting against SAML assertion theft and replay attacks.
https://yourapp.com/loginNode.js:
app.get('/login', async (req, res) => {
const { idp_initiated_login, error, error_description } = req.query;
if (error) {
return res.status(400).json({ message: error_description });
}
if (idp_initiated_login) {
// Decode JWT to extract connection details
const claims = await scalekit.getIdpInitiatedLoginClaims(idp_initiated_login);
const options = {
connectionId: claims.connection_id,
organizationId: claims.organization_id,
loginHint: claims.login_hint,
state: claims.relay_state
};
const authUrl = scalekit.getAuthorizationUrl(
'https://yourapp.com/auth/callback',
options
);
return res.redirect(authUrl);
}
// Handle normal login flow
});
Python:
@app.route('/login')
async def handle_login():
idp_initiated_login = request.args.get('idp_initiated_login')
error = request.args.get('error')
if error:
return {'error': request.args.get('error_description')}, 400
if idp_initiated_login:
claims = await scalekit.get_idp_initiated_login_claims(idp_initiated_login)
options = AuthorizationUrlOptions()
options.connection_id = claims.get('connection_id')
options.organization_id = claims.get('organization_id')
options.state = claims.get('relay_state')
auth_url = scalekit.get_authorization_url(
redirect_uri='https://yourapp.com/auth/callback',
options=options
)
return redirect(auth_url)
Handle the callback after successful IdP authentication.
/auth/callbackNode.js:
app.get('/auth/callback', async (req, res) => {
const { code, error, error_description } = req.query;
if (error) {
return res.status(400).json({ error: error_description });
}
try {
// Exchange code for user profile and tokens
const result = await scalekit.authenticateWithCode(
code,
'https://yourapp.com/auth/callback'
);
// Extract user information
const userEmail = result.user.email;
const userName = result.user.givenName + ' ' + result.user.familyName;
const userId = result.user.id;
// Create session for authenticated user
req.session.user = {
id: userId,
email: userEmail,
name: userName
};
res.redirect('/dashboard');
} catch (err) {
res.status(500).json({ error: 'Authentication failed' });
}
});
Python:
@app.route('/auth/callback')
async def auth_callback():
code = request.args.get('code')
error = request.args.get('error')
if error:
return {'error': request.args.get('error_description')}, 400
result = scalekit.authenticate_with_code(
code,
'https://yourapp.com/auth/callback'
)
# Create session
session['user'] = {
'id': result.user.id,
'email': result.user.email,
'name': f"{result.user.given_name} {result.user.family_name}"
}
return redirect('/dashboard')
ALWAYS validate tokens before trusting claims.
Node.js:
// Validate ID token
const idTokenClaims = await scalekit.validateToken(result.idToken);
// Validate access token
const accessTokenClaims = await scalekit.validateToken(result.accessToken);
Python:
id_token_claims = scalekit.validate_token(result['id_token'])
access_token_claims = scalekit.validate_token(result['access_token'])
ID Token includes:
email: User's email addressgiven_name, family_name: User's namesub: Unique user identifier (format: connectionId;userId)oid: Organization IDamr: Authentication method (SSO connection ID)Access Token includes:
sub: User identifierexp: Expiration timestampclient_id: Your application client IDUse the built-in IdP Simulator for comprehensive testing.
Your environment includes pre-configured test organization with domains:
@example.com@example.org@example.com domainTest ALL three scenarios:
Enable SSO for enterprise customers through self-service Admin Portal.
Create organization: Dashboard > Organizations > New Organization
Generate portal link (Node.js):
const portalLink = await scalekit.organization.generatePortalLink(
'org_32656XXXXXX0438'
);
// Share this link with customer's IT admin
console.log('Admin Portal:', portalLink.location);
Share link: Send to customer's IT administrator via email/Slack
Share setup guide: Include the Scalekit SSO setup guide — provider-specific steps for Okta, Azure AD, Google Workspace, and others.
Embed Admin Portal in your app for seamless experience:
// Backend: Generate portal link
const portalLink = await scalekit.organization.generatePortalLink(orgId);
res.json({ portalUrl: portalLink.location });
<!-- Frontend: Embed in iframe -->
<iframe
src="${portalUrl}"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write">
</iframe>
Prevent failed redirects by checking SSO configuration before redirecting:
Node.js:
const domain = email.split('@').pop()?.toLowerCase();
const connections = await scalekit.connections.listConnectionsByDomain({
domain
});
if (connections.length > 0) {
// SSO available - redirect to IdP
const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
domainHint: domain
});
return res.redirect(authUrl);
} else {
// No SSO - show password login
return showPasswordLogin();
}
Enable seamless routing by verifying customer domains:
@megacorp.org) in Admin PortalSet secure session configuration:
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // HTTPS only
httpOnly: true, // Prevent XSS
maxAge: 86400000, // 24 hours
sameSite: 'lax' // CSRF protection
}
}));
Implement session refresh:
// Check token expiration
if (Date.now() / 1000 > accessTokenClaims.exp) {
// Redirect to re-authentication
return res.redirect('/login');
}
Configure Scalekit as Custom Social Connection in Auth0:
Add Scalekit as Custom Auth Provider:
Configure Scalekit as SAML Identity Provider:
Before production deployment, verify:
secure and httpOnly flagsCause: Callback URL not registered in dashboard Fix: Add URL to Dashboard > Authentication > Redirect URLs
Cause: Invalid organization ID or user doesn't belong to organization Fix: Verify organization ID and user's email domain
Cause: Initiate login URL not configured Fix: Set URL in Dashboard > Authentication > Redirects
Cause: Token expired or invalid signature Fix: Check token expiration and environment URL configuration
// Determine organization from subdomain
const subdomain = req.hostname.split('.');
const organization = await getOrganizationBySubdomain(subdomain);
const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
organizationId: organization.scalekitOrgId
});
// Require re-authentication for sensitive operations
if (requiresStepUp && !session.recentAuth) {
return res.redirect('/auth/step-up');
}
app.post('/logout', (req, res) => {
req.session.destroy();
res.redirect('/');
});
Scalekit Dashboard: https://app.scalekit.com
Connection Selector Precedence: connectionId > organizationId > loginHint
Token Expiration: ID tokens expire in 15 minutes, access tokens in 24 hours
Admin Portal Events: Listen for sso.enabled, sso.disabled, session.expired
Support: docs.scalekit.com
Always validate tokens: Never trust token claims without validation
Handle errors gracefully: Show user-friendly messages, log details internally
Test all scenarios: SP-initiated, IdP-initiated, and domain-based routing
Enable domain verification: Provides best user experience
Use progressive enhancement: Start with basic SSO, add advanced features iteratively
Monitor authentication flows: Track success rates and common failure points
development
Walks through a structured production readiness checklist for Scalekit SSO implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, hardening their SSO setup, or wants to verify their Scalekit implementation is production-ready.
testing
Implements Scalekit's admin portal for customer self-serve SSO and SCIM configuration. Generates portal links server-side and embeds the portal as an iframe in the app's settings UI. Use when the user asks to add an admin portal, customer self-serve SSO setup, iframe embed for SSO config, shareable setup link, or let customers configure their own SSO or SCIM connection.
development
Walks through a structured production readiness checklist for Scalekit SCIM provisioning implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their SCIM directory sync implementation is production-ready.
development
Implements SCIM user provisioning using Scalekit's Directory API and webhooks. Use when the user asks to add SCIM, directory sync, user provisioning, deprovisioning, or lifecycle management to their existing application.