From 6be77702a5ee7e20790f6b36fd235093ebbc52da Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Tue, 12 May 2026 22:21:37 +0530
Subject: [PATCH 01/39] Consolidate 5 plugins into AgentKit + SaaSKit
Restructure from 5 plugins (agent-auth, full-stack-auth, mcp-auth,
modular-sso, modular-scim) to 2 plugins (agentkit, saaskit) matching
the Claude Code authstack architecture.
AgentKit (5 skills):
- integrating-agentkit, discovering-connector-tools,
testing-agentkit-tools, exposing-agentkit-via-mcp,
production-readiness-agentkit
- 44 connector reference docs + 6 reference files
SaaSKit (11 skills):
- implementing-saaskit, implementing-saaskit-nextjs,
implementing-saaskit-python, implementing-modular-sso,
implementing-scim-provisioning, adding-mcp-oauth,
implementing-access-control, managing-saaskit-sessions,
migrating-to-saaskit, adding-api-auth,
production-readiness-saaskit
- Framework references: Go, Spring Boot, Laravel, FastAPI, Flask
- MCP framework references: FastMCP, Express, FastAPI
Content improvements included:
- Renamed all skill frontmatter to match new plugin names
- Removed beta SDK version pin
- Fixed broken CONNECTORS.md link
- Validation passes: validate_marketplace.py
Supersedes #5.
---
.agents/plugins/marketplace.json | 44 +---
README.md | 60 ++---
plugins/agent-auth/.codex-plugin/plugin.json | 41 ----
plugins/agent-auth/README.md | 51 ----
.../skills/integrating-agent-auth/SKILL.md | 97 --------
plugins/agentkit/.codex-plugin/plugin.json | 33 +++
plugins/{agent-auth => agentkit}/.mcp.json | 0
plugins/agentkit/README.md | 27 ++
.../references/agent-connectors/README.md | 0
.../references/agent-connectors/airtable.md | 0
.../references/agent-connectors/asana.md | 0
.../references/agent-connectors/attention.md | 0
.../references/agent-connectors/bigquery.md | 0
.../references/agent-connectors/chorus.md | 0
.../agent-connectors/clari_copilot.md | 0
.../references/agent-connectors/clickup.md | 0
.../references/agent-connectors/confluence.md | 0
.../references/agent-connectors/dropbox.md | 0
.../references/agent-connectors/fathom.md | 0
.../references/agent-connectors/freshdesk.md | 0
.../references/agent-connectors/github.md | 0
.../references/agent-connectors/gmail.md | 0
.../references/agent-connectors/gong.md | 0
.../references/agent-connectors/google_ads.md | 0
.../agent-connectors/google_docs.md | 0
.../agent-connectors/google_drive.md | 0
.../agent-connectors/google_forms.md | 0
.../agent-connectors/google_meets.md | 0
.../agent-connectors/google_sheets.md | 0
.../agent-connectors/google_slides.md | 0
.../agent-connectors/googlecalendar.md | 0
.../references/agent-connectors/hubspot.md | 0
.../references/agent-connectors/intercom.md | 0
.../references/agent-connectors/jira.md | 0
.../references/agent-connectors/linear.md | 0
.../agent-connectors/microsoft_excel.md | 0
.../agent-connectors/microsoft_teams.md | 0
.../agent-connectors/microsoft_word.md | 0
.../references/agent-connectors/monday.md | 0
.../references/agent-connectors/notion.md | 0
.../references/agent-connectors/onedrive.md | 0
.../references/agent-connectors/onenote.md | 0
.../references/agent-connectors/outlook.md | 0
.../references/agent-connectors/salesforce.md | 0
.../references/agent-connectors/servicenow.md | 0
.../references/agent-connectors/sharepoint.md | 0
.../references/agent-connectors/slack.md | 0
.../references/agent-connectors/snowflake.md | 0
.../references/agent-connectors/trello.md | 0
.../references/agent-connectors/zendesk.md | 0
.../references/agent-connectors/zoom.md | 0
.../references/byoc.md | 0
.../references/code-samples.md | 0
.../references/connected-accounts.md | 0
.../references/connections.md | 0
.../references/providers.md | 0
.../references/redirects.md | 0
.../discovering-connector-tools/SKILL.md | 55 +++++
.../exposing-agentkit-via-mcp}/SKILL.md | 2 +-
.../skills/integrating-agentkit}/SKILL.md | 8 +-
.../production-readiness-agentkit}/SKILL.md | 12 +-
.../skills/testing-agentkit-tools/SKILL.md | 93 +++++++
.../full-stack-auth/.codex-plugin/plugin.json | 41 ----
plugins/full-stack-auth/README.md | 61 -----
.../skills/adding-oauth2-to-apis/SKILL.md | 232 ------------------
.../skills/implement-logout/SKILL.md | 187 --------------
.../skills/implementing-admin-portal/SKILL.md | 152 ------------
.../skills/implementing-scalekit-fsa/SKILL.md | 79 ------
.../production-readiness-scalekit/SKILL.md | 159 ------------
plugins/mcp-auth/.codex-plugin/plugin.json | 41 ----
plugins/mcp-auth/.mcp.json | 12 -
plugins/mcp-auth/README.md | 48 ----
plugins/mcp-auth/references/redirects.md | 76 ------
.../mcp-auth/skills/adding-mcp-oauth/SKILL.md | 118 ---------
.../production-readiness-scalekit/SKILL.md | 62 -----
.../modular-scim/.codex-plugin/plugin.json | 42 ----
plugins/modular-scim/.mcp.json | 8 -
plugins/modular-scim/README.md | 45 ----
plugins/modular-scim/references/redirects.md | 76 ------
.../skills/implementing-admin-portal/SKILL.md | 155 ------------
.../implementing-scim-provisioning/SKILL.md | 73 ------
.../production-readiness-scalekit/SKILL.md | 86 -------
plugins/modular-sso/.codex-plugin/plugin.json | 42 ----
plugins/modular-sso/.mcp.json | 8 -
plugins/modular-sso/README.md | 43 ----
plugins/modular-sso/references/redirects.md | 76 ------
.../skills/implementing-admin-portal/SKILL.md | 153 ------------
.../production-readiness-scalekit/SKILL.md | 110 ---------
plugins/saaskit/.codex-plugin/plugin.json | 33 +++
.../{full-stack-auth => saaskit}/.mcp.json | 0
plugins/saaskit/README.md | 32 +++
.../references/bring-your-own-auth.md | 0
.../references/redirects.md | 0
.../references/scalekit-logs.md | 0
.../references/scalekit-mcp-server.md | 0
.../references/scalekit-user-profiles.md | 0
.../skills/adding-api-auth}/SKILL.md | 2 +-
.../skills/adding-mcp-oauth}/SKILL.md | 0
.../adding-mcp-oauth/express-reference.md} | 0
.../adding-mcp-oauth/fastapi-reference.md} | 0
.../adding-mcp-oauth/fastmcp-reference.md} | 0
.../implementing-access-control/SKILL.md | 0
.../skills/implementing-modular-sso}/SKILL.md | 2 +-
.../implementing-saaskit-nextjs}/SKILL.md | 2 +-
.../implementing-saaskit-python}/SKILL.md | 2 +-
.../fastapi-reference.md} | 0
.../flask-reference.md} | 0
.../skills/implementing-saaskit}/SKILL.md | 2 +-
.../implementing-saaskit/go-reference.md} | 0
.../laravel-reference.md} | 0
.../springboot-reference.md} | 0
.../implementing-scim-provisioning}/SKILL.md | 0
.../managing-saaskit-sessions}/SKILL.md | 2 +-
.../migrating-to-saaskit}/AUDIT-CHECKLIST.md | 0
.../migrating-to-saaskit}/IMPORT-SAMPLES.md | 0
.../skills/migrating-to-saaskit}/SKILL.md | 2 +-
.../production-readiness-saaskit/SKILL.md | 64 +++++
117 files changed, 382 insertions(+), 2469 deletions(-)
delete mode 100644 plugins/agent-auth/.codex-plugin/plugin.json
delete mode 100644 plugins/agent-auth/README.md
delete mode 100644 plugins/agent-auth/skills/integrating-agent-auth/SKILL.md
create mode 100644 plugins/agentkit/.codex-plugin/plugin.json
rename plugins/{agent-auth => agentkit}/.mcp.json (100%)
create mode 100644 plugins/agentkit/README.md
rename plugins/{agent-auth => agentkit}/references/agent-connectors/README.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/airtable.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/asana.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/attention.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/bigquery.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/chorus.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/clari_copilot.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/clickup.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/confluence.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/dropbox.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/fathom.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/freshdesk.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/github.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/gmail.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/gong.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_ads.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_docs.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_drive.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_forms.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_meets.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_sheets.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/google_slides.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/googlecalendar.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/hubspot.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/intercom.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/jira.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/linear.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/microsoft_excel.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/microsoft_teams.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/microsoft_word.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/monday.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/notion.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/onedrive.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/onenote.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/outlook.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/salesforce.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/servicenow.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/sharepoint.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/slack.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/snowflake.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/trello.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/zendesk.md (100%)
rename plugins/{agent-auth => agentkit}/references/agent-connectors/zoom.md (100%)
rename plugins/{agent-auth => agentkit}/references/byoc.md (100%)
rename plugins/{agent-auth => agentkit}/references/code-samples.md (100%)
rename plugins/{agent-auth => agentkit}/references/connected-accounts.md (100%)
rename plugins/{agent-auth => agentkit}/references/connections.md (100%)
rename plugins/{agent-auth => agentkit}/references/providers.md (100%)
rename plugins/{agent-auth => agentkit}/references/redirects.md (100%)
create mode 100644 plugins/agentkit/skills/discovering-connector-tools/SKILL.md
rename plugins/{agent-auth/skills/building-agent-mcp-server => agentkit/skills/exposing-agentkit-via-mcp}/SKILL.md (99%)
rename plugins/{agent-auth/skills/agent-auth => agentkit/skills/integrating-agentkit}/SKILL.md (94%)
rename plugins/{agent-auth/skills/production-readiness-scalekit => agentkit/skills/production-readiness-agentkit}/SKILL.md (80%)
create mode 100644 plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
delete mode 100644 plugins/full-stack-auth/.codex-plugin/plugin.json
delete mode 100644 plugins/full-stack-auth/README.md
delete mode 100644 plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md
delete mode 100644 plugins/full-stack-auth/skills/implement-logout/SKILL.md
delete mode 100644 plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md
delete mode 100644 plugins/full-stack-auth/skills/implementing-scalekit-fsa/SKILL.md
delete mode 100644 plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md
delete mode 100644 plugins/mcp-auth/.codex-plugin/plugin.json
delete mode 100644 plugins/mcp-auth/.mcp.json
delete mode 100644 plugins/mcp-auth/README.md
delete mode 100644 plugins/mcp-auth/references/redirects.md
delete mode 100644 plugins/mcp-auth/skills/adding-mcp-oauth/SKILL.md
delete mode 100644 plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md
delete mode 100644 plugins/modular-scim/.codex-plugin/plugin.json
delete mode 100644 plugins/modular-scim/.mcp.json
delete mode 100644 plugins/modular-scim/README.md
delete mode 100644 plugins/modular-scim/references/redirects.md
delete mode 100644 plugins/modular-scim/skills/implementing-admin-portal/SKILL.md
delete mode 100644 plugins/modular-scim/skills/implementing-scim-provisioning/SKILL.md
delete mode 100644 plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md
delete mode 100644 plugins/modular-sso/.codex-plugin/plugin.json
delete mode 100644 plugins/modular-sso/.mcp.json
delete mode 100644 plugins/modular-sso/README.md
delete mode 100644 plugins/modular-sso/references/redirects.md
delete mode 100644 plugins/modular-sso/skills/implementing-admin-portal/SKILL.md
delete mode 100644 plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md
create mode 100644 plugins/saaskit/.codex-plugin/plugin.json
rename plugins/{full-stack-auth => saaskit}/.mcp.json (100%)
create mode 100644 plugins/saaskit/README.md
rename plugins/{mcp-auth => saaskit}/references/bring-your-own-auth.md (100%)
rename plugins/{full-stack-auth => saaskit}/references/redirects.md (100%)
rename plugins/{full-stack-auth => saaskit}/references/scalekit-logs.md (100%)
rename plugins/{mcp-auth => saaskit}/references/scalekit-mcp-server.md (100%)
rename plugins/{full-stack-auth => saaskit}/references/scalekit-user-profiles.md (100%)
rename plugins/{full-stack-auth/skills/adding-api-key-auth => saaskit/skills/adding-api-auth}/SKILL.md (99%)
rename plugins/{mcp-auth/skills/mcp-auth => saaskit/skills/adding-mcp-oauth}/SKILL.md (100%)
rename plugins/{mcp-auth/skills/express-mcp-server/SKILL.md => saaskit/skills/adding-mcp-oauth/express-reference.md} (100%)
rename plugins/{mcp-auth/skills/fastapi-fastmcp/SKILL.md => saaskit/skills/adding-mcp-oauth/fastapi-reference.md} (100%)
rename plugins/{mcp-auth/skills/add-auth-fastmcp/SKILL.md => saaskit/skills/adding-mcp-oauth/fastmcp-reference.md} (100%)
rename plugins/{full-stack-auth => saaskit}/skills/implementing-access-control/SKILL.md (100%)
rename plugins/{modular-sso/skills/modular-sso => saaskit/skills/implementing-modular-sso}/SKILL.md (98%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-nextjs-auth => saaskit/skills/implementing-saaskit-nextjs}/SKILL.md (99%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-django-auth => saaskit/skills/implementing-saaskit-python}/SKILL.md (99%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-fastapi-auth/SKILL.md => saaskit/skills/implementing-saaskit-python/fastapi-reference.md} (100%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-flask-auth/SKILL.md => saaskit/skills/implementing-saaskit-python/flask-reference.md} (100%)
rename plugins/{full-stack-auth/skills/full-stack-auth => saaskit/skills/implementing-saaskit}/SKILL.md (99%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-go-auth/SKILL.md => saaskit/skills/implementing-saaskit/go-reference.md} (100%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-laravel-auth/SKILL.md => saaskit/skills/implementing-saaskit/laravel-reference.md} (100%)
rename plugins/{full-stack-auth/skills/implementing-scalekit-springboot-auth/SKILL.md => saaskit/skills/implementing-saaskit/springboot-reference.md} (100%)
rename plugins/{modular-scim/skills/modular-scim => saaskit/skills/implementing-scim-provisioning}/SKILL.md (100%)
rename plugins/{full-stack-auth/skills/manage-user-sessions => saaskit/skills/managing-saaskit-sessions}/SKILL.md (99%)
rename plugins/{full-stack-auth/skills/migrating-to-scalekit-auth => saaskit/skills/migrating-to-saaskit}/AUDIT-CHECKLIST.md (100%)
rename plugins/{full-stack-auth/skills/migrating-to-scalekit-auth => saaskit/skills/migrating-to-saaskit}/IMPORT-SAMPLES.md (100%)
rename plugins/{full-stack-auth/skills/migrating-to-scalekit-auth => saaskit/skills/migrating-to-saaskit}/SKILL.md (99%)
create mode 100644 plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json
index bc6b6c8..cd34ea1 100644
--- a/.agents/plugins/marketplace.json
+++ b/.agents/plugins/marketplace.json
@@ -5,22 +5,10 @@
},
"plugins": [
{
- "name": "mcp-auth",
+ "name": "agentkit",
"source": {
"source": "local",
- "path": "./plugins/mcp-auth"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "MCP Security"
- },
- {
- "name": "agent-auth",
- "source": {
- "source": "local",
- "path": "./plugins/agent-auth"
+ "path": "./plugins/agentkit"
},
"policy": {
"installation": "AVAILABLE",
@@ -29,34 +17,10 @@
"category": "Agent Auth"
},
{
- "name": "modular-sso",
- "source": {
- "source": "local",
- "path": "./plugins/modular-sso"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "Enterprise SSO"
- },
- {
- "name": "modular-scim",
- "source": {
- "source": "local",
- "path": "./plugins/modular-scim"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "Provisioning"
- },
- {
- "name": "full-stack-auth",
+ "name": "saaskit",
"source": {
"source": "local",
- "path": "./plugins/full-stack-auth"
+ "path": "./plugins/saaskit"
},
"policy": {
"installation": "AVAILABLE",
diff --git a/README.md b/README.md
index 1ef9574..43ec856 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
-Scalekit Auth Plugins for OpenAI Codex — the auth stack for agents.
-Add SSO, SCIM, MCP Auth, agent auth, and tool-calling to your Codex projects.
+Scalekit Auth Stack for OpenAI Codex — AgentKit and SaaSKit plugins.
+Add agent auth, tool calling, SSO, SCIM, MCP auth, and session management to your Codex projects.
[](./LICENSE)
[](https://github.com/scalekit-inc/codex-authstack/pulls)
@@ -14,19 +14,16 @@ Add SSO, SCIM, MCP Auth, agent auth, and tool-calling to your Codex projects.
Connections`
-2. Create the connector
-3. Save the connection name
-4. Reuse that exact connection name in code
-
-## Working Checklist
-
-```text
-Agent Auth Integration:
-- [ ] Install the SDK and initialize the client
-- [ ] Create or fetch a connected account
-- [ ] Send the user through authorization if needed
-- [ ] Fetch the connected account again before API use
-- [ ] Use the access token against the third-party API
-```
-
-## Node.js Pattern
-
-```ts
-import { ScalekitClient } from '@scalekit-sdk/node';
-
-const client = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
- process.env.SCALEKIT_CLIENT_ID!,
- process.env.SCALEKIT_CLIENT_SECRET!
-);
-
-const response = await client.connectedAccounts.getOrCreateConnectedAccount({
- connector: 'gmail',
- identifier: 'user_123',
-});
-
-const connectedAccount = response.connectedAccount;
-
-if (connectedAccount?.status !== 'ACTIVE') {
- const linkResponse =
- await client.connectedAccounts.getMagicLinkForConnectedAccount({
- connector: 'gmail',
- identifier: 'user_123',
- });
-
- console.log(linkResponse.link);
-}
-```
-
-## Python Pattern
-
-```python
-import os
-import scalekit.client
-
-client = scalekit.client.ScalekitClient(
- client_id=os.getenv("SCALEKIT_CLIENT_ID"),
- client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
-)
-
-response = client.actions.get_or_create_connected_account(
- connection_name="gmail",
- identifier="user_123",
-)
-connected_account = response.connected_account
-```
-
-## Token Usage Rule
-
-Always refresh your view of the connected account immediately before making the downstream API call. Scalekit can refresh tokens automatically, and stale cached account objects are a common source of confusion.
-
-## Practical Review Points
-
-- Make sure the dashboard connection name and the code-side connector identifier match.
-- In web apps, redirect users to the authorization link instead of only printing it.
-- For agent workflows, keep user identity stable so the same person maps to the same connected account record.
-- Review token handling separately from third-party API logic so auth failures are easy to isolate.
diff --git a/plugins/agentkit/.codex-plugin/plugin.json b/plugins/agentkit/.codex-plugin/plugin.json
new file mode 100644
index 0000000..62612d8
--- /dev/null
+++ b/plugins/agentkit/.codex-plugin/plugin.json
@@ -0,0 +1,33 @@
+{
+ "name": "agentkit",
+ "version": "2.0.0",
+ "description": "Authentication for AI agents. OAuth flows, token vault, 40+ connectors, tool discovery, and live testing.",
+ "author": {
+ "name": "Scalekit Inc",
+ "email": "support@scalekit.com",
+ "url": "https://scalekit.com"
+ },
+ "homepage": "https://docs.scalekit.com/agentkit/overview.md",
+ "repository": "https://github.com/scalekit-inc/codex-authstack",
+ "license": "MIT",
+ "keywords": ["scalekit", "agentkit", "agent-auth", "oauth", "connectors", "tool-calling"],
+ "skills": "./skills/",
+ "mcpServers": "./.mcp.json",
+ "interface": {
+ "displayName": "AgentKit",
+ "shortDescription": "Connect agents to third-party apps safely.",
+ "longDescription": "Authentication for AI agents. OAuth flows, token vault, 40+ connectors (Gmail, Slack, Salesforce, etc.), tool discovery, and live testing — so agents can act on behalf of users.",
+ "developerName": "Scalekit",
+ "category": "Agent Auth",
+ "capabilities": ["Interactive", "Write"],
+ "websiteURL": "https://docs.scalekit.com/agentkit/overview.md",
+ "privacyPolicyURL": "https://www.scalekit.com/privacy",
+ "termsOfServiceURL": "https://www.scalekit.com/terms",
+ "defaultPrompt": [
+ "Integrate AgentKit for Gmail or Slack.",
+ "Set up a connected account flow for this agent.",
+ "Discover available tools for a connector."
+ ],
+ "brandColor": "#1D4ED8"
+ }
+}
diff --git a/plugins/agent-auth/.mcp.json b/plugins/agentkit/.mcp.json
similarity index 100%
rename from plugins/agent-auth/.mcp.json
rename to plugins/agentkit/.mcp.json
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
new file mode 100644
index 0000000..9ceef6e
--- /dev/null
+++ b/plugins/agentkit/README.md
@@ -0,0 +1,27 @@
+# AgentKit for Codex
+
+Authentication for AI agents. This plugin brings Scalekit AgentKit into Codex so agents can connect users to third-party apps, discover the right tools, and execute authenticated tool calls on their behalf.
+
+AgentKit handles the full OAuth lifecycle — authorization, token vault, and automatic refresh — across 40+ connectors (Gmail, Slack, Salesforce, Notion, and more).
+
+## Skills
+
+- `integrating-agentkit` — Core integration: SDK setup, connected accounts, OAuth flows, token fetching, downstream API calls, and agent framework examples.
+- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
+- `testing-agentkit-tools` — Generates authorization links, fetches live tool metadata, and executes tools.
+- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
+- `production-readiness-agentkit` — Structured production readiness checklist for AgentKit integrations.
+
+## Configuration
+
+Required environment variables:
+
+- `SCALEKIT_ENV_URL`
+- `SCALEKIT_CLIENT_ID`
+- `SCALEKIT_CLIENT_SECRET`
+
+## Links
+
+- [AgentKit overview](https://docs.scalekit.com/agentkit/overview.md)
+- [AgentKit quickstart](https://docs.scalekit.com/agentkit/quickstart.md)
+- [LLM docs map](https://docs.scalekit.com/llms.txt)
diff --git a/plugins/agent-auth/references/agent-connectors/README.md b/plugins/agentkit/references/agent-connectors/README.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/README.md
rename to plugins/agentkit/references/agent-connectors/README.md
diff --git a/plugins/agent-auth/references/agent-connectors/airtable.md b/plugins/agentkit/references/agent-connectors/airtable.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/airtable.md
rename to plugins/agentkit/references/agent-connectors/airtable.md
diff --git a/plugins/agent-auth/references/agent-connectors/asana.md b/plugins/agentkit/references/agent-connectors/asana.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/asana.md
rename to plugins/agentkit/references/agent-connectors/asana.md
diff --git a/plugins/agent-auth/references/agent-connectors/attention.md b/plugins/agentkit/references/agent-connectors/attention.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/attention.md
rename to plugins/agentkit/references/agent-connectors/attention.md
diff --git a/plugins/agent-auth/references/agent-connectors/bigquery.md b/plugins/agentkit/references/agent-connectors/bigquery.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/bigquery.md
rename to plugins/agentkit/references/agent-connectors/bigquery.md
diff --git a/plugins/agent-auth/references/agent-connectors/chorus.md b/plugins/agentkit/references/agent-connectors/chorus.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/chorus.md
rename to plugins/agentkit/references/agent-connectors/chorus.md
diff --git a/plugins/agent-auth/references/agent-connectors/clari_copilot.md b/plugins/agentkit/references/agent-connectors/clari_copilot.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/clari_copilot.md
rename to plugins/agentkit/references/agent-connectors/clari_copilot.md
diff --git a/plugins/agent-auth/references/agent-connectors/clickup.md b/plugins/agentkit/references/agent-connectors/clickup.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/clickup.md
rename to plugins/agentkit/references/agent-connectors/clickup.md
diff --git a/plugins/agent-auth/references/agent-connectors/confluence.md b/plugins/agentkit/references/agent-connectors/confluence.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/confluence.md
rename to plugins/agentkit/references/agent-connectors/confluence.md
diff --git a/plugins/agent-auth/references/agent-connectors/dropbox.md b/plugins/agentkit/references/agent-connectors/dropbox.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/dropbox.md
rename to plugins/agentkit/references/agent-connectors/dropbox.md
diff --git a/plugins/agent-auth/references/agent-connectors/fathom.md b/plugins/agentkit/references/agent-connectors/fathom.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/fathom.md
rename to plugins/agentkit/references/agent-connectors/fathom.md
diff --git a/plugins/agent-auth/references/agent-connectors/freshdesk.md b/plugins/agentkit/references/agent-connectors/freshdesk.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/freshdesk.md
rename to plugins/agentkit/references/agent-connectors/freshdesk.md
diff --git a/plugins/agent-auth/references/agent-connectors/github.md b/plugins/agentkit/references/agent-connectors/github.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/github.md
rename to plugins/agentkit/references/agent-connectors/github.md
diff --git a/plugins/agent-auth/references/agent-connectors/gmail.md b/plugins/agentkit/references/agent-connectors/gmail.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/gmail.md
rename to plugins/agentkit/references/agent-connectors/gmail.md
diff --git a/plugins/agent-auth/references/agent-connectors/gong.md b/plugins/agentkit/references/agent-connectors/gong.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/gong.md
rename to plugins/agentkit/references/agent-connectors/gong.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_ads.md b/plugins/agentkit/references/agent-connectors/google_ads.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_ads.md
rename to plugins/agentkit/references/agent-connectors/google_ads.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_docs.md b/plugins/agentkit/references/agent-connectors/google_docs.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_docs.md
rename to plugins/agentkit/references/agent-connectors/google_docs.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_drive.md b/plugins/agentkit/references/agent-connectors/google_drive.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_drive.md
rename to plugins/agentkit/references/agent-connectors/google_drive.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_forms.md b/plugins/agentkit/references/agent-connectors/google_forms.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_forms.md
rename to plugins/agentkit/references/agent-connectors/google_forms.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_meets.md b/plugins/agentkit/references/agent-connectors/google_meets.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_meets.md
rename to plugins/agentkit/references/agent-connectors/google_meets.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_sheets.md b/plugins/agentkit/references/agent-connectors/google_sheets.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_sheets.md
rename to plugins/agentkit/references/agent-connectors/google_sheets.md
diff --git a/plugins/agent-auth/references/agent-connectors/google_slides.md b/plugins/agentkit/references/agent-connectors/google_slides.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/google_slides.md
rename to plugins/agentkit/references/agent-connectors/google_slides.md
diff --git a/plugins/agent-auth/references/agent-connectors/googlecalendar.md b/plugins/agentkit/references/agent-connectors/googlecalendar.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/googlecalendar.md
rename to plugins/agentkit/references/agent-connectors/googlecalendar.md
diff --git a/plugins/agent-auth/references/agent-connectors/hubspot.md b/plugins/agentkit/references/agent-connectors/hubspot.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/hubspot.md
rename to plugins/agentkit/references/agent-connectors/hubspot.md
diff --git a/plugins/agent-auth/references/agent-connectors/intercom.md b/plugins/agentkit/references/agent-connectors/intercom.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/intercom.md
rename to plugins/agentkit/references/agent-connectors/intercom.md
diff --git a/plugins/agent-auth/references/agent-connectors/jira.md b/plugins/agentkit/references/agent-connectors/jira.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/jira.md
rename to plugins/agentkit/references/agent-connectors/jira.md
diff --git a/plugins/agent-auth/references/agent-connectors/linear.md b/plugins/agentkit/references/agent-connectors/linear.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/linear.md
rename to plugins/agentkit/references/agent-connectors/linear.md
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_excel.md b/plugins/agentkit/references/agent-connectors/microsoft_excel.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/microsoft_excel.md
rename to plugins/agentkit/references/agent-connectors/microsoft_excel.md
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_teams.md b/plugins/agentkit/references/agent-connectors/microsoft_teams.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/microsoft_teams.md
rename to plugins/agentkit/references/agent-connectors/microsoft_teams.md
diff --git a/plugins/agent-auth/references/agent-connectors/microsoft_word.md b/plugins/agentkit/references/agent-connectors/microsoft_word.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/microsoft_word.md
rename to plugins/agentkit/references/agent-connectors/microsoft_word.md
diff --git a/plugins/agent-auth/references/agent-connectors/monday.md b/plugins/agentkit/references/agent-connectors/monday.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/monday.md
rename to plugins/agentkit/references/agent-connectors/monday.md
diff --git a/plugins/agent-auth/references/agent-connectors/notion.md b/plugins/agentkit/references/agent-connectors/notion.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/notion.md
rename to plugins/agentkit/references/agent-connectors/notion.md
diff --git a/plugins/agent-auth/references/agent-connectors/onedrive.md b/plugins/agentkit/references/agent-connectors/onedrive.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/onedrive.md
rename to plugins/agentkit/references/agent-connectors/onedrive.md
diff --git a/plugins/agent-auth/references/agent-connectors/onenote.md b/plugins/agentkit/references/agent-connectors/onenote.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/onenote.md
rename to plugins/agentkit/references/agent-connectors/onenote.md
diff --git a/plugins/agent-auth/references/agent-connectors/outlook.md b/plugins/agentkit/references/agent-connectors/outlook.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/outlook.md
rename to plugins/agentkit/references/agent-connectors/outlook.md
diff --git a/plugins/agent-auth/references/agent-connectors/salesforce.md b/plugins/agentkit/references/agent-connectors/salesforce.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/salesforce.md
rename to plugins/agentkit/references/agent-connectors/salesforce.md
diff --git a/plugins/agent-auth/references/agent-connectors/servicenow.md b/plugins/agentkit/references/agent-connectors/servicenow.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/servicenow.md
rename to plugins/agentkit/references/agent-connectors/servicenow.md
diff --git a/plugins/agent-auth/references/agent-connectors/sharepoint.md b/plugins/agentkit/references/agent-connectors/sharepoint.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/sharepoint.md
rename to plugins/agentkit/references/agent-connectors/sharepoint.md
diff --git a/plugins/agent-auth/references/agent-connectors/slack.md b/plugins/agentkit/references/agent-connectors/slack.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/slack.md
rename to plugins/agentkit/references/agent-connectors/slack.md
diff --git a/plugins/agent-auth/references/agent-connectors/snowflake.md b/plugins/agentkit/references/agent-connectors/snowflake.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/snowflake.md
rename to plugins/agentkit/references/agent-connectors/snowflake.md
diff --git a/plugins/agent-auth/references/agent-connectors/trello.md b/plugins/agentkit/references/agent-connectors/trello.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/trello.md
rename to plugins/agentkit/references/agent-connectors/trello.md
diff --git a/plugins/agent-auth/references/agent-connectors/zendesk.md b/plugins/agentkit/references/agent-connectors/zendesk.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/zendesk.md
rename to plugins/agentkit/references/agent-connectors/zendesk.md
diff --git a/plugins/agent-auth/references/agent-connectors/zoom.md b/plugins/agentkit/references/agent-connectors/zoom.md
similarity index 100%
rename from plugins/agent-auth/references/agent-connectors/zoom.md
rename to plugins/agentkit/references/agent-connectors/zoom.md
diff --git a/plugins/agent-auth/references/byoc.md b/plugins/agentkit/references/byoc.md
similarity index 100%
rename from plugins/agent-auth/references/byoc.md
rename to plugins/agentkit/references/byoc.md
diff --git a/plugins/agent-auth/references/code-samples.md b/plugins/agentkit/references/code-samples.md
similarity index 100%
rename from plugins/agent-auth/references/code-samples.md
rename to plugins/agentkit/references/code-samples.md
diff --git a/plugins/agent-auth/references/connected-accounts.md b/plugins/agentkit/references/connected-accounts.md
similarity index 100%
rename from plugins/agent-auth/references/connected-accounts.md
rename to plugins/agentkit/references/connected-accounts.md
diff --git a/plugins/agent-auth/references/connections.md b/plugins/agentkit/references/connections.md
similarity index 100%
rename from plugins/agent-auth/references/connections.md
rename to plugins/agentkit/references/connections.md
diff --git a/plugins/agent-auth/references/providers.md b/plugins/agentkit/references/providers.md
similarity index 100%
rename from plugins/agent-auth/references/providers.md
rename to plugins/agentkit/references/providers.md
diff --git a/plugins/agent-auth/references/redirects.md b/plugins/agentkit/references/redirects.md
similarity index 100%
rename from plugins/agent-auth/references/redirects.md
rename to plugins/agentkit/references/redirects.md
diff --git a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
new file mode 100644
index 0000000..1796077
--- /dev/null
+++ b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
@@ -0,0 +1,55 @@
+---
+name: discovering-connector-tools
+description: Discovers live tools for a Scalekit AgentKit connector and explains their input and output schemas. Use when a user asks what tools are available for Gmail, Slack, Salesforce, or another connector, wants to inspect input_schema or output_schema, or needs help narrowing the tool set for an agent.
+---
+
+# Discovering Connector Tools
+
+Use live AgentKit metadata as the source of truth for tool names, required inputs, and output schemas.
+
+Do not rely on the static connector notes as a complete catalog. Those files are curated reference material and may lag the live platform.
+
+## When to use this skill
+
+Use this skill when the user asks:
+
+- what tools exist for a connector
+- which tool should the agent use
+- what inputs a tool requires
+- what output shape a tool returns
+- how to reduce the tool set before giving tools to an LLM
+
+## Discovery workflow
+
+1. Identify the target connector or exact tool name.
+2. Use the Scalekit MCP server or SDK to fetch live tool metadata.
+3. Summarize:
+ - tool name
+ - connector
+ - what the tool does
+ - required fields from `input_schema.required`
+ - optional fields from `input_schema.properties`
+ - important fields from `output_schema.properties`
+4. Recommend the smallest useful tool set for the workflow.
+5. If live credentials are unavailable, use the connector notes only as a fallback and say they may be stale.
+
+## Terminology
+
+- `connector`: Gmail, Slack, Salesforce, Notion, or a custom connector
+- `connection`: the exact dashboard configuration name used for authorization
+- `connected account`: the per-user authorized record
+- `tool`: the executable action exposed by a connector
+
+Use `connector` in explanations. Only use `provider` when the SDK or API filter field literally expects that name.
+
+## What to emphasize
+
+- `connection_name` is the exact dashboard value and may not equal the connector slug.
+- Tool metadata is the durable way to determine current inputs and outputs.
+- Restrict the tool set before handing it to an LLM. Fewer relevant tools improve tool selection and parameter filling.
+
+## Deep reference
+
+- Connector reference: [../../references/agent-connectors/README.md](../../references/agent-connectors/README.md)
+- Connected accounts lifecycle: [../../references/connected-accounts.md](../../references/connected-accounts.md)
+- Code samples: [../../references/code-samples.md](../../references/code-samples.md)
diff --git a/plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
similarity index 99%
rename from plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md
rename to plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
index b8e85b7..20b19e6 100644
--- a/plugins/agent-auth/skills/building-agent-mcp-server/SKILL.md
+++ b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
@@ -1,5 +1,5 @@
---
-name: building-agent-mcp-server
+name: exposing-agentkit-via-mcp
description: Guides developers through creating a Scalekit MCP server with authenticated tool access. Use when building an MCP server, exposing Scalekit tools over MCP, or connecting AI agents via LangChain/LangGraph MCP adapters.
---
diff --git a/plugins/agent-auth/skills/agent-auth/SKILL.md b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
similarity index 94%
rename from plugins/agent-auth/skills/agent-auth/SKILL.md
rename to plugins/agentkit/skills/integrating-agentkit/SKILL.md
index 05bf999..d338e27 100644
--- a/plugins/agent-auth/skills/agent-auth/SKILL.md
+++ b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
@@ -1,6 +1,6 @@
---
-name: integrating-agent-auth
-description: Integrates Scalekit Agent Auth into a project to handle OAuth flows, token storage, and automatic refresh for third-party services (Gmail, Slack, Notion, Calendar). Use when a user needs to connect to an external service, authorize OAuth access, fetch access or refresh tokens, or execute API calls on behalf of a user.
+name: integrating-agentkit
+description: Integrates Scalekit AgentKit into a project to handle OAuth flows, token storage, and automatic refresh for third-party connectors (Gmail, Slack, Notion, Calendar, and 40+ more). Use when a user needs to connect to an external service, authorize OAuth access, fetch access or refresh tokens, execute API calls on behalf of a user, or build agents with LangChain or Google ADK.
---
# Agent Auth Integration
@@ -39,7 +39,7 @@ actions = scalekit.actions
**Node.js**
```bash
-npm install @scalekit-sdk/node@2.2.0-beta.1
+npm install @scalekit-sdk/node
```
```typescript
import { ScalekitClient } from '@scalekit-sdk/node';
@@ -223,7 +223,7 @@ for (const msg of messages) {
Replace `"gmail"` with any supported connector name: `slack`, `notion`, `calendar`, etc.
The SDK workflow (Steps 1–3) is identical for all connectors. Only the downstream API call (Step 4) changes.
-For connector-specific API details, see [CONNECTORS.md](CONNECTORS.md).
+For connector-specific API details, see the [agent connectors reference](../../references/agent-connectors/README.md).
## Building agents
diff --git a/plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
similarity index 80%
rename from plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md
rename to plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
index 152ffd3..4f9ea78 100644
--- a/plugins/agent-auth/skills/production-readiness-scalekit/SKILL.md
+++ b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
@@ -1,9 +1,9 @@
---
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit agent authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their agent OAuth implementation is production-ready.
+name: production-readiness-agentkit
+description: Walks through a structured production readiness checklist for Scalekit AgentKit implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their AgentKit authorization and tool-calling setup is production-ready.
---
-# Scalekit Agent Auth Production Readiness
+# Scalekit AgentKit Production Readiness
Work through each section in order — earlier sections are blockers for later ones.
@@ -60,3 +60,9 @@ Work through each section in order — earlier sections are blockers for later o
- OAuth authorization completion rate (initiated vs completed)
- Per-service API error rates (distinguish auth errors from service errors)
- Token expiry distribution (are tokens being refreshed proactively?)
+
+## Deep reference
+
+- Connections: [../../references/connections.md](../../references/connections.md)
+- Connected accounts: [../../references/connected-accounts.md](../../references/connected-accounts.md)
+- BYOC: [../../references/byoc.md](../../references/byoc.md)
diff --git a/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md b/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
new file mode 100644
index 0000000..4d55bc9
--- /dev/null
+++ b/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
@@ -0,0 +1,93 @@
+---
+name: testing-agentkit-tools
+description: Tests live Scalekit AgentKit flows by generating authorization links, fetching tool metadata, and executing a tool for a connected account. Use when a user wants to validate a connector, inspect the exact payload for execute_tool, or build a workflow step by step.
+---
+
+# Testing AgentKit Tools
+
+This skill is the live playground for AgentKit. Use it to:
+
+- generate an authorization link for a connection
+- fetch live tool metadata for a connector or tool name
+- execute a tool with real inputs
+- inspect the exact JSON payload sent to AgentKit
+
+## Prerequisites
+
+Confirm the environment variables are available:
+- `SCALEKIT_ENV_URL`
+- `SCALEKIT_CLIENT_ID`
+- `SCALEKIT_CLIENT_SECRET`
+
+## Operations
+
+### Generate authorization link
+
+Creates or fetches the connected account and prints an authorization link if the account is not yet `ACTIVE`.
+
+**Python**
+```python
+response = actions.get_or_create_connected_account(
+ connection_name="",
+ identifier=""
+)
+if response.connected_account.status != "ACTIVE":
+ link_response = actions.get_authorization_link(
+ connection_name="",
+ identifier=""
+ )
+ print("Authorize here:", link_response.link)
+```
+
+### Fetch tool metadata
+
+Fetches live tool metadata. Omitting `tool_name` returns all matching tools for the filter.
+
+**Python**
+```python
+tools = actions.get_tools(providers=["GMAIL"], page_size=100)
+for tool in tools:
+ print(tool.name, tool.input_schema)
+```
+
+**Node.js**
+```typescript
+const tools = await scalekitClient.connectedAccounts.getTools({
+ providers: ['GMAIL'],
+ pageSize: 100,
+});
+```
+
+### Execute a tool
+
+Creates or fetches the connected account, prints an authorization link if needed, and executes the tool.
+
+**Python**
+```python
+result = actions.execute_tool(
+ tool_name="gmail_fetch_mails",
+ connection_name="",
+ identifier="",
+ tool_input={"query": "is:unread", "max_results": 5}
+)
+```
+
+## Default workflow
+
+1. Discover the tool first when the schema is unknown.
+2. Generate an authorization link if the connected account is not `ACTIVE`.
+3. Execute the tool with the smallest valid `tool_input`.
+4. Show the exact command and payload used so the user can translate it into app code.
+
+## Guardrails
+
+- Treat live metadata as the source of truth for `input_schema` and `output_schema`.
+- Do not assume the dashboard `connection_name` matches the connector slug.
+- Ask for missing credentials instead of inventing placeholder values.
+- Keep the tool set constrained to the current workflow.
+
+## Deep reference
+
+- Integration workflow: [../integrating-agentkit/SKILL.md](../integrating-agentkit/SKILL.md)
+- Connector reference: [../../references/agent-connectors/README.md](../../references/agent-connectors/README.md)
+- Connected accounts: [../../references/connected-accounts.md](../../references/connected-accounts.md)
diff --git a/plugins/full-stack-auth/.codex-plugin/plugin.json b/plugins/full-stack-auth/.codex-plugin/plugin.json
deleted file mode 100644
index 31f3a15..0000000
--- a/plugins/full-stack-auth/.codex-plugin/plugin.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "full-stack-auth",
- "version": "1.4.0",
- "description": "Production-ready authentication flows using Scalekit full-stack auth across common stacks.",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com",
- "url": "https://scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/claude-code-authstack",
- "license": "MIT",
- "keywords": [
- "authentication",
- "oauth",
- "full-stack",
- "sessions"
- ],
- "skills": "./skills/",
- "mcpServers": "./.mcp.json",
- "interface": {
- "displayName": "Full-Stack Auth",
- "shortDescription": "Build complete app auth with Scalekit.",
- "longDescription": "Covers login, callback, cookie-backed sessions, token refresh, logout, protected routes, framework-specific implementations, migrations, and production-readiness for web applications using Scalekit.",
- "developerName": "Scalekit",
- "category": "Application Auth",
- "capabilities": [
- "Interactive",
- "Write"
- ],
- "websiteURL": "https://docs.scalekit.com",
- "privacyPolicyURL": "https://www.scalekit.com/privacy",
- "termsOfServiceURL": "https://www.scalekit.com/terms",
- "defaultPrompt": [
- "Add Scalekit full-stack auth to this app.",
- "Implement login, callback, and logout with Scalekit.",
- "Review my session refresh and logout flow."
- ],
- "brandColor": "#7C3AED"
- }
-}
diff --git a/plugins/full-stack-auth/README.md b/plugins/full-stack-auth/README.md
deleted file mode 100644
index 75db8f3..0000000
--- a/plugins/full-stack-auth/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Full-Stack Auth
-
-`full-stack-auth` is for complete application authentication with Scalekit: login, callback, session creation, refresh, logout, and protected routes. Use it when you want Codex to help wire auth end to end instead of only solving SSO or provisioning in isolation.
-
-## Use This Plugin When
-
-- you need full login and callback routes
-- you need session cookies or token refresh handling
-- you need logout flows and protected pages
-- you want a review of your auth lifecycle before going live
-
-## Primary Skill
-
-- `implementing-scalekit-fsa`
-
-## Additional Skills
-
-- `full-stack-auth`
-- `implementing-scalekit-nextjs-auth`
-- `implementing-scalekit-fastapi-auth`
-- `implementing-scalekit-flask-auth`
-- `implementing-scalekit-django-auth`
-- `implementing-scalekit-go-auth`
-- `implementing-scalekit-laravel-auth`
-- `implementing-scalekit-springboot-auth`
-- `implementing-access-control`
-- `manage-user-sessions`
-- `implement-logout`
-- `adding-oauth2-to-apis`
-- `adding-api-key-auth`
-- `implementing-admin-portal`
-- `migrating-to-scalekit-auth`
-- `production-readiness-scalekit`
-
-Try asking Codex:
-
-- `Add Scalekit full-stack auth to this app`
-- `Implement login, callback, and logout with Scalekit`
-- `Review my session refresh flow`
-
-## Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-
-The plugin also ships [`./.mcp.json`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/.mcp.json), which points at the remote Scalekit MCP server.
-
-## Reference Docs
-
-- Redirects: [`references/redirects.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/references/redirects.md)
-- Logs: [`references/scalekit-logs.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/references/scalekit-logs.md)
-- User profiles: [`references/scalekit-user-profiles.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/references/scalekit-user-profiles.md)
-- Migration checklist: [`skills/migrating-to-scalekit-auth/AUDIT-CHECKLIST.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/AUDIT-CHECKLIST.md)
-- Migration import samples: [`skills/migrating-to-scalekit-auth/IMPORT-SAMPLES.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/IMPORT-SAMPLES.md)
-
-## Troubleshooting
-
-- Callback URLs must exactly match the values registered in the Scalekit dashboard.
-- Use HttpOnly cookies for tokens or session state and keep refresh handling off the client when possible.
-- If login works but pages still act anonymous, inspect cookie scope, secure flags, and refresh fallback behavior.
diff --git a/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md b/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md
deleted file mode 100644
index 4ecedea..0000000
--- a/plugins/full-stack-auth/skills/adding-oauth2-to-apis/SKILL.md
+++ /dev/null
@@ -1,232 +0,0 @@
----
-name: adding-oauth2-to-apis
-description: >
- Implements OAuth 2.0 client-credentials authentication on API endpoints using
- Scalekit as the authorization server. Use when protecting APIs with
- machine-to-machine auth, registering API clients for organizations, issuing
- bearer tokens, validating JWTs via JWKS, or enforcing scopes in middleware.
----
-
-# Adding OAuth 2.0 to APIs (Scalekit)
-
-## Flow overview
-
-```
-Register client (your app) → Issue client_id + secret (Scalekit) →
-API client fetches bearer token → Your server validates JWT + scopes
-```
-
-Security-critical steps (token validation, scope enforcement) use **low freedom** — follow them exactly.
-
----
-
-## 1. Install
-
-```bash
-pip install scalekit-sdk-python
-# or
-npm install @scalekit-sdk/node
-```
-
-Initialize once and reuse:
-
-```python
-from scalekit import ScalekitClient
-import os
-
-scalekit_client = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
- client_id=os.getenv("SCALEKIT_CLIENT_ID"),
- client_secret=os.getenv("SCALEKIT_CLIENT_SECRET")
-)
-```
-
-Required env vars: `SCALEKIT_ENVIRONMENT_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`.
-
----
-
-## 2. Register an API client for an organization
-
-One organization can have multiple API clients. Registration returns `client_id` and `plain_secret` — **`plain_secret` is shown only once; never stored by Scalekit**.
-
-```python
-from scalekit.v1.clients.clients_pb2 import OrganizationClient
-
-response = scalekit_client.m2m_client.create_organization_client(
- organization_id="",
- m2m_client=OrganizationClient(
- name="GitHub Actions Deployment Service",
- description="Deploys to production via GitHub Actions",
- scopes=["deploy:applications", "read:deployments"], # resource:action pattern
- audience=["deployment-api.acmecorp.com"],
- custom_claims=[
- {"key": "github_repository", "value": "acmecorp/inventory-service"},
- {"key": "environment", "value": "production_us"}
- ],
- expiry=3600 # seconds; default 3600
- )
-)
-
-client_id = response.client.client_id
-plain_secret = response.plain_secret # store this securely; not retrievable again
-```
-
-**cURL equivalent** (if not using SDK):
-
-```bash
-curl -X POST "$SCALEKIT_ENVIRONMENT_URL/api/v1/organizations//clients" \
- -H "Content-Type: application/json" \
- -H "Authorization: Bearer " \
- -d '{
- "name": "GitHub Actions Deployment Service",
- "scopes": ["deploy:applications", "read:deployments"],
- "audience": ["deployment-api.acmecorp.com"],
- "expiry": 3600
- }'
-```
-
-> Scope naming convention: use `resource:action` (e.g. `deployments:read`, `applications:create`).
-
----
-
-## 3. API client fetches a bearer token
-
-This step runs inside the **API client's** code, not your server. Shown here for reference.
-
-```bash
-curl -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
- -H "Content-Type: application/x-www-form-urlencoded" \
- -d "grant_type=client_credentials" \
- -d "client_id=" \
- -d "client_secret="
-```
-
-Response:
-
-```json
-{
- "access_token": "",
- "token_type": "Bearer",
- "expires_in": 86399,
- "scope": "deploy:applications read:deployments"
-}
-```
-
-The client sends this JWT in `Authorization: Bearer ` on every API request.
-
----
-
-## 4. Validate the JWT on your API server
-
-**Do this on EVERY request. Never trust unverified tokens.**
-
-### Python (SDK handles JWKS automatically)
-
-```python
-token = request.headers.get("Authorization", "").removeprefix("Bearer ")
-
-try:
- claims = scalekit_client.validate_access_token_and_get_claims(token=token)
- # claims["scopes"] → list of granted scopes
-except Exception:
- return 401 # invalid or expired
-```
-
-### Node.js (manual JWKS + JWT verify)
-
-```js
-import jwksClient from 'jwks-rsa';
-import jwt from 'jsonwebtoken';
-
-const jwks = jwksClient({
- jwksUri: `${process.env.SCALEKIT_ENVIRONMENT_URL}/.well-known/jwks.json`,
- cache: true
-});
-
-async function verifyToken(token) {
- const decoded = jwt.decode(token, { complete: true });
- const key = await jwks.getSigningKey(decoded.header.kid);
- return jwt.verify(token, key.getPublicKey(), {
- algorithms: ['RS256'],
- complete: true
- }).payload; // contains scopes, sub, iss, exp, oid, etc.
-}
-```
-
-Decoded JWT payload structure:
-
-```json
-{
- "client_id": "m2morg_69038819013296423",
- "oid": "org_59615193906282635",
- "scopes": ["deploy:applications", "read:deployments"],
- "iss": "",
- "exp": 1745305340
-}
-```
-
----
-
-## 5. Enforce scopes in middleware
-
-### Flask (Python)
-
-```python
-import functools
-from flask import request, jsonify
-
-def require_scope(scope):
- def decorator(f):
- @functools.wraps(f)
- def wrapper(*args, **kwargs):
- token = request.headers.get("Authorization", "").removeprefix("Bearer ")
- if not token:
- return jsonify({"error": "Missing token"}), 401
- try:
- claims = scalekit_client.validate_access_token_and_get_claims(token=token)
- except Exception:
- return jsonify({"error": "Invalid token"}), 401
- if scope not in claims.get("scopes", []):
- return jsonify({"error": "Insufficient permissions"}), 403
- return f(*args, **kwargs)
- return wrapper
- return decorator
-
-# Usage:
-# @app.route('/deploy', methods=['POST'])
-# @require_scope('deploy:applications')
-# def deploy(): ...
-```
-
-### Express (Node.js)
-
-```js
-function requireScope(scope) {
- return async (req, res, next) => {
- const token = (req.headers.authorization || '').replace('Bearer ', '');
- if (!token) return res.status(401).send('Missing token');
- try {
- const payload = await verifyToken(token); // from step 4
- if (!payload.scopes?.includes(scope))
- return res.status(403).send('Insufficient permissions');
- req.tokenClaims = payload;
- next();
- } catch {
- res.status(401).send('Invalid token');
- }
- };
-}
-
-// Usage:
-// app.post('/deploy', requireScope('deploy:applications'), handler);
-```
-
----
-
-## Key rules
-
-- `plain_secret` is **returned once only** — instruct customers to store it immediately.
-- Always validate tokens **server-side** before trusting claims.
-- Cache JWKS keys (avoid fetching on every request); rotate on `kid` mismatch.
-- Use `resource:action` scope naming for clarity.
-- An `organization_id` maps to one customer; multiple API clients per org are supported.
diff --git a/plugins/full-stack-auth/skills/implement-logout/SKILL.md b/plugins/full-stack-auth/skills/implement-logout/SKILL.md
deleted file mode 100644
index 47e76ef..0000000
--- a/plugins/full-stack-auth/skills/implement-logout/SKILL.md
+++ /dev/null
@@ -1,187 +0,0 @@
----
-name: implementing-fsa-logout
-description: Implements a complete logout flow for Scalekit FSA integrations by clearing application session cookies and redirecting the browser to Scalekit’s /oidc/logout endpoint to invalidate the Scalekit session. Use when adding or fixing logout in Node.js, Python, Go, or Java web apps that use Scalekit OIDC.
----
-
-# Implementing logout (Scalekit FSA)
-
-## Goal
-Implement a single `/logout` endpoint that:
-- Clears the application session layer (your cookies/tokens).
-- Invalidates the Scalekit session layer by redirecting the browser to Scalekit’s OIDC logout endpoint.
-- Returns the user to a safe, allowlisted post-logout redirect URL.
-
-## Key constraints (must follow)
-- The Scalekit logout call MUST be a browser redirect (top-level navigation), not a `fetch`/XHR from frontend and not a server-to-server API call.
-- The ID token (often `idToken`) MUST be read BEFORE clearing cookies, because it is used as `id_token_hint`.
-- The `post_logout_redirect_uri` MUST be allowlisted in Scalekit Dashboard (Post Logout URLs).
-
-## Inputs to collect from the user/project
-Ask for (or infer from the codebase):
-- Tech stack: Express/Fastify/Next.js (Node), Flask/Django (Python), Gin/Fiber (Go), Spring Boot (Java), etc.
-- Where tokens are stored: cookie names (default examples: `accessToken`, `refreshToken`, `idToken`) and cookie attributes (Path, Domain, SameSite).
-- The post-logout landing URL (example: `http://localhost:3000/login` or your production login page).
-- Scalekit configuration: base URL / environment, and whether the project uses a Scalekit SDK helper like `getLogoutUrl(...)`.
-
-## Recommended implementation (workflow)
-1. Locate the current auth/session code:
-- Find where access/refresh/ID tokens are set.
-- Note cookie names, paths, domains, and SameSite settings (you must match these when clearing).
-
-2. Add a GET `/logout` route:
-- Extract `idToken` (or equivalent) from cookies/session storage.
-- Compute `postLogoutRedirectUri`.
-- Build the Scalekit logout URL pointing at `/oidc/logout`, preferably using the Scalekit SDK helper if present.
-- Clear session cookies (access/refresh/id), preserving the correct Path/Domain so deletion actually works.
-- Redirect (302) the browser to the Scalekit logout URL.
-
-3. Configure Scalekit Dashboard allowlist:
-- Register `postLogoutRedirectUri` under: Redirects → Post Logout URL.
-
-4. Verify and iterate:
-- In DevTools → Network, clicking logout should show a **document** navigation to Scalekit (not XHR/fetch).
-- Confirm the request includes the Scalekit session cookie automatically.
-- After redirecting back, logging in should not silently reuse the application cookies you intended to clear.
-
-## Reference behavior (pseudocode)
-- Read `id_token_hint` from cookie/session.
-- `logoutUrl = scalekit.getLogoutUrl(id_token_hint, post_logout_redirect_uri)`
-- Clear cookies (access/refresh/id).
-- `302 -> logoutUrl`
-
-## Implementation templates
-
-### Node.js (Express)
-```js
-app.get('/logout', (req, res) => {
- const idTokenHint = req.cookies?.idToken; // read BEFORE clearing
- const postLogoutRedirectUri = process.env.POST_LOGOUT_REDIRECT_URI ?? 'http://localhost:3000/login';
-
- // Prefer SDK helper if available in your project
- const logoutUrl = scalekit.getLogoutUrl(idTokenHint, postLogoutRedirectUri);
-
- // Clear cookies (match Path/Domain/SameSite used when setting them)
- res.clearCookie('accessToken', { path: '/' });
- res.clearCookie('refreshToken', { path: '/' });
- res.clearCookie('idToken', { path: '/' });
-
- return res.redirect(logoutUrl);
-});
-```
-
-### Python (Flask)
-```py
-from flask import request, redirect, make_response
-
-@app.get("/logout")
-def logout():
- id_token = request.cookies.get("idToken") # read BEFORE clearing
- post_logout_redirect_uri = os.getenv("POST_LOGOUT_REDIRECT_URI", "http://localhost:3000/login")
-
- logout_url = scalekit_client.get_logout_url(
- id_token_hint=id_token,
- post_logout_redirect_uri=post_logout_redirect_uri
- )
-
- resp = make_response(redirect(logout_url))
- resp.set_cookie("accessToken", "", max_age=0, path="/")
- resp.set_cookie("refreshToken", "", max_age=0, path="/")
- resp.set_cookie("idToken", "", max_age=0, path="/")
- return resp
-```
-
-### Go (Gin)
-```go
-func LogoutHandler(c *gin.Context) {
- idToken, _ := c.Cookie("idToken") // read BEFORE clearing
- postLogoutRedirectURI := os.Getenv("POST_LOGOUT_REDIRECT_URI")
- if postLogoutRedirectURI == "" {
- postLogoutRedirectURI = "http://localhost:3000/login"
- }
-
- logoutURL, err := scalekit.GetLogoutUrl(scalekit.LogoutUrlOptions{
- IdTokenHint: idToken,
- PostLogoutRedirectUri: postLogoutRedirectURI,
- })
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
- return
- }
-
- // Clear cookies (match original attributes)
- c.SetCookie("accessToken", "", -1, "/", "", true, true)
- c.SetCookie("refreshToken", "", -1, "/", "", true, true)
- c.SetCookie("idToken", "", -1, "/", "", true, true)
-
- c.Redirect(http.StatusFound, logoutURL.String())
-}
-```
-
-### Java (Spring Boot)
-```java
-@GetMapping("/logout")
-public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
- String idToken = null;
- if (request.getCookies() != null) {
- for (Cookie c : request.getCookies()) {
- if ("idToken".equals(c.getName())) {
- idToken = c.getValue();
- break;
- }
- }
- }
-
- String postLogoutRedirectUri = System.getenv().getOrDefault(
- "POST_LOGOUT_REDIRECT_URI",
- "http://localhost:3000/login"
- );
-
- URL logoutUrl = scalekitClient.authentication().getLogoutUrl(
- idToken,
- postLogoutRedirectUri
- );
-
- // Clear cookies (ensure Path/Domain match your app cookies)
- Cookie access = new Cookie("accessToken", "");
- access.setMaxAge(0);
- access.setPath("/");
- access.setHttpOnly(true);
- access.setSecure(true);
- response.addCookie(access);
-
- Cookie refresh = new Cookie("refreshToken", "");
- refresh.setMaxAge(0);
- refresh.setPath("/");
- refresh.setHttpOnly(true);
- refresh.setSecure(true);
- response.addCookie(refresh);
-
- Cookie id = new Cookie("idToken", "");
- id.setMaxAge(0);
- id.setPath("/");
- id.setHttpOnly(true);
- id.setSecure(true);
- response.addCookie(id);
-
- response.sendRedirect(logoutUrl.toString());
-}
-```
-
-## Logout security checklist (copy/paste)
-- Extract ID token BEFORE clearing cookies.
-- Clear all application session cookies (access/refresh/id).
-- Redirect browser (302) to Scalekit `/oidc/logout` via the generated logout URL.
-- Ensure `post_logout_redirect_uri` is allowlisted in Scalekit dashboard.
-- Validate logout is a document navigation (not XHR/fetch) and cookies are actually removed.
-
-## Common failure modes (what to check)
-- “Logout doesn’t really log out”: cookie deletion mismatches Path/Domain/SameSite; clear cookies with the same attributes used when setting them.
-- “Login immediately succeeds after logout”: identity provider session may still be active; this is expected for SSO providers, but your app cookies should still be cleared.
-- “Scalekit logout doesn’t take effect”: logout was done via API call rather than browser redirect; use a redirect so the Scalekit session cookie is included automatically.
-- “Redirect rejected”: `post_logout_redirect_uri` is not allowlisted in Scalekit dashboard.
-
-## Output expectations when using this skill
-When asked to implement logout in a real repo, the assistant should:
-- Identify the correct cookie names and where they are set.
-- Implement `/logout` with the correct sequence (read id token → build logout URL → clear cookies → redirect).
-- Provide a brief test plan and the exact dashboard value to allowlist for post-logout redirect.
diff --git a/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md b/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index cf0d039..0000000
--- a/plugins/full-stack-auth/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-name: implementing-admin-portal
-description: 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.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SSO_CONFIGURED':
- // Refresh org status, show success banner, etc.
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SSO configuration inside the portal — confirm `SSO_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `sso.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SSO setup guides](https://docs.scalekit.com/guides/integrations/sso-integrations/) so the IT admin has provider-specific configuration steps alongside the portal link.
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-fsa/SKILL.md b/plugins/full-stack-auth/skills/implementing-scalekit-fsa/SKILL.md
deleted file mode 100644
index 1c531b9..0000000
--- a/plugins/full-stack-auth/skills/implementing-scalekit-fsa/SKILL.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-name: implementing-scalekit-fsa
-description: Implements Scalekit full-stack authentication including login, callback, logout, secure session storage, and refresh-token handling. Use when building end-to-end authentication for a web application with Scalekit.
----
-
-# Scalekit Full-Stack Authentication
-
-Use this skill when you want a complete application auth flow rather than a single enterprise SSO or provisioning feature.
-
-## Required Configuration
-
-```text
-SCALEKIT_ENVIRONMENT_URL=
-SCALEKIT_CLIENT_ID=
-SCALEKIT_CLIENT_SECRET=
-```
-
-## Core Flow
-
-1. Generate an authorization URL and redirect the user to Scalekit.
-2. Exchange the callback code for tokens.
-3. Store session state in secure server-controlled cookies.
-4. Refresh access tokens when needed.
-5. Clear local session state and redirect to the Scalekit logout URL.
-
-## Node.js Sketch
-
-```ts
-const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, {
- scopes: ['openid', 'profile', 'email', 'offline_access'],
-});
-
-res.redirect(authorizationUrl);
-```
-
-```ts
-const { user, idToken, accessToken, refreshToken } =
- await scalekit.authenticateWithCode(code, redirectUri);
-```
-
-```ts
-res.cookie('accessToken', accessToken, {
- httpOnly: true,
- secure: true,
- sameSite: 'strict',
- path: '/api',
-});
-```
-
-## Implementation Checklist
-
-```text
-Full-Stack Auth:
-- [ ] Generate login URL
-- [ ] Implement callback exchange
-- [ ] Create secure session storage
-- [ ] Add refresh-token fallback
-- [ ] Add logout route
-- [ ] Protect server-rendered and API routes
-```
-
-## Review Guidance
-
-- Callback URLs must exactly match the values configured in the dashboard.
-- Prefer HttpOnly cookies and server-side refresh logic over exposing tokens to the browser runtime.
-- Validate access tokens first, then fall back to refresh using the refresh token.
-- If refresh fails, clear local session state and require a new login.
-
-## Cross-Language Note
-
-Scalekit keeps the same auth lifecycle across SDKs even though method names vary slightly:
-
-- authorization URL generation
-- code exchange
-- token validation
-- token refresh
-- logout URL generation
-
-Use the framework and cookie abstractions already present in the target app rather than creating a parallel auth subsystem.
diff --git a/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index 8ab1a0a..0000000
--- a/plugins/full-stack-auth/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,159 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, hardening their auth setup, or wants to verify their Scalekit implementation is production-ready.
----
-
-# Scalekit Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones. Skip sections that don't apply to this implementation.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-- [ ] Only enabled auth methods are active in production
-
----
-
-## Customization
-
-- [ ] Login page branded with logo, colors, styling
-- [ ] Email templates customized (sign-up, password reset, invitations)
-- [ ] Custom domain configured for auth pages (if applicable)
-- [ ] Email provider configured in **Dashboard > Customization > Emails**
-- [ ] Email deliverability tested — check spam folders
-- [ ] Webhooks configured with signature validation
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Configure token lifetimes for your security requirements
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-
-**Test each enabled auth method:**
-- [ ] Email/password: sign-up, login, password reset
-- [ ] Magic links: initiation, delivery, redemption, expiry
-- [ ] Social logins: each configured provider (Google, Microsoft, GitHub, etc.)
- → Provider setup guides: https://docs.scalekit.com/guides/integrations/social-connections/
-- [ ] Passkeys: registration, authentication, fallback
-- [ ] Auth method selection UI renders correctly
-- [ ] Fallback scenarios when an auth method fails
-
-**Error handling:**
-- [ ] Expired tokens handled gracefully
-- [ ] Invalid authorization codes rejected
-- [ ] Network failures show user-friendly messages
-- [ ] Complete end-to-end flow validated in staging before production
-
----
-
-## Enterprise auth (if enterprise customers at launch)
-
-**SSO:**
-- [ ] Test SSO with target IdPs: Okta, Azure AD, Google Workspace
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/sso-integrations/
-- [ ] Configure user attribute mapping (email, name, groups)
-- [ ] Test both SP-initiated and IdP-initiated SSO flows
-- [ ] Verify SSO error handling for misconfigured connections
-- [ ] Test SSO with: new users, existing users, deactivated users
-
-**JIT provisioning:**
-- [ ] Register all organization domains for JIT provisioning
-- [ ] Configure consistent user identifiers across SSO connections (email or userPrincipalName)
-- [ ] Set default roles for JIT-provisioned users
-- [ ] Enable "Sync user attributes during login"
-- [ ] Plan manual invitation process for contractors/external users with non-matching domains
-
-**SCIM provisioning:**
-- [ ] Configure webhook endpoints to receive SCIM events
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/scim-integrations/
-- [ ] Verify webhook security with signature validation
-- [ ] Test user provisioning (automatic creation)
-- [ ] Test user deprovisioning (deactivation/deletion)
-- [ ] Test user profile updates and role changes
-- [ ] Set up group-based role assignment and sync
-- [ ] Test error cases: duplicate users, invalid data
-
-**Admin portal:**
-- [ ] Configure admin portal access for enterprise customers
-- [ ] Test admin portal SSO configuration flows
-- [ ] Verify user management features in admin portal
-
-**Network/firewall — enterprise customers behind VPN must whitelist:**
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Auth + admin portal |
-| `cdn.scalekit.com` | Static assets |
-| `fonts.googleapis.com` | Font resources |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SSO tested from customer's network environment
-
----
-
-## User and organization management (if implemented)
-
-**User flows:**
-- [ ] Configure profile fields collected at sign-up
-- [ ] Test invitation flow and email templates
-- [ ] Test user deletion flow
-
-**Organization flows:**
-- [ ] Test organization creation
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org sign-ups (if applicable)
-- [ ] Verify organization switching for users in multiple orgs
-- [ ] Test organization deletion flow
-
-**RBAC (if implemented):**
-- [ ] Define and create roles and permissions
-- [ ] Set default roles for new users
-- [ ] Test role assignment to users and org members
-- [ ] Verify permission checks in application code
-- [ ] Test access control across all role levels
-- [ ] Validate permission enforcement at API endpoints
-
----
-
-## MCP authentication (if implemented)
-
-- [ ] Test MCP server authentication flow
-- [ ] Verify OAuth consent screen for MCP clients
-- [ ] Test token exchange for MCP connections
-- [ ] Verify custom auth handlers (if using)
-- [ ] Test MCP session management
-
----
-
-## Monitoring and incident readiness
-
-**Observability:**
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (multiple failed logins, unusual locations)
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for authentication failures
-
-**Key metrics to track from day one:**
-- Sign-up rate and conversion
-- Login success/failure rates
-- Session creation and duration
-- Token refresh frequency
-- Webhook delivery success rate
-
-**Reliability:**
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back, escalation path)
-- [ ] Rollback plan ready (feature flag to disable new auth flows if needed)
diff --git a/plugins/mcp-auth/.codex-plugin/plugin.json b/plugins/mcp-auth/.codex-plugin/plugin.json
deleted file mode 100644
index 233ba3e..0000000
--- a/plugins/mcp-auth/.codex-plugin/plugin.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "name": "mcp-auth",
- "version": "1.3.0",
- "description": "Guides teams through adding OAuth 2.1 authorization to MCP servers with Scalekit.",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com",
- "url": "https://scalekit.com"
- },
- "homepage": "https://docs.scalekit.com/authenticate/mcp/start-mcp-auth-coding-agents",
- "repository": "https://github.com/scalekit-inc/claude-code-authstack",
- "license": "MIT",
- "keywords": [
- "oauth",
- "mcp",
- "authentication",
- "scalekit"
- ],
- "skills": "./skills/",
- "mcpServers": "./.mcp.json",
- "interface": {
- "displayName": "MCP Auth",
- "shortDescription": "Add OAuth 2.1 protection to MCP servers.",
- "longDescription": "Production-oriented guidance for securing MCP servers with Scalekit, including protected-resource metadata, token validation, and host testing.",
- "developerName": "Scalekit",
- "category": "MCP Security",
- "capabilities": [
- "Interactive",
- "Write"
- ],
- "websiteURL": "https://docs.scalekit.com/authenticate/mcp/start-mcp-auth-coding-agents",
- "privacyPolicyURL": "https://www.scalekit.com/privacy",
- "termsOfServiceURL": "https://www.scalekit.com/terms",
- "defaultPrompt": [
- "Add Scalekit OAuth 2.1 auth to this MCP server.",
- "Review this MCP auth flow for missing security steps.",
- "Set up protected-resource metadata for my MCP server."
- ],
- "brandColor": "#0F766E"
- }
-}
diff --git a/plugins/mcp-auth/.mcp.json b/plugins/mcp-auth/.mcp.json
deleted file mode 100644
index ffaff7a..0000000
--- a/plugins/mcp-auth/.mcp.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": [
- "-y",
- "mcp-remote",
- "https://mcp.scalekit.com"
- ]
- }
- }
-}
diff --git a/plugins/mcp-auth/README.md b/plugins/mcp-auth/README.md
deleted file mode 100644
index 494fde3..0000000
--- a/plugins/mcp-auth/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# MCP Auth
-
-`mcp-auth` helps Codex add OAuth 2.1 authorization to MCP servers using Scalekit. It is the plugin to use when you need protected tools for Claude Desktop, Cursor, VS Code, or any other MCP host that expects standards-based auth.
-
-## Use This Plugin When
-
-- your MCP server needs OAuth 2.1 protection
-- you need `/.well-known/oauth-protected-resource`
-- you need token validation middleware with Scalekit
-- you want a review of an existing MCP auth flow before launch
-
-## Primary Skill
-
-- `adding-mcp-oauth`
-
-## Additional Skills
-
-- `mcp-auth`
-- `mcp-oauth-fastmcp`
-- `express-mcp-server`
-- `fastapi-fastmcp`
-- `production-readiness-scalekit`
-
-Try asking Codex:
-
-- `Add Scalekit OAuth 2.1 auth to this MCP server`
-- `Implement protected-resource metadata for my MCP server`
-- `Review this MCP auth integration for missing security steps`
-
-## Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-
-The plugin also ships [`./.mcp.json`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/mcp-auth/.mcp.json), which points at the remote Scalekit MCP server.
-
-## Reference Docs
-
-- [`references/scalekit-mcp-server.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/mcp-auth/references/scalekit-mcp-server.md)
-- [`references/bring-your-own-auth.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/mcp-auth/references/bring-your-own-auth.md)
-- [`references/redirects.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/mcp-auth/references/redirects.md)
-
-## Troubleshooting
-
-- OAuth-capable MCP auth requires HTTP transport, not stdio transport.
-- Missing or invalid bearer tokens should return `401` plus a `WWW-Authenticate` header that points hosts at your protected-resource metadata.
-- Keep dashboard resource settings and your metadata endpoint aligned before debugging token validation.
diff --git a/plugins/mcp-auth/references/redirects.md b/plugins/mcp-auth/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/mcp-auth/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/mcp-auth/skills/adding-mcp-oauth/SKILL.md b/plugins/mcp-auth/skills/adding-mcp-oauth/SKILL.md
deleted file mode 100644
index f87a6a2..0000000
--- a/plugins/mcp-auth/skills/adding-mcp-oauth/SKILL.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-name: adding-mcp-oauth
-description: Guides users through adding OAuth 2.1 authorization to Model Context Protocol servers using Scalekit. Use when the user mentions MCP security, OAuth, protected-resource metadata, MCP hosts like Claude Desktop or Cursor, or a need to secure tools exposed over HTTP.
----
-
-# Adding OAuth 2.1 Authorization To MCP Servers
-
-Use this skill when an MCP server needs standards-based authorization for AI hosts.
-
-## Critical Prerequisite
-
-OAuth-capable MCP auth requires HTTP-based transport. A stdio-only MCP server cannot complete the browser and callback flows needed for OAuth 2.1.
-
-- Node.js: use `StreamableHTTPServerTransport`
-- Python: expose an ASGI app with streamable HTTP support
-- Keep your well-known metadata reachable over HTTPS
-
-## Required Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-
-Get these from the Scalekit dashboard after registering the MCP server.
-
-## Working Checklist
-
-```text
-MCP OAuth Setup:
-- [ ] Install Scalekit SDK
-- [ ] Register the MCP server in Scalekit
-- [ ] Publish /.well-known/oauth-protected-resource
-- [ ] Add token validation middleware
-- [ ] Test from an MCP host
-```
-
-## Recommended Flow
-
-1. Confirm the server is already using HTTP transport.
-2. Register the MCP server in Scalekit and enable the features needed for host registration.
-3. Add `/.well-known/oauth-protected-resource` with the authorization server metadata from Scalekit.
-4. Add bearer-token extraction and validation on MCP routes, while leaving well-known endpoints public.
-5. Return `401` with a `WWW-Authenticate` header that points to the protected-resource metadata whenever auth is missing or invalid.
-6. Test from the real host integration instead of only with raw curl requests.
-
-## Node.js Pattern
-
-```ts
-import { Scalekit } from '@scalekit-sdk/node';
-
-const scalekit = new Scalekit(
- process.env.SCALEKIT_ENVIRONMENT_URL!,
- process.env.SCALEKIT_CLIENT_ID!,
- process.env.SCALEKIT_CLIENT_SECRET!
-);
-
-const RESOURCE_ID = 'https://mcp.yourapp.com';
-const METADATA_ENDPOINT =
- 'https://mcp.yourapp.com/.well-known/oauth-protected-resource';
-
-export async function authMiddleware(req, res, next) {
- if (req.path.includes('.well-known')) return next();
-
- const authHeader = req.headers.authorization;
- const token = authHeader?.startsWith('Bearer ')
- ? authHeader.slice('Bearer '.length).trim()
- : null;
-
- if (!token) {
- return res
- .status(401)
- .set(
- 'WWW-Authenticate',
- `Bearer realm="OAuth", resource_metadata="${METADATA_ENDPOINT}"`
- )
- .end();
- }
-
- await scalekit.validateToken(token, { audience: [RESOURCE_ID] });
- next();
-}
-```
-
-## Python Pattern
-
-```python
-from scalekit import ScalekitClient
-import os
-
-client = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
- client_id=os.getenv("SCALEKIT_CLIENT_ID"),
- client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
-)
-
-RESOURCE_ID = "https://mcp.yourapp.com"
-
-async def verify_token(token: str):
- return client.validate_access_token(token, {"audience": [RESOURCE_ID]})
-```
-
-## Protected-Resource Metadata
-
-Your metadata endpoint should include:
-
-- `authorization_servers`
-- `bearer_methods_supported`
-- `resource`
-- `resource_documentation`
-- `scopes_supported`
-
-Source these values from the Scalekit dashboard for the registered MCP resource instead of inventing them manually.
-
-## Guardrails
-
-- Never implement OAuth on top of stdio transport and expect hosts to make it work.
-- Keep the resource identifier used in token validation aligned with the resource metadata you publish.
-- Treat missing tokens, expired tokens, and wrong audiences as host-facing auth errors with actionable responses.
diff --git a/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md b/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index c3e4583..0000000
--- a/plugins/mcp-auth/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-name: production-readiness-scalekit
-description: Walks through a structured production readiness checklist for Scalekit MCP authentication implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their MCP server authentication is production-ready.
----
-
-# Scalekit MCP Auth Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Configure token lifetimes for your security requirements
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-- [ ] Expired tokens handled gracefully
-- [ ] Network failures show user-friendly messages
-
----
-
-## MCP authentication
-
-- [ ] Test MCP server authentication flow end-to-end
-- [ ] Verify OAuth consent screen displays correctly for MCP clients
-- [ ] Test token exchange for MCP connections
-- [ ] Verify resource metadata published at `/.well-known/oauth-protected-resource`
-- [ ] Test MCP session management (session creation, expiry, refresh)
-- [ ] Verify custom auth handlers behave correctly (if using)
-- [ ] Test MCP client reconnection after token expiry
-- [ ] Verify scopes are correctly enforced per MCP tool/resource
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (repeated auth failures, unusual access patterns)
-- [ ] Error tracking configured for authentication failures
-- [ ] Log retention policies configured
-- [ ] Incident response runbook written (who to contact, how to roll back)
-- [ ] Rollback plan ready (disable MCP auth without breaking existing sessions)
-
-**Key metrics:**
-- MCP auth success/failure rates
-- Token exchange latency
-- Session creation and duration
-- Token refresh frequency
diff --git a/plugins/modular-scim/.codex-plugin/plugin.json b/plugins/modular-scim/.codex-plugin/plugin.json
deleted file mode 100644
index 98b5e32..0000000
--- a/plugins/modular-scim/.codex-plugin/plugin.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "modular-scim",
- "version": "1.2.0",
- "description": "Guides teams through SCIM provisioning with Scalekit using the Directory API and webhooks.",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com",
- "url": "https://scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/claude-code-authstack",
- "license": "MIT",
- "keywords": [
- "scim",
- "provisioning",
- "webhooks",
- "users",
- "groups"
- ],
- "skills": "./skills/",
- "mcpServers": "./.mcp.json",
- "interface": {
- "displayName": "Modular SCIM",
- "shortDescription": "Add provisioning and lifecycle sync with Scalekit.",
- "longDescription": "Covers SCIM-style provisioning workflows with Scalekit Directory API sync, webhook handling, admin portal setup, production-readiness checks, event mapping, and operational guardrails.",
- "developerName": "Scalekit",
- "category": "Provisioning",
- "capabilities": [
- "Interactive",
- "Write"
- ],
- "websiteURL": "https://docs.scalekit.com",
- "privacyPolicyURL": "https://www.scalekit.com/privacy",
- "termsOfServiceURL": "https://www.scalekit.com/terms",
- "defaultPrompt": [
- "Add Scalekit SCIM provisioning to this app.",
- "Implement a Scalekit webhook endpoint for directory sync.",
- "Review my user provisioning and deprovisioning flow."
- ],
- "brandColor": "#BE123C"
- }
-}
diff --git a/plugins/modular-scim/.mcp.json b/plugins/modular-scim/.mcp.json
deleted file mode 100644
index 36dbbf4..0000000
--- a/plugins/modular-scim/.mcp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
- }
- }
-}
diff --git a/plugins/modular-scim/README.md b/plugins/modular-scim/README.md
deleted file mode 100644
index a83a7fc..0000000
--- a/plugins/modular-scim/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Modular SCIM
-
-`modular-scim` helps Codex add provisioning and deprovisioning with Scalekit Directory APIs and webhooks. It is for products that want user lifecycle sync without rewriting their existing application user model.
-
-## Use This Plugin When
-
-- you need SCIM-style user provisioning
-- you need directory user and group sync
-- you need a webhook endpoint for lifecycle events
-- you want to review event mapping and idempotency
-
-## Primary Skill
-
-- `implementing-scim-provisioning`
-
-## Additional Skills
-
-- `modular-scim`
-- `implementing-admin-portal`
-- `production-readiness-scalekit`
-
-Try asking Codex:
-
-- `Add Scalekit SCIM provisioning to this app`
-- `Implement a Scalekit webhook endpoint for directory sync`
-- `Review my user deprovisioning flow`
-
-## Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-- `SCALEKIT_WEBHOOK_SECRET`
-
-The plugin also ships [`./.mcp.json`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/modular-scim/.mcp.json), which points at the remote Scalekit MCP server.
-
-## Reference Docs
-
-- [`references/redirects.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/modular-scim/references/redirects.md)
-
-## Troubleshooting
-
-- Always verify webhook signatures before processing payloads.
-- Prefer idempotent upsert and deactivate operations to avoid duplicate-event surprises.
-- Keep webhook processing lightweight and move slow work to background jobs if delivery retries start piling up.
diff --git a/plugins/modular-scim/references/redirects.md b/plugins/modular-scim/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/modular-scim/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md b/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index a12fb3a..0000000
--- a/plugins/modular-scim/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-name: implementing-admin-portal
-description: 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 SCIM setup, iframe embed for directory sync config, shareable setup link, or let customers configure their own SSO or SCIM connection.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SCIM_CONFIGURED':
- // Refresh org SCIM status, show success banner, etc.
- break;
- case 'SSO_CONFIGURED':
- // Refresh org SSO status if SSO is also in scope
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SCIM configuration inside the portal — confirm `SCIM_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `scim.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SCIM setup guides](https://docs.scalekit.com/guides/integrations/scim-integrations/) so the IT admin has provider-specific directory sync steps alongside the portal link.
diff --git a/plugins/modular-scim/skills/implementing-scim-provisioning/SKILL.md b/plugins/modular-scim/skills/implementing-scim-provisioning/SKILL.md
deleted file mode 100644
index 12bb50a..0000000
--- a/plugins/modular-scim/skills/implementing-scim-provisioning/SKILL.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-name: implementing-scim-provisioning
-description: Implements Scalekit provisioning using the Directory API and webhook events. Use when the user needs user lifecycle sync, SCIM-style provisioning, deprovisioning, or directory-backed group management.
----
-
-# SCIM Provisioning With Scalekit
-
-Use this skill when the application needs automated user lifecycle management without replacing its local data model.
-
-## Required Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-- `SCALEKIT_WEBHOOK_SECRET`
-
-## Working Checklist
-
-```text
-SCIM Provisioning:
-- [ ] Install and initialize the Scalekit SDK
-- [ ] Add Directory API sync
-- [ ] Add a webhook endpoint
-- [ ] Verify webhook signatures
-- [ ] Map directory events to local user operations
-- [ ] Test create, update, and deactivate flows
-```
-
-## Node.js Sketch
-
-```ts
-const directory = await scalekit.directory.getPrimaryDirectoryByOrganizationId(
- orgId
-);
-const { users } = await scalekit.directory.listDirectoryUsers(orgId, directory.id);
-
-for (const user of users) {
- await upsertUser({ email: user.email, name: user.name, orgId });
-}
-```
-
-```ts
-app.post('/webhooks/scalekit', async (req, res) => {
- try {
- await scalekit.verifyWebhookPayload(
- process.env.SCALEKIT_WEBHOOK_SECRET,
- req.headers,
- req.body
- );
- } catch {
- return res.status(400).json({ error: 'Invalid signature' });
- }
-
- await handleDirectoryEvent(req.body.type, req.body.data);
- res.status(201).json({ status: 'processed' });
-});
-```
-
-## Event Mapping Guidance
-
-Map incoming events to the app's existing user and group operations:
-
-- `organization.directory.user_created` -> create or upsert the user
-- `organization.directory.user_updated` -> update the local record
-- `organization.directory.user_deleted` -> prefer deactivation over hard deletion
-- group events -> sync roles, memberships, or permissions
-
-## Operational Guardrails
-
-- Verify webhook signatures before touching application state.
-- Keep handlers idempotent because webhook retries happen.
-- Return success quickly and move slow downstream work to a queue if needed.
-- Reuse the application's existing user-management functions instead of creating a parallel lifecycle path.
diff --git a/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md b/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index dca5b5f..0000000
--- a/plugins/modular-scim/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-name: production-readiness-scalekit
-description: 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.
----
-
-# Scalekit SCIM Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all endpoints
-- [ ] API credentials stored in environment variables — never committed to code
-- [ ] Webhook secret stored in environment variables — never committed to code
-
----
-
-## SCIM provisioning
-
-- [ ] Configure webhook endpoints to receive SCIM events
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/scim-integrations/
-- [ ] Verify webhook security with signature validation on every request
-- [ ] Test user provisioning (automatic creation from IdP)
-- [ ] Test user deprovisioning (deactivation/deletion when removed in IdP)
-- [ ] Test user profile updates (name, email, attributes synced correctly)
-- [ ] Test role changes propagated via group membership
-- [ ] Set up group-based role assignment and sync
-- [ ] Test error cases: duplicate users, invalid data, missing required fields
-- [ ] Verify idempotent handling — duplicate events must not create duplicate records
-- [ ] Deactivation preferred over hard deletion for `user_deleted` events
-
-**Webhook reliability:**
-- [ ] Webhook endpoint returns 2xx quickly — offload heavy processing to a queue if needed
-- [ ] Scalekit retries on non-2xx with exponential backoff (up to 8 attempts over ~10 hours)
-- [ ] Tested webhook delivery end-to-end with a real IdP or Scalekit's test tool
-
----
-
-## User and organization management
-
-- [ ] Test organization creation and domain assignment
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org provisioning (if applicable)
-- [ ] Set default roles for auto-provisioned users
-- [ ] Test user deletion flow
-
-**RBAC (if implemented):**
-- [ ] Define roles and permissions that map to IdP groups
-- [ ] Test role assignment via group membership sync
-- [ ] Verify permission enforcement at API endpoints
-- [ ] Test access control across all role levels
-
----
-
-## Network and firewall
-
-Enterprise customers behind VPN or corporate firewall must whitelist:
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Directory API + webhook delivery |
-| `cdn.scalekit.com` | Static assets |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SCIM provisioning tested from customer's network environment
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for provisioning failures
-- [ ] Alerts configured for failed webhook deliveries
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back)
-- [ ] Rollback plan ready (disable SCIM sync without breaking existing users)
-
-**Key metrics:**
-- Webhook delivery success rate
-- User provisioning/deprovisioning latency
-- Failed sync events (by type and error)
-- Group-to-role mapping accuracy
diff --git a/plugins/modular-sso/.codex-plugin/plugin.json b/plugins/modular-sso/.codex-plugin/plugin.json
deleted file mode 100644
index 8c6e2e3..0000000
--- a/plugins/modular-sso/.codex-plugin/plugin.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "modular-sso",
- "version": "1.2.0",
- "description": "Guides teams through Modular SSO with Scalekit when the app already manages users and sessions.",
- "author": {
- "name": "Scalekit Inc",
- "email": "support@scalekit.com",
- "url": "https://scalekit.com"
- },
- "homepage": "https://docs.scalekit.com",
- "repository": "https://github.com/scalekit-inc/claude-code-authstack",
- "license": "MIT",
- "keywords": [
- "sso",
- "saml",
- "oidc",
- "authentication",
- "enterprise"
- ],
- "skills": "./skills/",
- "mcpServers": "./.mcp.json",
- "interface": {
- "displayName": "Modular SSO",
- "shortDescription": "Add enterprise SSO without replacing your app stack.",
- "longDescription": "Helps implement connection-based SSO, IdP-initiated login handling, enterprise onboarding, admin portal setup, and production-readiness while preserving existing user and session management.",
- "developerName": "Scalekit",
- "category": "Enterprise SSO",
- "capabilities": [
- "Interactive",
- "Write"
- ],
- "websiteURL": "https://docs.scalekit.com",
- "privacyPolicyURL": "https://www.scalekit.com/privacy",
- "termsOfServiceURL": "https://www.scalekit.com/terms",
- "defaultPrompt": [
- "Add modular enterprise SSO with Scalekit to this app.",
- "Implement IdP-initiated login handling with Scalekit.",
- "Review my SSO onboarding and callback flow."
- ],
- "brandColor": "#B45309"
- }
-}
diff --git a/plugins/modular-sso/.mcp.json b/plugins/modular-sso/.mcp.json
deleted file mode 100644
index 36dbbf4..0000000
--- a/plugins/modular-sso/.mcp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "mcpServers": {
- "scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
- }
- }
-}
diff --git a/plugins/modular-sso/README.md b/plugins/modular-sso/README.md
deleted file mode 100644
index 9e1bce0..0000000
--- a/plugins/modular-sso/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Modular SSO
-
-`modular-sso` helps Codex implement enterprise SSO with Scalekit for applications that already manage their own users and sessions. It focuses on connection selection, callback handling, IdP-initiated login, and enterprise onboarding.
-
-## Use This Plugin When
-
-- your app already has user/session management
-- you need SAML or OIDC enterprise SSO
-- you need IdP-initiated login support
-- you want guidance on onboarding customers to the right SSO connection
-
-## Primary Skill
-
-- `modular-sso`
-
-## Additional Skills
-
-- `implementing-admin-portal`
-- `production-readiness-scalekit`
-
-Try asking Codex:
-
-- `Add enterprise SSO with Scalekit to this app`
-- `Implement IdP-initiated login handling`
-- `Review my modular SSO callback flow`
-
-## Configuration
-
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-
-The plugin also ships [`./.mcp.json`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/modular-sso/.mcp.json), which points at the remote Scalekit MCP server.
-
-## Reference Docs
-
-- [`references/redirects.md`](/Users/saif/Projects/ai-first/codex-auth-stack/plugins/modular-sso/references/redirects.md)
-
-## Troubleshooting
-
-- Disable Full-Stack Auth in the dashboard before implementing Modular SSO flows.
-- Decide whether you route users by `connectionId`, `organizationId`, or `loginHint` and keep that choice consistent.
-- IdP-initiated login usually fails when the initiate-login endpoint or relay-state handling is incomplete.
diff --git a/plugins/modular-sso/references/redirects.md b/plugins/modular-sso/references/redirects.md
deleted file mode 100644
index dbe1977..0000000
--- a/plugins/modular-sso/references/redirects.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Redirects
-
-Redirects are registered endpoints in Scalekit that control where users are directed during authentication flows. You must configure these endpoints in the Scalekit dashboard before they can be used.
-
-All redirect URIs must be registered under Authentication settings in your Scalekit dashboard. This is a security requirement to prevent unauthorized redirects.
-
-
-## Redirect endpoint types
-
-### Allowed callback URLs
-**Purpose**: Where users are sent after successful authentication to exchange authorization codes and retrieve profile information.
-
-**Example scenario**: A user completes sign-in and Scalekit redirects them to `https://yourapp.com/callback` where your application processes the authentication response.
-
-To add or remove an redirect URL, go to Dashboard > Authentication > Redirects > Allowed Callback URLs.
-
-### Initiate login URL
-**Purpose**: When authentication does not initiate from your application, Scalekit redirects users back to your application's login initiation endpoint. This endpoint should point to a route in your application that ultimately redirects users to Scalekit's `/authorize` endpoint.
-
-**Example scenarios**:
-
-- **Bookmarked login page**: A user bookmarks your login page and visits it directly. Your application detects they're not authenticated and redirects them to Scalekit's authorization endpoint.
-
-- **Organization invitation flow**: A user clicks an invitation link to join an organization. Your application receives the invitation token and redirects the user to Scalekit's authorization endpoint to complete the sign-up process.
-
-- **IdP-initiated SSO**: An administrator initiates single sign-on from their identity provider dashboard. The IdP redirects users to your application, which then redirects them to Scalekit's authorization endpoint to complete authentication.
-
-- **Session expiration**: When a user's session expires or they access a protected resource, they're redirected to `https://yourapp.com/login` which then redirects to Scalekit's authentication endpoint.
-
-### Post logout URL
-**Purpose**: Where users are sent after successfully signing out of your application.
-
-**Example scenario**: After logging out, users are redirected to `https://yourapp.com/goodbye` to confirm their session has ended.
-
-### Back channel logout URL
-**Purpose**: A secure endpoint that receives notifications whenever a user is logged out from Scalekit, regardless of how the logout was initiated — admin triggered, user initiated, or due to session policies like idle timeout.
-
-**Example scenario**: When a user logs out from any application (user-initiated, admin-initiated, or due to session policies like idle timeout), Scalekit sends a logout notification to `https://yourapp.com/logout` to suggest termination of the user's session across all connected applications, ensuring coordinated logout for enhanced security.
-
-### Custom URI schemes
-
-Custom URI schemes allow for redirects, enabling deep linking and native app integrations. Some applications include:
-- **Desktop applications**: Use schemes like `{scheme}://` for native app integration
-- **Mobile apps**: Use schemes like `myapp://` for mobile app deep linking
-
-**Example custom schemes**:
-- `{scheme}://auth/callback` - For custom scheme authentication
-- `myapp://login/callback` - For mobile app authentication
-
-
-## URI validation requirements
-
-Your redirect URIs must meet specific requirements that vary between development and production environments:
-
-| Requirement | Development | Production |
-| ----------- | ----------- | ---------- |
-| Supported schemes | `http`, `https`, `{scheme}` | `https`, `{scheme}` |
-| Localhost support | Allowed | Not allowed |
-| Wildcard domains | Allowed | Not allowed |
-| URI length limit | 256 characters | 256 characters |
-| Query parameters | Not allowed | Not allowed |
-| URL fragments | Not allowed | Not allowed |
-
-
-### Wildcard usage patterns
-
-Wildcards can simplify testing in development environments, but they must follow specific patterns:
-
-| Validation rule | Valid examples | Invalid examples |
-| --------------- | -------------- | ---------------- |
-| Wildcards cannot be used as root-level domains | `https://*.acmecorp.com`, `https://auth-*.acmecorp.com` | `https://*.com` |
-| Only one wildcard character is allowed per URI | `https://*.acmecorp.com` | `https://*.*.acmecorp.com` |
-| Wildcards must be in the hostname component only | `https://*.acmecorp.com` | `https://acmecorp.*.com` |
-| Wildcards must be in the outermost subdomain | `https://*.auth.acmecorp.com` | `https://auth.*.acmecorp.com` |
-
-> **Note**: According to the [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), redirect URIs must be absolute URIs. For development convenience, Scalekit relaxes this restriction slightly by allowing wildcards in development environments.
diff --git a/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md b/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md
deleted file mode 100644
index 7bbfd19..0000000
--- a/plugins/modular-sso/skills/implementing-admin-portal/SKILL.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-name: implementing-admin-portal
-description: 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.
----
-
-# Admin Portal with Scalekit
-
-Adds a self-serve portal where customers configure their own SSO and SCIM settings — embedded inside your app's settings UI.
-
-If the user only needs a quick shareable link with no code (e.g., for a one-time onboarding call), skip to the **Shareable link** section at the bottom.
-
----
-
-## Implementation progress
-
-```
-Admin Portal Implementation Progress:
-- [ ] Step 1: Install SDK
-- [ ] Step 2: Set environment credentials
-- [ ] Step 3: Register app domain in dashboard
-- [ ] Step 4: Generate portal link (server-side)
-- [ ] Step 5: Render iframe (client-side)
-- [ ] Step 6: Handle session expiry events
-- [ ] Step 7: Verify portal loads and events fire correctly
-```
-
----
-
-## Step 1: Install SDK
-
-Detect the project's language/framework from existing files and install:
-
-| Stack | Install |
-|---------|---------|
-| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` |
-
----
-
-## Step 2: Set environment credentials
-
-Add to `.env` (never hardcode):
-
-```shell
-SCALEKIT_ENVIRONMENT_URL='https://.scalekit.com'
-SCALEKIT_CLIENT_ID=''
-SCALEKIT_CLIENT_SECRET=''
-```
-
-Credentials are in **Dashboard > Developers > Settings > API Credentials**.
-
----
-
-## Step 3: Register app domain
-
-In **Dashboard > Developers > API Configuration > Redirect URIs**, add the domain where the portal will be embedded. The iframe will be blocked if this is missing.
-
----
-
-## Step 4: Generate the portal link (server-side)
-
-Generate a new link on every page load — links are single-use. Plug into the existing route or controller that serves the settings/admin page:
-
-**Node.js:**
-```javascript
-const { location } = await scalekit.organization.generatePortalLink(organizationId);
-// Pass `location` to the frontend as a template variable or API response
-```
-
-**Python:**
-```python
-portal = scalekit_client.organization.generate_portal_link(organization_id)
-location = portal.location
-# Pass `location` to your template or JSON response
-```
-
-**Never cache this value** — each link is single-use and will fail if reused.
-
----
-
-## Step 5: Render the iframe (client-side)
-
-In the frontend settings/admin template, inject `location` as the `src`:
-
-```html
-
-```
-
-Minimum recommended height: **600px**. Match the variable name to the project's existing templating convention.
-
----
-
-## Step 6: Handle portal UI events
-
-Listen for messages from the iframe to react to configuration changes and session expiry:
-
-```javascript
-window.addEventListener('message', (event) => {
- if (event.origin !== process.env.SCALEKIT_ENVIRONMENT_URL) return;
-
- const { type } = event.data;
- switch (type) {
- case 'SSO_CONFIGURED':
- // Refresh org SSO status, show success banner, etc.
- break;
- case 'SESSION_EXPIRED':
- // Re-fetch a new portal link and reload the iframe src
- reloadPortalIframe();
- break;
- }
-});
-```
-
-`SESSION_EXPIRED` handling is required — without it the portal silently breaks for long-lived sessions.
-
----
-
-## Step 7: Verify
-
-- [ ] Open the settings page — confirm the iframe renders without console errors
-- [ ] Complete a test SSO configuration inside the portal — confirm `SSO_CONFIGURED` fires
-- [ ] Wait for session expiry (or simulate it) — confirm `SESSION_EXPIRED` triggers a link refresh
-- [ ] Confirm portal link is never the same across two page loads (single-use verification)
-
----
-
-## Branding (optional)
-
-Configure at **Dashboard > Settings > Branding**: logo, accent color, favicon. Custom domain support (e.g., `sso.yourapp.com`) is available in the Scalekit dashboard.
-
----
-
-## Guardrails
-
-- **Generate link server-side only** — never expose `CLIENT_SECRET` to the browser
-- **Re-generate on every page load** — caching will break the portal
-- **Register your domain** in Redirect URIs before testing or the iframe will be blocked
-- **Handle `SESSION_EXPIRED`** — re-generate and reload, don't let it fail silently
-
----
-
-## Shareable link (no-code alternative)
-
-For one-time onboarding calls or zero-engineering setup: go to **Dashboard > Organizations**, select the org, click **Generate link**, and share the URL directly. The link gives anyone who has it full access to configure that org's SSO/SCIM settings — use the iframe approach for production. Also share Scalekit's [SSO setup guides](https://docs.scalekit.com/guides/integrations/sso-integrations/) so the IT admin has provider-specific configuration steps alongside the portal link.
-
diff --git a/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md b/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md
deleted file mode 100644
index b24ffab..0000000
--- a/plugins/modular-sso/skills/production-readiness-scalekit/SKILL.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-name: production-readiness-scalekit
-description: 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.
----
-
-# Scalekit SSO Production Readiness
-
-Work through each section in order — earlier sections are blockers for later ones.
-
----
-
-## Quick checks (run first)
-
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
-- [ ] HTTPS enforced on all auth endpoints
-- [ ] CORS restricted to your domains only
-- [ ] API credentials stored in environment variables — never committed to code
-
----
-
-## Customization
-
-- [ ] Login page branded with logo, colors, styling
-- [ ] Email templates customized (sign-up, password reset, invitations)
-- [ ] Custom domain configured for auth pages (if applicable)
-- [ ] Email provider configured in **Dashboard > Customization > Emails**
-- [ ] Email deliverability tested — check spam folders
-- [ ] Webhooks configured with signature validation
-
----
-
-## Core auth flows
-
-- [ ] Test login initiation with authorization URL
-- [ ] Validate redirect URLs match dashboard configuration exactly
-- [ ] Test authentication completion and code exchange
-- [ ] Validate `state` parameter in callbacks (CSRF protection)
-- [ ] Verify session token storage uses `httpOnly`, `secure`, and `sameSite` flags
-- [ ] Test session timeout and automatic token refresh
-- [ ] Verify logout clears sessions completely
-- [ ] Expired tokens handled gracefully
-- [ ] Network failures show user-friendly messages
-
----
-
-## SSO flows
-
-- [ ] Test SSO with target IdPs: Okta, Azure AD, Google Workspace
- → IT admin setup guides per IdP: https://docs.scalekit.com/guides/integrations/sso-integrations/
-- [ ] Configure user attribute mapping (email, name, groups)
-- [ ] Test both SP-initiated and IdP-initiated SSO flows
-- [ ] Verify SSO error handling for misconfigured connections
-- [ ] Test SSO with: new users, existing users, deactivated users
-
-**JIT provisioning:**
-- [ ] Register all organization domains for JIT provisioning
-- [ ] Configure consistent user identifiers across SSO connections (email or userPrincipalName)
-- [ ] Set default roles for JIT-provisioned users
-- [ ] Enable "Sync user attributes during login"
-- [ ] Plan manual invitation process for contractors/external users with non-matching domains
-- [ ] Set up review process for automatically provisioned users
-
-**Admin portal:**
-- [ ] Configure admin portal access for enterprise customers
-- [ ] Test admin portal SSO configuration flows
-- [ ] Verify user management features in admin portal
-
----
-
-## Organization management
-
-- [ ] Test organization creation
-- [ ] Test adding and removing users from organizations
-- [ ] Set allowed email domains for org sign-ups (if applicable)
-- [ ] Verify organization switching for users in multiple orgs
-- [ ] Test invitation flow and email templates
-
----
-
-## Network and firewall
-
-Enterprise customers behind VPN or corporate firewall must whitelist:
-
-| Domain | Purpose |
-|---|---|
-| `.scalekit.com` | Auth + admin portal |
-| `cdn.scalekit.com` | Static assets |
-| `fonts.googleapis.com` | Font resources |
-
-- [ ] Customer firewalls allow Scalekit domains
-- [ ] SSO tested from customer's network environment
-
----
-
-## Monitoring and incident readiness
-
-- [ ] Auth logs monitoring configured in **Dashboard > Auth Logs**
-- [ ] Alerts set for suspicious activity (multiple failed logins, unusual locations)
-- [ ] Webhook event monitoring and logging active
-- [ ] Error tracking configured for authentication failures
-- [ ] Log retention policies configured
-- [ ] Webhook delivery and retry mechanism tested
-- [ ] Incident response runbook written (who to contact, how to roll back, escalation path)
-- [ ] Rollback plan ready (feature flag to disable SSO flows if needed)
-
-**Key metrics:**
-- Login success/failure rates
-- SSO initiation vs completion rate
-- Session creation and duration
-- Webhook delivery success rate
diff --git a/plugins/saaskit/.codex-plugin/plugin.json b/plugins/saaskit/.codex-plugin/plugin.json
new file mode 100644
index 0000000..8bd3432
--- /dev/null
+++ b/plugins/saaskit/.codex-plugin/plugin.json
@@ -0,0 +1,33 @@
+{
+ "name": "saaskit",
+ "version": "2.0.0",
+ "description": "Production-ready auth for B2B SaaS apps. Login, sessions, SSO, SCIM, MCP server auth, and API key management.",
+ "author": {
+ "name": "Scalekit Inc",
+ "email": "support@scalekit.com",
+ "url": "https://scalekit.com"
+ },
+ "homepage": "https://docs.scalekit.com",
+ "repository": "https://github.com/scalekit-inc/codex-authstack",
+ "license": "MIT",
+ "keywords": ["scalekit", "saaskit", "authentication", "sso", "scim", "mcp-auth", "sessions"],
+ "skills": "./skills/",
+ "mcpServers": "./.mcp.json",
+ "interface": {
+ "displayName": "SaaSKit",
+ "shortDescription": "Production-ready B2B SaaS authentication.",
+ "longDescription": "Production-ready auth for B2B SaaS apps. Login, sessions, SSO (Okta, Azure AD, Google), SCIM provisioning, RBAC, MCP server auth, and API key management.",
+ "developerName": "Scalekit",
+ "category": "Application Auth",
+ "capabilities": ["Interactive", "Write"],
+ "websiteURL": "https://docs.scalekit.com",
+ "privacyPolicyURL": "https://www.scalekit.com/privacy",
+ "termsOfServiceURL": "https://www.scalekit.com/terms",
+ "defaultPrompt": [
+ "Add login and sessions to my app with Scalekit.",
+ "Implement enterprise SSO for my B2B app.",
+ "Add SCIM provisioning to my application."
+ ],
+ "brandColor": "#1D4ED8"
+ }
+}
diff --git a/plugins/full-stack-auth/.mcp.json b/plugins/saaskit/.mcp.json
similarity index 100%
rename from plugins/full-stack-auth/.mcp.json
rename to plugins/saaskit/.mcp.json
diff --git a/plugins/saaskit/README.md b/plugins/saaskit/README.md
new file mode 100644
index 0000000..bddc8c8
--- /dev/null
+++ b/plugins/saaskit/README.md
@@ -0,0 +1,32 @@
+# SaaSKit for Codex
+
+Production-ready auth for B2B SaaS apps. This plugin brings Scalekit SaaSKit into Codex to build production-ready B2B authentication. It covers login, sessions, SSO, SCIM provisioning, MCP server auth, API keys, and more.
+
+## Skills
+
+- `implementing-saaskit` — Core auth flow: login, signup, callback, token exchange, session management, logout. Framework references for Go, Spring Boot, Laravel.
+- `implementing-saaskit-nextjs` — Auth for Next.js App Router.
+- `implementing-saaskit-python` — Auth for Django, FastAPI, or Flask. Framework references included.
+- `implementing-modular-sso` — Enterprise SSO (SAML/OIDC) with 20+ IdPs, admin portal, JIT provisioning.
+- `implementing-scim-provisioning` — SCIM 2.0 webhooks, user/group lifecycle, directory API.
+- `adding-mcp-oauth` — OAuth 2.1 for MCP servers (FastMCP, Express, FastAPI).
+- `implementing-access-control` — RBAC and permission checks.
+- `managing-saaskit-sessions` — Secure session storage, token refresh, session revocation.
+- `migrating-to-saaskit` — Migration planning from Auth0, Firebase, Cognito, or custom auth.
+- `adding-api-auth` — API keys (org/user scoped) and OAuth 2.0 client credentials.
+- `production-readiness-saaskit` — Unified production checklist across all SaaSKit domains.
+
+## Configuration
+
+Required environment variables:
+
+- `SCALEKIT_ENVIRONMENT_URL`
+- `SCALEKIT_CLIENT_ID`
+- `SCALEKIT_CLIENT_SECRET`
+
+## Links
+
+- [Full-stack auth quickstart](https://docs.scalekit.com/authenticate/fsa/quickstart/)
+- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/)
+- [SCIM directory sync](https://docs.scalekit.com/directory/scim/quickstart/)
+- [MCP Auth quickstart](https://docs.scalekit.com/authenticate/mcp/quickstart/)
diff --git a/plugins/mcp-auth/references/bring-your-own-auth.md b/plugins/saaskit/references/bring-your-own-auth.md
similarity index 100%
rename from plugins/mcp-auth/references/bring-your-own-auth.md
rename to plugins/saaskit/references/bring-your-own-auth.md
diff --git a/plugins/full-stack-auth/references/redirects.md b/plugins/saaskit/references/redirects.md
similarity index 100%
rename from plugins/full-stack-auth/references/redirects.md
rename to plugins/saaskit/references/redirects.md
diff --git a/plugins/full-stack-auth/references/scalekit-logs.md b/plugins/saaskit/references/scalekit-logs.md
similarity index 100%
rename from plugins/full-stack-auth/references/scalekit-logs.md
rename to plugins/saaskit/references/scalekit-logs.md
diff --git a/plugins/mcp-auth/references/scalekit-mcp-server.md b/plugins/saaskit/references/scalekit-mcp-server.md
similarity index 100%
rename from plugins/mcp-auth/references/scalekit-mcp-server.md
rename to plugins/saaskit/references/scalekit-mcp-server.md
diff --git a/plugins/full-stack-auth/references/scalekit-user-profiles.md b/plugins/saaskit/references/scalekit-user-profiles.md
similarity index 100%
rename from plugins/full-stack-auth/references/scalekit-user-profiles.md
rename to plugins/saaskit/references/scalekit-user-profiles.md
diff --git a/plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md b/plugins/saaskit/skills/adding-api-auth/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md
rename to plugins/saaskit/skills/adding-api-auth/SKILL.md
index 8b9cfe5..feb8c9a 100644
--- a/plugins/full-stack-auth/skills/adding-api-key-auth/SKILL.md
+++ b/plugins/saaskit/skills/adding-api-auth/SKILL.md
@@ -1,5 +1,5 @@
---
-name: adding-api-key-auth
+name: adding-api-auth
description: >
Creates, validates, lists, and revokes long-lived opaque API keys using
Scalekit for organization-scoped or user-scoped bearer authentication.
diff --git a/plugins/mcp-auth/skills/mcp-auth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
similarity index 100%
rename from plugins/mcp-auth/skills/mcp-auth/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
diff --git a/plugins/mcp-auth/skills/express-mcp-server/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/express-mcp-server/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
diff --git a/plugins/mcp-auth/skills/fastapi-fastmcp/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/fastapi-fastmcp/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
diff --git a/plugins/mcp-auth/skills/add-auth-fastmcp/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/fastmcp-reference.md
similarity index 100%
rename from plugins/mcp-auth/skills/add-auth-fastmcp/SKILL.md
rename to plugins/saaskit/skills/adding-mcp-oauth/fastmcp-reference.md
diff --git a/plugins/full-stack-auth/skills/implementing-access-control/SKILL.md b/plugins/saaskit/skills/implementing-access-control/SKILL.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-access-control/SKILL.md
rename to plugins/saaskit/skills/implementing-access-control/SKILL.md
diff --git a/plugins/modular-sso/skills/modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
similarity index 98%
rename from plugins/modular-sso/skills/modular-sso/SKILL.md
rename to plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index 1775d2e..82a186f 100644
--- a/plugins/modular-sso/skills/modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -1,5 +1,5 @@
---
-name: modular-sso
+name: implementing-modular-sso
description: Implements Modular SSO with Scalekit for applications that already manage their own users and sessions. Use when adding enterprise SSO, SAML, OIDC, IdP-initiated login, or customer onboarding flows.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
index 3d4ba84..137ee9e 100644
--- a/plugins/full-stack-auth/skills/implementing-scalekit-nextjs-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-nextjs-auth
+name: implementing-saaskit-nextjs
description: Implements Scalekit authentication in a Next.js App Router project using the patterns from scalekit-inc/scalekit-nextjs-auth-example. Handles login, OAuth callback, session management, token refresh, logout, and permission-based access control using @scalekit-sdk/node. Use when adding auth routes, protecting pages, managing sessions, or checking permissions in a Next.js + Scalekit codebase.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index 7fffb09..bad9eea 100644
--- a/plugins/full-stack-auth/skills/implementing-scalekit-django-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-django-auth
+name: implementing-saaskit-python
description: Implements Scalekit authentication in a Django project using the patterns from scalekit-inc/scalekit-django-auth-example. Handles login, OAuth callback, Django session storage, automatic token refresh via middleware, logout, and permission-based route protection using decorators. Use when adding auth views, protecting URLs, managing sessions, or checking permissions in a Django + Scalekit codebase.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-fastapi-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-fastapi-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-flask-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-flask-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
diff --git a/plugins/full-stack-auth/skills/full-stack-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/SKILL.md
index 389d2f1..c57df34 100644
--- a/plugins/full-stack-auth/skills/full-stack-auth/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
@@ -1,5 +1,5 @@
---
-name: implementing-scalekit-fsa
+name: implementing-saaskit
description: Implements Scalekit full-stack authentication (FSA) including sign-up, login, logout, and secure session management using JWT tokens. Use when building or integrating user authentication with the Scalekit SDK across Node.js, Python, Go, or Java — or when the user asks about auth flows, OAuth callbacks, token refresh, or session handling with Scalekit.
---
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-go-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/go-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-go-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/go-reference.md
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-laravel-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-laravel-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
diff --git a/plugins/full-stack-auth/skills/implementing-scalekit-springboot-auth/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
similarity index 100%
rename from plugins/full-stack-auth/skills/implementing-scalekit-springboot-auth/SKILL.md
rename to plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
diff --git a/plugins/modular-scim/skills/modular-scim/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
similarity index 100%
rename from plugins/modular-scim/skills/modular-scim/SKILL.md
rename to plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
diff --git a/plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md
rename to plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
index ea94dc5..e6fb8fc 100644
--- a/plugins/full-stack-auth/skills/manage-user-sessions/SKILL.md
+++ b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
@@ -1,5 +1,5 @@
---
-name: managing-user-sessions
+name: managing-saaskit-sessions
description: Manages Scalekit-backed user sessions by securely storing access/refresh/ID tokens (with encryption and correct cookie attributes), validating access tokens on every request, transparently refreshing tokens in middleware, and optionally revoking sessions remotely via Scalekit session APIs. Use when building session persistence for only for web apps. For SPAs this is NOT the skill.
---
diff --git a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/AUDIT-CHECKLIST.md b/plugins/saaskit/skills/migrating-to-saaskit/AUDIT-CHECKLIST.md
similarity index 100%
rename from plugins/full-stack-auth/skills/migrating-to-scalekit-auth/AUDIT-CHECKLIST.md
rename to plugins/saaskit/skills/migrating-to-saaskit/AUDIT-CHECKLIST.md
diff --git a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/IMPORT-SAMPLES.md b/plugins/saaskit/skills/migrating-to-saaskit/IMPORT-SAMPLES.md
similarity index 100%
rename from plugins/full-stack-auth/skills/migrating-to-scalekit-auth/IMPORT-SAMPLES.md
rename to plugins/saaskit/skills/migrating-to-saaskit/IMPORT-SAMPLES.md
diff --git a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
similarity index 99%
rename from plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md
rename to plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
index 66f84e5..9c670f5 100644
--- a/plugins/full-stack-auth/skills/migrating-to-scalekit-auth/SKILL.md
+++ b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
@@ -1,5 +1,5 @@
---
-name: migrating-to-scalekit-auth
+name: migrating-to-saaskit
description: Plans and executes a safe, incremental migration from any existing auth system to Scalekit's full-stack auth platform. Use when the user asks to migrate authentication, replace session middleware, import users/organizations to Scalekit, configure SSO, or set up SCIM provisioning with Scalekit.
---
diff --git a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
new file mode 100644
index 0000000..5a52753
--- /dev/null
+++ b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
@@ -0,0 +1,64 @@
+---
+name: production-readiness-saaskit
+description: Walks through a structured production readiness checklist for Scalekit SaaSKit implementations covering authentication, SSO, SCIM, MCP server auth, and API security. Use when going live, launching to production, or doing a pre-launch review.
+---
+
+# SaaSKit Production Readiness
+
+Unified checklist for all SaaSKit domains. Work through in order — skip sections that don't apply.
+
+## Quick checks (run first)
+
+- [ ] Production env URL, client ID, and client secret set (not dev/staging)
+- [ ] HTTPS enforced; CORS restricted to your domains only
+- [ ] All credentials in environment variables — never committed to code
+- [ ] Only enabled auth methods active in production
+
+## Customization
+
+- [ ] Login page branded; email templates customized
+- [ ] Custom domain configured (if applicable); email deliverability tested
+- [ ] Webhooks configured with signature validation
+
+## Core auth flows
+
+- [ ] Login initiation, code exchange, and redirect URLs match dashboard exactly
+- [ ] `state` parameter validated in callbacks (CSRF); tokens stored with `httpOnly`, `secure`, `sameSite`
+- [ ] Token refresh and session timeout working; logout calls Scalekit end-session
+- [ ] Each enabled auth method tested; errors handled gracefully
+
+## SSO (if applicable)
+
+- [ ] SSO tested with target IdPs (Okta, Azure AD, Google Workspace)
+- [ ] SP-initiated and IdP-initiated flows both working
+- [ ] Admin portal configured for self-serve SSO setup
+- [ ] JIT provisioning: domains registered, default roles set, attribute sync enabled
+
+## SCIM provisioning (if applicable)
+
+- [ ] Webhook endpoints receiving events with signature validation
+- [ ] User provisioning, deprovisioning, and profile updates tested
+- [ ] Group-based role sync working; idempotent handling verified
+
+## MCP authentication (if applicable)
+
+- [ ] MCP auth flow tested end-to-end; resource metadata published
+- [ ] Scopes enforced per tool; client reconnection after token expiry working
+
+## Network / firewall
+
+Enterprise VPN customers must whitelist: `.scalekit.com`, `cdn.scalekit.com`, `fonts.googleapis.com`.
+
+## Monitoring
+
+- [ ] Auth logs monitoring active; alerts for suspicious activity configured
+- [ ] Webhook monitoring active; error tracking for auth and provisioning failures
+- [ ] Incident response runbook written; rollback plan ready (feature flag)
+- **Key metrics:** login success/failure rates, session duration, webhook delivery, SSO completion rate
+
+## Deep reference
+
+- [Scalekit Documentation](https://docs.scalekit.com)
+- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/)
+- [SCIM directory sync](https://docs.scalekit.com/directory/scim/quickstart/)
+- [MCP Auth quickstart](https://docs.scalekit.com/authenticate/mcp/quickstart/)
From 0fb2b60d5b1287f94ffbad3ba14d971b0be7b8ee Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 14:20:01 +0530
Subject: [PATCH 02/39] =?UTF-8?q?remove=20testing-agentkit-tools=20skill?=
=?UTF-8?q?=20=E2=80=94=20redundant=20with=20MCP=20server?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
plugins/agentkit/README.md | 1 -
.../skills/testing-agentkit-tools/SKILL.md | 93 -------------------
2 files changed, 94 deletions(-)
delete mode 100644 plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
index 9ceef6e..20b9d63 100644
--- a/plugins/agentkit/README.md
+++ b/plugins/agentkit/README.md
@@ -8,7 +8,6 @@ AgentKit handles the full OAuth lifecycle — authorization, token vault, and au
- `integrating-agentkit` — Core integration: SDK setup, connected accounts, OAuth flows, token fetching, downstream API calls, and agent framework examples.
- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
-- `testing-agentkit-tools` — Generates authorization links, fetches live tool metadata, and executes tools.
- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
- `production-readiness-agentkit` — Structured production readiness checklist for AgentKit integrations.
diff --git a/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md b/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
deleted file mode 100644
index 4d55bc9..0000000
--- a/plugins/agentkit/skills/testing-agentkit-tools/SKILL.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-name: testing-agentkit-tools
-description: Tests live Scalekit AgentKit flows by generating authorization links, fetching tool metadata, and executing a tool for a connected account. Use when a user wants to validate a connector, inspect the exact payload for execute_tool, or build a workflow step by step.
----
-
-# Testing AgentKit Tools
-
-This skill is the live playground for AgentKit. Use it to:
-
-- generate an authorization link for a connection
-- fetch live tool metadata for a connector or tool name
-- execute a tool with real inputs
-- inspect the exact JSON payload sent to AgentKit
-
-## Prerequisites
-
-Confirm the environment variables are available:
-- `SCALEKIT_ENV_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
-
-## Operations
-
-### Generate authorization link
-
-Creates or fetches the connected account and prints an authorization link if the account is not yet `ACTIVE`.
-
-**Python**
-```python
-response = actions.get_or_create_connected_account(
- connection_name="",
- identifier=""
-)
-if response.connected_account.status != "ACTIVE":
- link_response = actions.get_authorization_link(
- connection_name="",
- identifier=""
- )
- print("Authorize here:", link_response.link)
-```
-
-### Fetch tool metadata
-
-Fetches live tool metadata. Omitting `tool_name` returns all matching tools for the filter.
-
-**Python**
-```python
-tools = actions.get_tools(providers=["GMAIL"], page_size=100)
-for tool in tools:
- print(tool.name, tool.input_schema)
-```
-
-**Node.js**
-```typescript
-const tools = await scalekitClient.connectedAccounts.getTools({
- providers: ['GMAIL'],
- pageSize: 100,
-});
-```
-
-### Execute a tool
-
-Creates or fetches the connected account, prints an authorization link if needed, and executes the tool.
-
-**Python**
-```python
-result = actions.execute_tool(
- tool_name="gmail_fetch_mails",
- connection_name="",
- identifier="",
- tool_input={"query": "is:unread", "max_results": 5}
-)
-```
-
-## Default workflow
-
-1. Discover the tool first when the schema is unknown.
-2. Generate an authorization link if the connected account is not `ACTIVE`.
-3. Execute the tool with the smallest valid `tool_input`.
-4. Show the exact command and payload used so the user can translate it into app code.
-
-## Guardrails
-
-- Treat live metadata as the source of truth for `input_schema` and `output_schema`.
-- Do not assume the dashboard `connection_name` matches the connector slug.
-- Ask for missing credentials instead of inventing placeholder values.
-- Keep the tool set constrained to the current workflow.
-
-## Deep reference
-
-- Integration workflow: [../integrating-agentkit/SKILL.md](../integrating-agentkit/SKILL.md)
-- Connector reference: [../../references/agent-connectors/README.md](../../references/agent-connectors/README.md)
-- Connected accounts: [../../references/connected-accounts.md](../../references/connected-accounts.md)
From d0034c5948e6d4d4e8eeb005f9b5042a7d3ee448 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 14:37:32 +0530
Subject: [PATCH 03/39] add AGENTS.md with Codex-specific plugin conventions
---
AGENTS.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 121 insertions(+)
create mode 100644 AGENTS.md
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..c9bf547
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,121 @@
+# AGENTS.md
+
+This repository is a monorepo of Codex plugins intended for marketplace distribution.
+Any agent changing this repo must follow this document.
+
+## What this repo contains
+
+Everything under `plugins/` is a Codex plugin. A plugin includes skills and reference files that teach the agent how to integrate Scalekit authentication.
+
+Codex does not have a public plugin marketplace. This repo ships with a bootstrap installer (`install.sh`) and a local install script (`scripts/install_codex_marketplace.sh`) that copy plugins into `~/.codex/marketplaces/scalekit-auth-stack`.
+
+## Monorepo layout
+
+```
+codex-authstack/
+├── plugins/
+│ ├── agentkit/ # AI agent authentication
+│ │ ├── README.md
+│ │ ├── skills/ # Skill entrypoints
+│ │ └── references/ # Deep docs and connector notes
+│ └── saaskit/ # B2B SaaS authentication
+│ ├── README.md
+│ ├── skills/
+│ └── references/
+├── scripts/
+│ ├── install_codex_marketplace.sh
+│ └── validate_marketplace.py
+├── install.sh # One-command bootstrap installer
+├── AGENTS.md # This file
+└── README.md
+```
+
+## Plugins
+
+### agentkit
+
+Authentication for AI agents. OAuth flows, token vault, 40+ connectors, tool discovery.
+
+Skills:
+- `integrating-agentkit` — core integration: SDK setup, connected accounts, OAuth flows, token fetching, agent frameworks
+- `discovering-connector-tools` — live tool metadata discovery, schema inspection, tool set narrowing
+- `exposing-agentkit-via-mcp` — expose AgentKit tools through MCP for compatible runtimes
+- `production-readiness-agentkit` — production readiness checklist for AgentKit integrations
+
+References: `agent-connectors/` (connector docs), `connected-accounts.md`, `code-samples.md`, `providers.md`, `connections.md`, `byoc.md`, `redirects.md`
+
+### saaskit
+
+Production-ready auth for B2B SaaS apps. Login, sessions, SSO, SCIM, MCP server auth.
+
+Skills:
+- `implementing-saaskit` — core auth flow (+ Go, Spring Boot, Laravel reference files)
+- `implementing-saaskit-nextjs` — Next.js App Router auth
+- `implementing-saaskit-python` — Django, FastAPI, Flask (+ framework reference files)
+- `implementing-modular-sso` — enterprise SSO (SAML/OIDC) with 20+ IdPs, admin portal
+- `implementing-scim-provisioning` — SCIM 2.0 webhooks, user/group lifecycle
+- `implementing-access-control` — server-side RBAC
+- `managing-saaskit-sessions` — token storage, validation, refresh, revocation
+- `adding-mcp-oauth` — OAuth 2.1 for MCP servers (+ Express, FastAPI, FastMCP reference files)
+- `adding-api-auth` — API keys and client credentials for M2M auth
+- `migrating-to-saaskit` — incremental migration from existing auth systems
+- `production-readiness-saaskit` — unified production checklist
+
+References: `bring-your-own-auth.md`, `redirects.md`, `scalekit-logs.md`, `scalekit-mcp-server.md`, `scalekit-user-profiles.md`
+
+## Non-negotiable rules
+
+- Work on one plugin at a time unless the user explicitly asks for cross-plugin changes.
+- Never add secrets, tokens, credentials, or private endpoints to any file.
+- Prefer minimal changes that improve correctness, security, and user clarity.
+- Keep instructions stable, avoid time-dependent guidance.
+- Use forward slashes in all paths.
+
+## Codex-specific conventions
+
+Codex plugins differ from Claude Code and Cursor plugins:
+
+- **No `.claude-plugin/` or `.cursor-plugin/` directory.** Codex uses `~/.agents/plugins/marketplace.json` to discover marketplaces.
+- **No rules (`.mdc` files).** Codex does not support Cursor-style rules. Use skill content and references instead.
+- **No agents.** Codex does not support sub-agent definitions. Guidance that would be an agent in other auth stacks should be a skill or reference doc here.
+- **No hooks.** Codex does not support lifecycle hooks.
+- **No commands.** Codex does not support slash commands. Skills are the only entrypoint.
+
+## Skill authoring rules
+
+Each skill is a folder with `SKILL.md` as its entrypoint.
+
+Frontmatter requirements:
+- `name` must be lowercase, hyphenated, max 64 chars.
+- `description` must be third person and include both what it does and when to use it.
+
+Context budget:
+- Keep `SKILL.md` short and practical.
+- Put deep docs in reference files linked from `SKILL.md`.
+- Do not create multi-hop reference chains.
+
+## Validation
+
+Run the validation script before committing:
+
+```bash
+python3 scripts/validate_marketplace.py
+```
+
+This checks marketplace manifest structure, plugin manifests, skill files, frontmatter, and reference file depth.
+
+## Local testing
+
+1. Run `./scripts/install_codex_marketplace.sh` to copy plugins to `~/.codex/marketplaces/scalekit-auth-stack`
+2. Restart Codex
+3. Open Plugin Directory and select `Scalekit Auth Stack`
+4. Install `agentkit` or `saaskit`
+5. Invoke at least one skill to verify it triggers correctly
+
+## Documentation rules
+
+Each plugin README must include:
+- Purpose
+- Skills list with descriptions
+- Configuration (required env vars)
+- Links to Scalekit docs
\ No newline at end of file
From 496bd406a147b273eb20736fd0955794c902216c Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 16:39:33 +0530
Subject: [PATCH 04/39] update install script and changelog for
agentkit+saaskit consolidation
- Replace 5 old plugin entries with agentkit + saaskit in personal marketplace
- Add cleanup of old v1.x plugin directories on re-install
- Update CHANGELOG to reflect consolidation
---
CHANGELOG.md | 13 +++---
scripts/install_codex_marketplace.sh | 66 ++++++++++------------------
2 files changed, 31 insertions(+), 48 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 654f4bd..b88c024 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,14 @@
## Unreleased
-- Expand Codex auth plugin depth and coverage:
- - Add the missing portable skills across `mcp-auth`, `agent-auth`, `full-stack-auth`, `modular-sso`, and `modular-scim`.
- - Add plugin-local reference docs, including the full Agent Auth connector corpus.
- - Add `.mcp.json` support across all five plugins.
- - Add a richer repo README for public-facing marketplace storytelling.
+- Consolidate 5 plugins into 2:
+ - `agentkit` — AI agent authentication (replaces `agent-auth`)
+ - `saaskit` — B2B SaaS authentication (replaces `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim`)
+- Add `.mcp.json` to both plugins pointing to `https://mcp.scalekit.com`.
+- Add plugin-local reference docs, including the full AgentKit connector corpus.
+- Add a richer repo README for public-facing marketplace storytelling.
+- Update install script to handle migration from old plugin names.
+- Add `AGENTS.md` with Codex-specific plugin conventions.
- Improve installation UX:
- Add a one-command GitHub bootstrap installer.
- Add a safe local installer that avoids overwriting an unrelated personal marketplace by default.
diff --git a/scripts/install_codex_marketplace.sh b/scripts/install_codex_marketplace.sh
index 3028cca..5379333 100755
--- a/scripts/install_codex_marketplace.sh
+++ b/scripts/install_codex_marketplace.sh
@@ -9,6 +9,9 @@ INSTALL_ROOT="${HOME}/.codex/marketplaces/scalekit-auth-stack"
PERSONAL_MARKETPLACE="${HOME}/.agents/plugins/marketplace.json"
FORCE_PERSONAL_MARKETPLACE="${FORCE_PERSONAL_MARKETPLACE:-0}"
+# Old plugin names from v1.x (now consolidated into agentkit + saaskit)
+OLD_PLUGINS=("mcp-auth" "agent-auth" "modular-sso" "modular-scim" "full-stack-auth")
+
mkdir -p "$(dirname "$INSTALL_ROOT")"
rm -rf "$INSTALL_ROOT"
mkdir -p "$INSTALL_ROOT"
@@ -16,6 +19,11 @@ mkdir -p "$INSTALL_ROOT"
cp -R "$REPO_ROOT"/. "$INSTALL_ROOT"
rm -rf "$INSTALL_ROOT/.git"
+# Clean up old v1.x plugin directories if they exist from a previous install
+for old in "${OLD_PLUGINS[@]}"; do
+ rm -rf "$INSTALL_ROOT/plugins/$old"
+done
+
PLUGIN_BASE="./.codex/marketplaces/scalekit-auth-stack/plugins"
write_personal_marketplace() {
@@ -28,22 +36,10 @@ write_personal_marketplace() {
},
"plugins": [
{
- "name": "mcp-auth",
- "source": {
- "source": "local",
- "path": "${PLUGIN_BASE}/mcp-auth"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "MCP Security"
- },
- {
- "name": "agent-auth",
+ "name": "agentkit",
"source": {
"source": "local",
- "path": "${PLUGIN_BASE}/agent-auth"
+ "path": "${PLUGIN_BASE}/agentkit"
},
"policy": {
"installation": "AVAILABLE",
@@ -52,34 +48,10 @@ write_personal_marketplace() {
"category": "Agent Auth"
},
{
- "name": "modular-sso",
+ "name": "saaskit",
"source": {
"source": "local",
- "path": "${PLUGIN_BASE}/modular-sso"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "Enterprise SSO"
- },
- {
- "name": "modular-scim",
- "source": {
- "source": "local",
- "path": "${PLUGIN_BASE}/modular-scim"
- },
- "policy": {
- "installation": "AVAILABLE",
- "authentication": "ON_INSTALL"
- },
- "category": "Provisioning"
- },
- {
- "name": "full-stack-auth",
- "source": {
- "source": "local",
- "path": "${PLUGIN_BASE}/full-stack-auth"
+ "path": "${PLUGIN_BASE}/saaskit"
},
"policy": {
"installation": "AVAILABLE",
@@ -135,22 +107,30 @@ if [[ "$PERSONAL_RESULT" == "created" ]]; then
Created personal Codex marketplace:
$PERSONAL_MARKETPLACE
+Available plugins:
+ agentkit — AI agent authentication (connectors, tool discovery, token vault)
+ saaskit — B2B SaaS authentication (login, SSO, SCIM, RBAC, MCP server auth)
+
Next steps:
1. Restart Codex.
2. Open the Plugin Directory.
3. Choose "Scalekit Auth Stack".
-4. Install one of the plugins.
+4. Install agentkit, saaskit, or both.
EOF
elif [[ "$PERSONAL_RESULT" == "updated" ]]; then
cat <
Date: Wed, 13 May 2026 16:53:03 +0530
Subject: [PATCH 05/39] rename scripts/install_codex_marketplace.sh to
scripts/install.sh
---
AGENTS.md | 6 +++---
README.md | 2 +-
install.sh | 6 +++---
scripts/{install_codex_marketplace.sh => install.sh} | 2 +-
4 files changed, 8 insertions(+), 8 deletions(-)
rename scripts/{install_codex_marketplace.sh => install.sh} (98%)
diff --git a/AGENTS.md b/AGENTS.md
index c9bf547..2b92950 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -7,7 +7,7 @@ Any agent changing this repo must follow this document.
Everything under `plugins/` is a Codex plugin. A plugin includes skills and reference files that teach the agent how to integrate Scalekit authentication.
-Codex does not have a public plugin marketplace. This repo ships with a bootstrap installer (`install.sh`) and a local install script (`scripts/install_codex_marketplace.sh`) that copy plugins into `~/.codex/marketplaces/scalekit-auth-stack`.
+Codex does not have a public plugin marketplace. This repo ships with a bootstrap installer (`install.sh`) and a local install script (`scripts/install.sh`) that copy plugins into `~/.codex/marketplaces/scalekit-auth-stack`.
## Monorepo layout
@@ -23,7 +23,7 @@ codex-authstack/
│ ├── skills/
│ └── references/
├── scripts/
-│ ├── install_codex_marketplace.sh
+│ ├── install.sh
│ └── validate_marketplace.py
├── install.sh # One-command bootstrap installer
├── AGENTS.md # This file
@@ -106,7 +106,7 @@ This checks marketplace manifest structure, plugin manifests, skill files, front
## Local testing
-1. Run `./scripts/install_codex_marketplace.sh` to copy plugins to `~/.codex/marketplaces/scalekit-auth-stack`
+1. Run `./scripts/install.sh` to copy plugins to `~/.codex/marketplaces/scalekit-auth-stack`
2. Restart Codex
3. Open Plugin Directory and select `Scalekit Auth Stack`
4. Install `agentkit` or `saaskit`
diff --git a/README.md b/README.md
index 43ec856..84908fb 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ This installer:
If you are developing locally from a clone:
```bash
-./scripts/install_codex_marketplace.sh
+./scripts/install.sh
```
This script:
diff --git a/install.sh b/install.sh
index 737d075..dc4c90d 100755
--- a/install.sh
+++ b/install.sh
@@ -7,7 +7,7 @@ REPO_REF="${CODEX_AUTHSTACK_REF:-main}"
SOURCE_DIR="${CODEX_AUTHSTACK_SOURCE_DIR:-}"
if [[ -n "$SOURCE_DIR" ]]; then
- exec "${SOURCE_DIR%/}/scripts/install_codex_marketplace.sh"
+ exec "${SOURCE_DIR%/}/scripts/install.sh"
fi
TMP_DIR="$(mktemp -d)"
@@ -27,9 +27,9 @@ tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR"
EXTRACTED_DIR="$(find "$TMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
-if [[ -z "$EXTRACTED_DIR" ]] || [[ ! -x "$EXTRACTED_DIR/scripts/install_codex_marketplace.sh" ]]; then
+if [[ -z "$EXTRACTED_DIR" ]] || [[ ! -x "$EXTRACTED_DIR/scripts/install.sh" ]]; then
echo "Failed to find installer in downloaded archive." >&2
exit 1
fi
-exec "$EXTRACTED_DIR/scripts/install_codex_marketplace.sh"
+exec "$EXTRACTED_DIR/scripts/install.sh"
diff --git a/scripts/install_codex_marketplace.sh b/scripts/install.sh
similarity index 98%
rename from scripts/install_codex_marketplace.sh
rename to scripts/install.sh
index 5379333..3360e1d 100755
--- a/scripts/install_codex_marketplace.sh
+++ b/scripts/install.sh
@@ -149,6 +149,6 @@ What you can do next:
4. Choose "Scalekit Auth Stack" and install agentkit, saaskit, or both.
If you intentionally want this installer to replace your personal marketplace file, re-run:
- FORCE_PERSONAL_MARKETPLACE=1 ./scripts/install_codex_marketplace.sh
+ FORCE_PERSONAL_MARKETPLACE=1 ./scripts/install.sh
EOF
fi
From b59e9359e5c016b515a6ffd0171398b1e0bb4f1a Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 17:12:48 +0530
Subject: [PATCH 06/39] Add missing skills, references, and fix connector
terminology
- Add testing-auth-setup skill to saaskit (npx dryrun CLI)
- Add session-management-patterns.md reference to saaskit
- Add tool-discovery.md reference to agentkit (adapted for Codex)
- Add setup-scalekit.md reference (converted from agent)
- Add mcp-auth-troubleshooting.md reference (converted from agent)
- Rename providers.md to connectors.md, fix terminology to AgentKit/connectors
- Update connectors table with Attention, Chorus, Clari Copilot, Google Slides
- Update AGENTS.md and saaskit README to reflect new files
---
AGENTS.md | 5 +-
.../{providers.md => connectors.md} | 71 ++---
plugins/agentkit/references/tool-discovery.md | 83 ++++++
.../skills/integrating-agentkit/SKILL.md | 2 +-
plugins/saaskit/README.md | 1 +
.../references/mcp-auth-troubleshooting.md | 93 ++++++
.../references/session-management-patterns.md | 279 ++++++++++++++++++
plugins/saaskit/references/setup-scalekit.md | 100 +++++++
.../skills/testing-auth-setup/SKILL.md | 55 ++++
9 files changed, 651 insertions(+), 38 deletions(-)
rename plugins/agentkit/references/{providers.md => connectors.md} (69%)
create mode 100644 plugins/agentkit/references/tool-discovery.md
create mode 100644 plugins/saaskit/references/mcp-auth-troubleshooting.md
create mode 100644 plugins/saaskit/references/session-management-patterns.md
create mode 100644 plugins/saaskit/references/setup-scalekit.md
create mode 100644 plugins/saaskit/skills/testing-auth-setup/SKILL.md
diff --git a/AGENTS.md b/AGENTS.md
index 2b92950..d5b1143 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -42,7 +42,7 @@ Skills:
- `exposing-agentkit-via-mcp` — expose AgentKit tools through MCP for compatible runtimes
- `production-readiness-agentkit` — production readiness checklist for AgentKit integrations
-References: `agent-connectors/` (connector docs), `connected-accounts.md`, `code-samples.md`, `providers.md`, `connections.md`, `byoc.md`, `redirects.md`
+References: `agent-connectors/` (connector docs), `connected-accounts.md`, `code-samples.md`, `connectors.md`, `connections.md`, `byoc.md`, `redirects.md`, `tool-discovery.md`
### saaskit
@@ -60,8 +60,9 @@ Skills:
- `adding-api-auth` — API keys and client credentials for M2M auth
- `migrating-to-saaskit` — incremental migration from existing auth systems
- `production-readiness-saaskit` — unified production checklist
+- `testing-auth-setup` — validates auth integration via dryrun CLI
-References: `bring-your-own-auth.md`, `redirects.md`, `scalekit-logs.md`, `scalekit-mcp-server.md`, `scalekit-user-profiles.md`
+References: `bring-your-own-auth.md`, `redirects.md`, `scalekit-logs.md`, `scalekit-mcp-server.md`, `scalekit-user-profiles.md`, `session-management-patterns.md`, `setup-scalekit.md`, `mcp-auth-troubleshooting.md`
## Non-negotiable rules
diff --git a/plugins/agentkit/references/providers.md b/plugins/agentkit/references/connectors.md
similarity index 69%
rename from plugins/agentkit/references/providers.md
rename to plugins/agentkit/references/connectors.md
index 5a4270b..b9c35e7 100644
--- a/plugins/agentkit/references/providers.md
+++ b/plugins/agentkit/references/connectors.md
@@ -1,27 +1,27 @@
-# Providers
+# Connectors Overview
-Providers in Agent Auth represent third-party applications that your users can connect to and interact with through Scalekit's unified API. Each provider offers a set of tools and capabilities that can be executed on behalf of connected users.
+Connectors in AgentKit represent third-party applications that your users can connect to and interact with through Scalekit's unified API. Each connector offers a set of tools and capabilities that can be executed on behalf of connected users.
-## What are providers?
+## What are connectors?
-Providers are pre-configured integrations with popular third-party applications that enable your users to:
+Connectors are pre-configured integrations with popular third-party applications that enable your users to:
- **Connect their accounts** using secure authentication methods
- **Execute tools and actions** through a unified API interface
- **Access data and functionality** from external applications
- **Maintain secure connections** with proper authorization scopes
-## Supported providers
+## Supported connectors
-Agent Auth supports a wide range of popular business applications:
+AgentKit supports a wide range of popular business applications:
-| Category | Providers |
+| Category | Connectors |
|---|---|
-| **Google Workspace** | Gmail, Google Calendar, Google Drive, Google Docs, Google Sheets, Google Forms, Google Meet, Google Ads |
+| **Google Workspace** | Gmail, Google Calendar, Google Drive, Google Docs, Google Sheets, Google Slides, Google Forms, Google Meet, Google Ads |
| **Microsoft 365** | Outlook, OneDrive, SharePoint, Microsoft Teams, Microsoft Excel, Microsoft Word, OneNote |
| **Communication** | Slack, Zoom |
| **Project Management** | Jira, Asana, Trello, Monday.com, ClickUp, Linear, Confluence |
-| **CRM & Sales** | Salesforce, HubSpot, Zendesk, Freshdesk, Intercom, Gong |
+| **CRM & Sales** | Salesforce, HubSpot, Zendesk, Freshdesk, Intercom, Gong, Attention, Chorus, Clari Copilot |
| **Development** | GitHub |
| **Productivity** | Notion, Airtable, Dropbox |
| **Data & Analytics** | BigQuery, Snowflake, Fathom |
@@ -29,19 +29,19 @@ Agent Auth supports a wide range of popular business applications:
For per-connector tool specifications, see [agent-connectors/README.md](agent-connectors/README.md).
-## Provider capabilities
+## Connector capabilities
-Each provider offers different capabilities based on their API and authentication model.
+Each connector offers different capabilities based on its API and authentication model.
### Authentication methods
-- **OAuth 2.0**: Standard method for all supported providers
+- **OAuth 2.0**: Standard method for all supported connectors
### Available tools
-Providers expose various tools that can be executed through Agent Auth:
+Connectors expose various tools that can be executed through AgentKit:
-> **Note:** Tool availability depends on the specific provider and the user's permissions within that application.
+> **Note:** Tool availability depends on the specific connector, the current live catalog, and the user's permissions within that application.
**Common tool categories:**
@@ -53,25 +53,25 @@ Providers expose various tools that can be executed through Agent Auth:
### Rate limits and quotas
-Each provider has different rate limits and quotas:
+Each connector has different rate limits and quotas:
- **API rate limits**: Requests per minute/hour limitations
- **Data quotas**: Storage or transfer limitations
- **Feature restrictions**: Premium features or enterprise-only capabilities
-## Provider configuration
+## Connector configuration
-### Adding a provider
+### Adding a connector
-1. **Navigate to providers** in your Agent Auth dashboard
-2. **Select provider** from the available options
+1. **Navigate to connections** in your AgentKit dashboard
+2. **Select connector** from the available options
3. **Configure settings** such as scopes and permissions
4. **Set up authentication** — configure OAuth client credentials if using custom OAuth apps
-5. **Test connection** to verify provider setup
+5. **Test connection** to verify connector setup
-### Provider settings
+### Connector settings
-Each provider can be configured with:
+Each connector can be configured with:
**Authentication settings:**
- OAuth client credentials (if using custom OAuth apps)
@@ -83,11 +83,11 @@ Each provider can be configured with:
- Request throttling settings
- Backoff strategies for rate limit errors
-## Working with provider APIs
+## Working with connector APIs
### API integration
-The Scalekit SDK abstracts provider-specific APIs — the workflow (create account → authorize → fetch token → call API) is identical for all providers. Only the downstream API call changes:
+The Scalekit SDK abstracts connector-specific APIs — the workflow (create account → authorize → fetch token → call API) is identical for all connectors. Only the downstream API call changes:
```python
# Step 3: Fetch token (always call this immediately before the API call)
@@ -98,7 +98,7 @@ response = actions.get_connected_account(
tokens = response.connected_account.authorization_details["oauth_token"]
access_token = tokens["access_token"]
-# Step 4: Call the provider API with the token
+# Step 4: Call the connector API with the token
headers = {"Authorization": f"Bearer {access_token}"}
```
@@ -106,7 +106,7 @@ Scalekit automatically refreshes expired tokens on `get_connected_account` — n
### Error handling
-Agent Auth normalizes provider-specific errors into consistent error responses:
+AgentKit normalizes connector-specific errors into consistent error responses:
```javascript
{
@@ -122,7 +122,7 @@ Agent Auth normalizes provider-specific errors into consistent error responses:
}
```
-## Provider-specific considerations
+## Connector-specific considerations
### Google Workspace
@@ -167,23 +167,24 @@ Agent Auth normalizes provider-specific errors into consistent error responses:
## Monitoring and analytics
-### Provider health
+### Connector health
-- **API uptime**: Track provider API availability
+- **API uptime**: Track connector API availability
- **Response times**: Monitor latency for different operations
-- **Error rates**: Track errors by provider and tool type
+- **Error rates**: Track errors by connector and tool type
- **Rate limit usage**: Monitor quota consumption
### Usage analytics
-- **Popular providers**: Which providers are used most
+- **Popular connectors**: Which connectors are used most
- **Tool usage**: Which tools are executed most frequently
-- **User adoption**: How many users connect to each provider
-- **Error patterns**: Common failure modes by provider
+- **User adoption**: How many users connect to each connector
+- **Error patterns**: Common failure modes by connector
## Related documentation
-- [connections.md](connections.md) — how to configure authentication credentials for a provider
+- [connections.md](connections.md) — how to configure authentication credentials for a connector
- [connected-accounts.md](connected-accounts.md) — per-user account lifecycle and token management
-- [agent-connectors/README.md](agent-connectors/README.md) — detailed API tools for each provider
+- [agent-connectors/README.md](agent-connectors/README.md) — detailed API tools for each connector
+- [tool-discovery.md](tool-discovery.md) — live discovery model for current tools and schemas
- [code-samples.md](code-samples.md) — implementation examples by framework
diff --git a/plugins/agentkit/references/tool-discovery.md b/plugins/agentkit/references/tool-discovery.md
new file mode 100644
index 0000000..15a631d
--- /dev/null
+++ b/plugins/agentkit/references/tool-discovery.md
@@ -0,0 +1,83 @@
+# Tool Discovery
+
+## Overview
+
+In AgentKit, the live tool metadata is the source of truth for:
+
+- current connector coverage
+- tool names
+- `input_schema`
+- `output_schema`
+
+For connector-specific guidance, auth quirks, and example workflows, see the canonical connector docs at [docs.scalekit.com/agentkit/connectors](https://docs.scalekit.com/agentkit/connectors/).
+
+## Terminology
+
+- `connector`: the integration, such as Gmail, Slack, Salesforce, or a custom connector
+- `connection`: the dashboard configuration created once per environment
+- `connected account`: the per-user authorized instance of a connection
+- `tool`: the executable action exposed by a connector
+
+Use `connector` in user-facing explanations. Use `provider` only when the SDK or API filter field literally uses that name.
+
+## Discovery rules
+
+1. Prefer live lookup over hand-maintained docs.
+2. Narrow the search to a single connector or tool name whenever possible.
+3. Summarize required inputs from `input_schema.required`.
+4. Summarize optional inputs from `input_schema.properties`.
+5. Describe likely results from `output_schema.properties`.
+6. Recommend the smallest useful tool set before handing tools to an LLM.
+
+## What to inspect
+
+When live metadata is available, capture:
+
+- tool `name`
+- tool `description`
+- connector / provider slug
+- `input_schema.properties`
+- `input_schema.required`
+- `output_schema.properties`
+
+If the metadata contains pagination or large result fields, mention them so the user can limit tool scope or post-process results before sending them back to the model.
+
+## How to use this in Codex
+
+For interactive discovery, use the Scalekit MCP server. When connected at `https://mcp.scalekit.com`, you can query tool metadata, generate auth links, and execute tools directly through MCP tool calls.
+
+For implementation guidance, use:
+
+- `discovering-connector-tools` when the user needs the current tool list or schema
+- The Scalekit MCP server when the user wants to execute a tool and inspect the payload interactively
+- `integrating-agentkit` when the user wants to wire the result into application code
+
+For per-connector tool specifications, see [agent-connectors/README.md](agent-connectors/README.md).
+
+## Connection names vs connector names
+
+Do not confuse:
+
+- dashboard `connection_name`: exact value from `AgentKit -> Connections`
+- connector / provider slug: value used to group live tools in metadata
+
+The first is for authorization and connected account flows.
+The second is for catalog discovery and tool grouping.
+
+They are related, but they are not always the same string.
+
+## Example reasoning pattern
+
+1. User says: "What tools can I use for Google Sheets?"
+2. Discover the live tool list for the Google Sheets connector.
+3. Inspect the candidate tools and their `input_schema`.
+4. Recommend only the few tools needed for the workflow, such as read values, update values, or append rows.
+5. If the user wants to validate the flow, generate an auth link if needed and execute one tool with minimal input.
+
+## Fallback behavior
+
+If live credentials are not available:
+
+- refer to [docs.scalekit.com/agentkit/connectors](https://docs.scalekit.com/agentkit/connectors/) as a directional guide
+- clearly say the catalog may be stale without live credentials
+- avoid claiming that the listed tools are exhaustive
diff --git a/plugins/agentkit/skills/integrating-agentkit/SKILL.md b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
index d338e27..7c37bdd 100644
--- a/plugins/agentkit/skills/integrating-agentkit/SKILL.md
+++ b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
@@ -297,7 +297,7 @@ For comprehensive documentation on connected accounts lifecycle, states, and API
For code samples and implementation examples by framework, see [code-samples.md](../references/code-samples.md).
-For an overview of supported providers and their capabilities, see [providers.md](../references/providers.md).
+For an overview of supported connectors and their capabilities, see [connectors.md](../references/connectors.md).
For comprehensive token management including refresh, security, and monitoring, see [token-management.md](../references/token-management.md).
diff --git a/plugins/saaskit/README.md b/plugins/saaskit/README.md
index bddc8c8..dd4eaea 100644
--- a/plugins/saaskit/README.md
+++ b/plugins/saaskit/README.md
@@ -15,6 +15,7 @@ Production-ready auth for B2B SaaS apps. This plugin brings Scalekit SaaSKit int
- `migrating-to-saaskit` — Migration planning from Auth0, Firebase, Cognito, or custom auth.
- `adding-api-auth` — API keys (org/user scoped) and OAuth 2.0 client credentials.
- `production-readiness-saaskit` — Unified production checklist across all SaaSKit domains.
+- `testing-auth-setup` — Validates auth integration by running the Scalekit dryrun CLI.
## Configuration
diff --git a/plugins/saaskit/references/mcp-auth-troubleshooting.md b/plugins/saaskit/references/mcp-auth-troubleshooting.md
new file mode 100644
index 0000000..95424f5
--- /dev/null
+++ b/plugins/saaskit/references/mcp-auth-troubleshooting.md
@@ -0,0 +1,93 @@
+# MCP Auth Troubleshooting
+
+Reference for diagnosing and resolving common Scalekit MCP auth integration issues. Covers handshake/metadata verification, cached client state, CORS/network problems, and client-specific quirks.
+
+## Principles
+
+- Always collect evidence first (HTTP status, headers, URLs, logs) before suggesting fixes.
+- Prefer reversible fixes (config, allowlists, callback URLs, proxy rules) over code changes.
+- Follow the triage flow in order — earlier steps catch the most common failures.
+
+## Triage flow
+
+### 1. Identify the client and environment
+
+Determine which MCP client is failing: MCP Inspector, MCP-Remote, VS Code, Codex, Claude Desktop, or another client.
+
+Capture:
+- MCP server URL
+- Scalekit environment URL
+- Whether this is dev or prod
+
+### 2. Confirm the auth handshake (server-side)
+
+Goal: verify the server challenges unauthenticated requests correctly and points clients to resource metadata.
+
+Run these checks:
+
+```bash
+# Should return HTTP 401
+curl -s -o /dev/null -w "%{http_code}" https:///
+
+# Should include WWW-Authenticate header with resource_metadata URL
+curl -s -I https:/// | grep -i www-authenticate
+```
+
+Then open the `resource_metadata` URL in a browser and confirm the JSON matches the Scalekit dashboard configuration for that environment.
+
+If these checks fail, classify as **metadata/handshake misconfiguration** and fix the protected resource metadata wiring first.
+
+### 3. Check cached client state
+
+If the handshake looks correct but the client still fails, suspect cached old domain/metadata after a domain change.
+
+Clear cached auth by client:
+- **MCP-Remote**: delete `~/.mcp-auth/mcp-remote-` and reconnect
+- **VS Code**: run "Authentication: Remove Dynamic Authentication Provider", remove the cached entry, reconnect
+
+### 4. CORS and callback URL issues
+
+Common with MCP Inspector. If you see CORS failures during the handshake in browser network logs:
+
+1. In Scalekit Dashboard → Authentication → Redirect URLs → Allowed Callback URLs
+2. Add the client's callback URL (e.g., `http://localhost:6274/` for MCP Inspector)
+3. Retry the connection
+
+### 5. Network / proxy / firewall blocks
+
+If MCP client calls don't reach the server:
+
+- Identify whether behind Cloudflare, AWS WAF, or corporate proxy
+- Allow or exempt MCP client → server traffic for the server domain
+- Confirm via proxy/WAF logs
+- Test direct connectivity from the same machine running the MCP client
+
+### 6. Client-specific: port limitations
+
+Some MCP clients (e.g., Claude Desktop) only support standard HTTPS on port 443 and will ignore custom ports.
+
+Workarounds:
+- Expose MCP server on 443 via a load balancer or reverse proxy
+- Use a reverse proxy that listens on 443 and forwards to the internal custom port
+
+### 7. Client-specific: browser not invoked during auth
+
+If authentication times out because the browser never opens:
+
+- **macOS**: allow the MCP client to open applications (System Preferences → Security & Privacy → App Management), then restart
+- **Windows**: enable default app management permissions (Settings → Privacy → App permissions), then restart
+- **Linux**: ensure `xdg-open` exists (`which xdg-open`) and is on PATH, then restart
+
+## Verification checklist
+
+After applying a fix, verify:
+
+1. Unauthenticated request returns HTTP 401 with `WWW-Authenticate` header
+2. Resource metadata URL returns valid JSON matching dashboard config
+3. MCP client successfully completes the OAuth handshake
+4. At least one MCP tool call succeeds end-to-end
+
+## Related references
+
+- [scalekit-mcp-server.md](scalekit-mcp-server.md) — Scalekit MCP server architecture and implementation patterns
+- [Adding MCP OAuth skill](../skills/adding-mcp-oauth/SKILL.md) — implementing OAuth 2.1 for MCP servers
diff --git a/plugins/saaskit/references/session-management-patterns.md b/plugins/saaskit/references/session-management-patterns.md
new file mode 100644
index 0000000..228a5d0
--- /dev/null
+++ b/plugins/saaskit/references/session-management-patterns.md
@@ -0,0 +1,279 @@
+# Session Management Patterns
+
+Reference guide for evaluating and implementing session management with Scalekit. Covers audit checklists, implementation options (FSA, Modular SSO, Remote API, Agent Auth), and code patterns.
+
+Related references:
+- [scalekit-user-profiles.md](scalekit-user-profiles.md) — attribute schema and SDK methods
+- [scalekit-logs.md](scalekit-logs.md) — filter strategies and status definitions
+
+## Phase 1: Discovery — Understand the Existing Setup
+
+Run all discovery steps before forming any opinion. Use the results to inform Phases 2–4.
+
+### 1.1 Locate session-related files
+```bash
+grep -rn "session" --include="*.ts" --include="*.js" --include="*.py" --include="*.go" \
+ -l . 2>/dev/null | head -40
+```
+
+### 1.2 Identify token handling patterns
+```bash
+grep -rn "access_token\|refresh_token\|id_token\|Bearer\|HttpOnly\|cookie" \
+ --include="*.ts" --include="*.js" --include="*.py" -l . 2>/dev/null | head -30
+```
+
+### 1.3 Find authentication middleware
+```bash
+grep -rn "middleware\|authMiddleware\|validateToken\|verifyToken\|requireAuth" \
+ --include="*.ts" --include="*.js" --include="*.py" --include="*.go" \
+ -l . 2>/dev/null | head -20
+```
+
+### 1.4 Detect existing auth libraries in use
+```bash
+cat package.json 2>/dev/null || cat requirements.txt 2>/dev/null || cat go.mod 2>/dev/null
+grep -rn "express-session\|passport\|next-auth\|iron-session\|lucia\|better-auth\|@scalekit" \
+ package.json requirements.txt 2>/dev/null
+```
+
+### 1.5 Check for existing Scalekit setup
+```bash
+grep -rn "scalekit\|SCALEKIT_" --include="*.ts" --include="*.js" --include="*.py" \
+ --include="*.env*" -l . 2>/dev/null
+cat .env.example 2>/dev/null || cat .env.local 2>/dev/null
+```
+
+### 1.6 Identify framework and rendering model
+```bash
+ls -la | grep -E "next.config|nuxt.config|remix.config|vite.config|app.py|main.go"
+grep -rn "\"next\"\|\"remix\"\|\"nuxt\"\|\"express\"\|\"fastapi\"\|\"gin\"" package.json 2>/dev/null
+```
+
+After running all discovery commands, read each file identified as relevant before proceeding.
+
+---
+
+## Phase 2: Audit — Evaluate What's There
+
+Score each concern against the discovered files:
+
+| Concern | What to Check | Risk if Missing |
+|---|---|---|
+| Token storage | HttpOnly cookies vs localStorage | XSS exposure |
+| Refresh rotation | Token rotated on each refresh use | Session fixation / theft |
+| Middleware validation | Every protected route validated | Unauthorized access |
+| Absolute timeout | Max session duration enforced | Stale sessions |
+| Idle timeout | Inactivity logout configured | Unused session hijack |
+| CSRF protection | SameSite cookie attribute set | CSRF attacks |
+| Revocation capability | Remote session termination API | Incident response gap |
+| JWKS validation | Public key fetched & cached | Token forgery |
+
+For each concern, mark: ✅ Implemented | ⚠️ Partial | ❌ Missing | 🔍 Cannot determine
+
+Flag any critical anti-patterns immediately before options:
+- Tokens stored in localStorage → XSS risk
+- Missing HttpOnly flag → JS-accessible session tokens
+- No refresh rotation → session fixation window
+
+---
+
+## Phase 3: Options — Scalekit Implementation Paths
+
+Present only the options relevant to what is missing or broken. Tailor code examples to the
+actual framework and language detected in Phase 1.
+
+---
+
+### Option A: Full Stack Auth (FSA) — Scalekit Manages Sessions End-to-End
+**Best for:** New projects, or apps willing to delegate the full session lifecycle to Scalekit.
+
+Scalekit issues access tokens, refresh tokens, and ID tokens after login (Magic Link/OTP,
+Social, Enterprise SSO). Store them in HttpOnly cookies:
+
+```typescript
+// After successful Scalekit login callback
+res.cookie('access_token', tokens.access_token, {
+ httpOnly: true,
+ secure: true,
+ sameSite: 'lax',
+ path: '/api',
+ maxAge: 5 * 60 * 1000 // 5 minutes — match Scalekit dashboard config
+});
+
+res.cookie('refresh_token', tokens.refresh_token, {
+ httpOnly: true,
+ secure: true,
+ sameSite: 'strict',
+ path: '/auth/refresh', // scope to refresh endpoint only
+ maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
+});
+
+// ID token: accessible to JS for logout flows
+res.cookie('id_token', tokens.id_token, {
+ secure: true,
+ sameSite: 'lax',
+ path: '/'
+});
+```
+
+**Middleware pattern for every protected route:**
+```typescript
+async function scalekitSessionMiddleware(req, res, next) {
+ const accessToken = req.cookies.access_token;
+ if (!accessToken) return res.redirect('/login');
+
+ try {
+ const payload = await scalekit.auth.validateAccessToken(accessToken);
+ req.user = payload;
+ return next();
+ } catch (err) {
+ if (err.code === 'TOKEN_EXPIRED') {
+ return await handleTokenRefresh(req, res, next);
+ }
+ return res.redirect('/login');
+ }
+}
+
+async function handleTokenRefresh(req, res, next) {
+ const refreshToken = req.cookies.refresh_token;
+ if (!refreshToken) return res.redirect('/login');
+
+ try {
+ const newTokens = await scalekit.auth.refreshTokens(refreshToken);
+ res.cookie('access_token', newTokens.access_token, { /* same options */ });
+ res.cookie('refresh_token', newTokens.refresh_token, { /* same options */ });
+ req.user = await scalekit.auth.validateAccessToken(newTokens.access_token);
+ return next();
+ } catch (err) {
+ res.clearCookie('access_token');
+ res.clearCookie('refresh_token');
+ return res.redirect('/login');
+ }
+}
+```
+
+**Dashboard configuration (no code needed):**
+- Absolute session timeout: max duration user stays logged in
+- Idle session timeout: logout on inactivity
+- Access token lifetime: how often silent refresh triggers
+
+**Effort:** Medium | **Control:** Scalekit-managed | **Migration risk:** High if existing sessions
+
+---
+
+### Option B: Modular SSO — Scalekit for Identity Only, App Manages Sessions
+**Best for:** Apps with existing session infrastructure (express-session, next-auth, iron-session,
+lucia) that want enterprise SSO without rebuilding auth.
+
+```typescript
+// After Scalekit SSO callback — create your own session from verified identity
+app.get('/auth/callback', async (req, res) => {
+ const { code } = req.query;
+
+ const { user, idTokenClaims } = await scalekit.auth.authenticateWithCode(code, {
+ redirectUri: process.env.REDIRECT_URI
+ });
+
+ // Create session using YOUR existing mechanism
+ req.session.userId = user.id;
+ req.session.email = user.email;
+ req.session.org = idTokenClaims.org_id;
+ req.session.save(() => res.redirect('/dashboard'));
+});
+```
+
+**When to use this:**
+- `express-session`, `iron-session`, `lucia`, or similar already in place
+- Session storage (Redis, DB) is already wired
+- You need SSO on top, not a full auth overhaul
+
+**Effort:** Low | **Control:** App-managed | **Migration risk:** Low
+
+---
+
+### Option C: Remote Session Management API
+**Best for:** Adding session visibility and revocation to account settings or security
+dashboards. Works alongside Option A or B.
+
+```typescript
+// List all active sessions for a user (for account settings page)
+const sessions = await scalekit.sessions.list({ userId: req.user.id });
+
+// Revoke a specific session (user clicks "Sign out of this device")
+await scalekit.sessions.revoke({ sessionId: req.params.sessionId });
+
+// Revoke all sessions for a user (security incident response)
+await scalekit.sessions.revokeAll({ userId: req.user.id });
+```
+
+**Effort:** Low (additive) | **Control:** Full | **Migration risk:** None
+
+---
+
+### Option D: Agent Auth — Token Vault for AI Agent Scenarios
+**Best for:** AI apps where agents make API calls on behalf of users to third-party services.
+
+```typescript
+// Agent retrieves a valid token for a user's connected account
+const { access_token } = await scalekit.agentAuth.getToken({
+ userId: req.user.id,
+ provider: 'google',
+ scopes: ['calendar.read']
+});
+
+// Token is automatically refreshed, encrypted at rest, rotated on use
+await googleCalendarClient.listEvents({
+ headers: { Authorization: `Bearer ${access_token}` }
+});
+```
+
+**Effort:** Low | **Control:** Scalekit-managed token vault | **Migration risk:** None
+
+---
+
+## Phase 4: Recommendation Output Format
+
+Produce this structured report after completing all phases:
+
+---
+
+### 🔍 Session Audit Report
+
+**Detected stack:** [Framework, language, existing auth libs]
+**Existing Scalekit integration:** [Yes / Partial / None]
+**Session storage detected:** [Cookies / localStorage / In-memory / Server-side / Unknown]
+
+#### Audit Results
+[Completed audit table from Phase 2]
+
+#### ⚠️ Critical Anti-Patterns (fix before anything else)
+[List any immediate security issues with specific file references]
+
+#### Recommended Implementation Path
+**Primary:** [Option A / B / C / D] — [One-line reason tied to audit findings]
+**Secondary (if applicable):** [Option] — [Why it complements primary]
+
+#### Critical Gaps to Address First
+1. [Gap] — [Specific file:line to fix] — [Scalekit feature that addresses it]
+2. ...
+
+#### Implementation Steps
+[Numbered, concrete steps specific to this codebase. Reference actual file paths. No generic steps.]
+
+#### Scalekit Dashboard Actions Required
+- [ ] Set absolute session timeout to [suggested value based on app type]
+- [ ] Set access token lifetime to [suggested value]
+- [ ] Enable/disable idle session timeout
+
+---
+
+## Routing After Audit
+
+After delivering the report, offer to route to the appropriate skill for implementation:
+
+- Option A selected → `plugins/saaskit/skills/implementing-saaskit/SKILL.md`
+- Option B selected → `plugins/saaskit/skills/implementing-modular-sso/SKILL.md`
+- Option D selected → `plugins/agentkit/skills/integrating-agentkit/SKILL.md`
+
+If Scalekit is not yet set up, route to setup first:
+- `plugins/saaskit/references/setup-scalekit.md`
diff --git a/plugins/saaskit/references/setup-scalekit.md b/plugins/saaskit/references/setup-scalekit.md
new file mode 100644
index 0000000..aea1c50
--- /dev/null
+++ b/plugins/saaskit/references/setup-scalekit.md
@@ -0,0 +1,100 @@
+# Scalekit Setup Guide
+
+Reference for setting up Scalekit credentials, installing the SDK, and verifying the integration works before building features.
+
+## Required environment variables
+
+| Variable | Where to find it |
+|----------|-----------------|
+| `SCALEKIT_ENVIRONMENT_URL` | [app.scalekit.com](https://app.scalekit.com) → Settings → Environment |
+| `SCALEKIT_CLIENT_ID` | [app.scalekit.com](https://app.scalekit.com) → Developers → Settings → API Credentials |
+| `SCALEKIT_CLIENT_SECRET` | [app.scalekit.com](https://app.scalekit.com) → Developers → Settings → API Credentials |
+
+Store credentials in `.env`, shell environment, or CI secrets. Never hardcode them in source files.
+
+## Setup workflow
+
+### 1. Determine language and env var location
+
+Identify the project's language/runtime (Node.js, Python, Go, Java) and where env vars should live (`.env`, shell profile, CI secrets).
+
+### 2. Confirm env vars exist
+
+Verify all three variables are set in the current shell or process:
+
+```bash
+echo $SCALEKIT_ENVIRONMENT_URL
+echo $SCALEKIT_CLIENT_ID
+echo $SCALEKIT_CLIENT_SECRET
+```
+
+### 3. Install the SDK
+
+| Language | Package |
+|----------|---------|
+| Node.js | `npm install @scalekit-sdk/node` |
+| Python | `pip install scalekit-sdk-python` |
+| Go | `go get github.com/scalekit-inc/scalekit-sdk-go` |
+| Java | Add `scalekit-sdk-java` to Maven/Gradle |
+
+### 4. Initialize the client
+
+**Python**
+```python
+import scalekit.client, os
+from dotenv import load_dotenv
+load_dotenv()
+
+scalekit = scalekit.client.ScalekitClient(
+ client_id=os.getenv("SCALEKIT_CLIENT_ID"),
+ client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
+)
+```
+
+**Node.js**
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+import 'dotenv/config';
+
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+```
+
+### 5. Verify credentials
+
+List organizations with a small page size as the simplest verification:
+
+**Python**
+```python
+orgs = scalekit.organizations.list(page_size=5)
+print(f"Connected. Found {len(orgs.organizations)} organizations.")
+```
+
+**Node.js**
+```typescript
+const orgs = await scalekit.organization.listOrganizations({ pageSize: 5 });
+console.log(`Connected. Found ${orgs.organizations.length} organizations.`);
+```
+
+### 6. Diagnose failures
+
+If verification fails, check in this order:
+
+1. **Wrong environment URL** — dev vs prod, missing `https://` prefix
+2. **Missing env vars** — not loaded in current shell/process, `.env` not in project root
+3. **Incorrect client ID/secret** — regenerate from dashboard if unsure
+4. **Network/DNS issues** — corporate proxy, firewall, or VPN blocking the request
+
+## After setup succeeds
+
+Route to the appropriate skill for the user's goal:
+
+- SSO → `plugins/saaskit/skills/implementing-modular-sso/SKILL.md`
+- SCIM → `plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md`
+- MCP server auth → `plugins/saaskit/skills/adding-mcp-oauth/SKILL.md`
+- SaaSKit auth → `plugins/saaskit/skills/implementing-saaskit/SKILL.md`
+- Agent auth → `plugins/agentkit/skills/integrating-agentkit/SKILL.md`
diff --git a/plugins/saaskit/skills/testing-auth-setup/SKILL.md b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
new file mode 100644
index 0000000..4db0bd2
--- /dev/null
+++ b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
@@ -0,0 +1,55 @@
+---
+name: testing-auth-setup
+description: Validates a Scalekit auth integration by running the dryrun CLI against a live environment. Use when the user says "test my auth", "verify SSO setup", "check my login flow", "dryrun", or wants to confirm their Scalekit credentials and configuration are working.
+argument-hint: "[fsa|sso]"
+---
+
+# Testing Auth Setup
+
+Runs the Scalekit dryrun CLI to validate that your auth integration is correctly configured against a live environment.
+
+## Modes
+
+| Mode | What it tests | When to use |
+|------|--------------|-------------|
+| `fsa` | Full-stack auth login flow | User is setting up or verifying login, callback, and session handling |
+| `sso` | Enterprise SSO flow | User is setting up or verifying SAML/OIDC SSO with an identity provider |
+
+## Prerequisites
+
+Before running, confirm these environment variables are available:
+
+- `SCALEKIT_ENV_URL` — your Scalekit environment URL
+- `SCALEKIT_CLIENT_ID` — your client ID from app.scalekit.com → Settings
+
+If either is missing, ask the user to provide them. Do not write credentials into source-controlled files.
+
+## Running the test
+
+### Full-stack auth (fsa)
+
+```bash
+npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa
+```
+
+### Enterprise SSO
+
+Requires an `organization_id` — ask for it if not provided.
+
+```bash
+npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=sso --organization_id=
+```
+
+## Choosing the mode
+
+If the user doesn't specify a mode:
+
+1. Check the project context — if there's SSO configuration (identity providers, SAML metadata), suggest `sso`.
+2. Otherwise default to `fsa` as the most common starting point.
+3. If ambiguous, ask which mode to use.
+
+## After running
+
+- Show the command output.
+- Explain what passed and what failed in plain language.
+- If the test fails, suggest specific next steps based on the error (missing redirect URI, invalid credentials, organization not found, etc.).
\ No newline at end of file
From 77cc16d0fac83a6e48862013211b765b94603777 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 17:21:00 +0530
Subject: [PATCH 07/39] Improve post-install message with plugin activation and
auto-update guidance
---
scripts/install.sh | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/scripts/install.sh b/scripts/install.sh
index 3360e1d..f337e45 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -111,11 +111,16 @@ Available plugins:
agentkit — AI agent authentication (connectors, tool discovery, token vault)
saaskit — B2B SaaS authentication (login, SSO, SCIM, RBAC, MCP server auth)
-Next steps:
-1. Restart Codex.
+To activate the plugins in Codex:
+1. Restart Codex (or reload the session).
2. Open the Plugin Directory.
-3. Choose "Scalekit Auth Stack".
+3. Select "Scalekit Auth Stack" as your marketplace.
4. Install agentkit, saaskit, or both.
+5. Set update policy to "Auto-update (recommended)" to stay current.
+
+To verify:
+ Check the Plugin Directory shows agentkit and saaskit as installed.
+ Try a skill: ask "help me integrate agentkit" or "test my auth setup".
EOF
elif [[ "$PERSONAL_RESULT" == "updated" ]]; then
cat <
Date: Wed, 13 May 2026 17:30:56 +0530
Subject: [PATCH 08/39] Simplify post-install message to focus on what to look
for, not UI steps
---
scripts/install.sh | 52 ++++++++++++++++++++--------------------------
1 file changed, 23 insertions(+), 29 deletions(-)
diff --git a/scripts/install.sh b/scripts/install.sh
index f337e45..a4da0bf 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -111,16 +111,14 @@ Available plugins:
agentkit — AI agent authentication (connectors, tool discovery, token vault)
saaskit — B2B SaaS authentication (login, SSO, SCIM, RBAC, MCP server auth)
-To activate the plugins in Codex:
-1. Restart Codex (or reload the session).
-2. Open the Plugin Directory.
-3. Select "Scalekit Auth Stack" as your marketplace.
-4. Install agentkit, saaskit, or both.
-5. Set update policy to "Auto-update (recommended)" to stay current.
-
-To verify:
- Check the Plugin Directory shows agentkit and saaskit as installed.
- Try a skill: ask "help me integrate agentkit" or "test my auth setup".
+What to do next in Codex:
+- Restart Codex (or reload the session).
+- Look for the "Scalekit Auth Stack" marketplace in your plugin settings.
+- Install both plugins: "agentkit" and "saaskit".
+- Set the update policy to auto-update so you always have the latest skills.
+
+To verify it works:
+ Ask Codex to "help me integrate agentkit" or "test my auth setup".
EOF
elif [[ "$PERSONAL_RESULT" == "updated" ]]; then
cat <
Date: Wed, 13 May 2026 18:05:24 +0530
Subject: [PATCH 09/39] =?UTF-8?q?Fix=20stale=20terminology:=20Agent=20Auth?=
=?UTF-8?q?=20=E2=86=92=20AgentKit=20across=20all=20plugin=20content?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Replace 'Agent Auth' with 'AgentKit' in 8 files (skills, references)
- Fix stale skill reference: integrating-agent-auth → integrating-agentkit
- Fix stale URL: /agent-auth/connected-accounts → connected-accounts.md
---
.../agentkit/references/agent-connectors/README.md | 4 ++--
plugins/agentkit/references/byoc.md | 6 +++---
plugins/agentkit/references/code-samples.md | 4 ++--
plugins/agentkit/references/connected-accounts.md | 4 ++--
plugins/agentkit/references/connections.md | 12 ++++++------
.../skills/exposing-agentkit-via-mcp/SKILL.md | 8 ++++----
.../agentkit/skills/integrating-agentkit/SKILL.md | 8 ++++----
.../references/session-management-patterns.md | 4 ++--
8 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/plugins/agentkit/references/agent-connectors/README.md b/plugins/agentkit/references/agent-connectors/README.md
index 807653a..2a38c02 100644
--- a/plugins/agentkit/references/agent-connectors/README.md
+++ b/plugins/agentkit/references/agent-connectors/README.md
@@ -1,6 +1,6 @@
# Agent Connectors Reference
-This directory contains documentation for all supported agent connectors in the Scalekit Agent Auth platform.
+This directory contains documentation for all supported agent connectors in the Scalekit AgentKit platform.
## Available Connectors
@@ -61,7 +61,7 @@ Each connector documentation includes:
## Authentication
-Connectors support OAuth 2.0, API Key, or Basic Auth authentication through the Agent Auth platform. You'll need to:
+Connectors support OAuth 2.0, API Key, or Basic Auth authentication through the AgentKit platform. You'll need to:
1. Create a connection for the desired service
2. Configure OAuth credentials in your connection
diff --git a/plugins/agentkit/references/byoc.md b/plugins/agentkit/references/byoc.md
index b88d0f6..83460ac 100644
--- a/plugins/agentkit/references/byoc.md
+++ b/plugins/agentkit/references/byoc.md
@@ -1,6 +1,6 @@
# Bring Your Own Credentials
-Bring Your Own Credentials (BYOC) allows you to use your own OAuth applications and authentication credentials with Agent Auth instead of Scalekit's shared credentials. This provides complete control over the authentication experience and enables full whitelabeling of your application.
+Bring Your Own Credentials (BYOC) allows you to use your own OAuth applications and authentication credentials with AgentKit instead of Scalekit's shared credentials. This provides complete control over the authentication experience and enables full whitelabeling of your application.
## Why bring your own credentials?
@@ -33,7 +33,7 @@ With BYOC, authentication flows work as follows:
1. **Scalekit** handles the initial authentication request with your OAuth client-id details
2. **Provider** authenticates the user and returns tokens to Scalekit
-3. **Agent Auth** uses your tokens to execute tools on behalf of users
+3. **AgentKit** uses your tokens to execute tools on behalf of users
## Setting up BYOC
@@ -53,4 +53,4 @@ If you're currently using Scalekit's shared credentials and want to migrate to B
> - Rate limits and quotas will change to your application's limits
> - Some users may need to re-grant permissions
-By implementing BYOC, you gain complete control over your users' authentication experience while maintaining the power and flexibility of Agent Auth's unified API for tool execution.
+By implementing BYOC, you gain complete control over your users' authentication experience while maintaining the power and flexibility of AgentKit's unified API for tool execution.
diff --git a/plugins/agentkit/references/code-samples.md b/plugins/agentkit/references/code-samples.md
index 537ca57..81361aa 100644
--- a/plugins/agentkit/references/code-samples.md
+++ b/plugins/agentkit/references/code-samples.md
@@ -1,6 +1,6 @@
# Code Samples
-This reference provides implementation examples for integrating Scalekit Agent Auth across different frameworks, languages, and use cases.
+This reference provides implementation examples for integrating Scalekit AgentKit across different frameworks, languages, and use cases.
## Quick Start Guide
@@ -129,7 +129,7 @@ response = agent_executor.invoke({
### Repository: [scalekit-inc/google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example.git)
-**Overview:** Minimal Gmail-powered agent demonstrating Agent Auth integration with Google's Agent Development Kit. Entire integration fits in one file.
+**Overview:** Minimal Gmail-powered agent demonstrating AgentKit integration with Google's Agent Development Kit. Entire integration fits in one file.
**Requirements:**
- Python >= 3.11
diff --git a/plugins/agentkit/references/connected-accounts.md b/plugins/agentkit/references/connected-accounts.md
index c32f761..6aa7b9c 100644
--- a/plugins/agentkit/references/connected-accounts.md
+++ b/plugins/agentkit/references/connected-accounts.md
@@ -1,6 +1,6 @@
# Connected accounts
-Connected accounts in Agent Auth represent individual user or organization connections to third-party providers. They contain the authentication state, tokens, and permissions needed to execute tools on behalf of a specific identifier (user_id, org_id, or custom identifier).
+Connected accounts in AgentKit represent individual user or organization connections to third-party providers. They contain the authentication state, tokens, and permissions needed to execute tools on behalf of a specific identifier (user_id, org_id, or custom identifier).
## What are connected accounts?
@@ -51,7 +51,7 @@ F -> B
### Using the dashboard
-1. Navigate to connected accounts in your Agent Auth dashboard
+1. Navigate to connected accounts in your AgentKit dashboard
2. Click create account to start the process
3. Select connection to use for authentication
4. Enter identifier (user_id, email, or custom identifier)
diff --git a/plugins/agentkit/references/connections.md b/plugins/agentkit/references/connections.md
index 118dc1f..5f0ef42 100644
--- a/plugins/agentkit/references/connections.md
+++ b/plugins/agentkit/references/connections.md
@@ -1,6 +1,6 @@
# Connections
-Connections in Agent Auth are specific configurations that define how your application authenticates and interacts with third-party providers. Each connection contains the necessary credentials, settings, and parameters required to establish secure communication with a provider's API.
+Connections in AgentKit are specific configurations that define how your application authenticates and interacts with third-party providers. Each connection contains the necessary credentials, settings, and parameters required to establish secure communication with a provider's API.
## Table of Contents
@@ -18,7 +18,7 @@ Connections in Agent Auth are specific configurations that define how your appli
## What are connections?
-Connections serve as the bridge between your Agent Auth setup and third-party providers. They contain:
+Connections serve as the bridge between your AgentKit setup and third-party providers. They contain:
- **Authentication credentials** (OAuth client ID/secret, API keys, etc.)
- **Configuration settings** (scopes, permissions, endpoints)
@@ -28,7 +28,7 @@ Connections serve as the bridge between your Agent Auth setup and third-party pr
## Connection types
-Agent Auth supports various connection types based on different authentication methods:
+AgentKit supports various connection types based on different authentication methods:
### OAuth 2.0 connections
@@ -101,7 +101,7 @@ For providers with unique authentication requirements:
### Using the dashboard
-1. **Navigate to connections** in your Agent Auth dashboard
+1. **Navigate to connections** in your AgentKit dashboard
2. **Select provider** from the list of available providers
3. **Choose connection type** based on your authentication method
4. **Configure credentials** by entering your API keys or OAuth settings
@@ -111,7 +111,7 @@ For providers with unique authentication requirements:
### Using the API
-Create connections programmatically using the Agent Auth API:
+Create connections programmatically using the AgentKit API:
**cURL:**
@@ -427,7 +427,7 @@ Use templates for common connection patterns:
}
```
-Next, learn how to create and manage [Connected accounts](/agent-auth/connected-accounts) that use these connections to authenticate and execute tools for your users.
+Next, learn how to create and manage [Connected accounts](connected-accounts.md) that use these connections to authenticate and execute tools for your users.
## Related documentation
diff --git a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
index 20b19e6..5c54742 100644
--- a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
+++ b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
@@ -7,9 +7,9 @@ description: Guides developers through creating a Scalekit MCP server with authe
Scalekit lets you build MCP servers that manage authentication, create personalized access URLs for users, and define which tools are accessible. You can also bundle several toolkits (e.g., Gmail + Google Calendar) within a single server.
-[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open-source standard that enables AI systems to interface with external tools and data sources. Where the `integrating-agent-auth` skill uses the SDK directly, this workflow exposes Scalekit tools over the MCP protocol so any compliant client — LangChain, Claude Desktop, MCP Inspector — can consume them.
+[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open-source standard that enables AI systems to interface with external tools and data sources. Where the `integrating-agentkit` skill uses the SDK directly, this workflow exposes Scalekit tools over the MCP protocol so any compliant client — LangChain, Claude Desktop, MCP Inspector — can consume them.
-> **Note:** Agent Auth MCP servers only support Streamable HTTP transport.
+> **Note:** AgentKit MCP servers only support Streamable HTTP transport.
## What you'll build
@@ -23,12 +23,12 @@ Scalekit lets you build MCP servers that manage authentication, create personali
> **Gmail is the only connector that does not require dashboard setup.** All other connectors (including Google Calendar) must be created in the Scalekit Dashboard before use:
>
-> Go to **Scalekit Dashboard → Agent Auth → Connections → + Create Connection → Select connector** → Set `Connection Name` → Save
+> Go to **Scalekit Dashboard → AgentKit → Connections → + Create Connection → Select connector** → Set `Connection Name` → Save
> **Important**: The **Connection Name** you set in the dashboard is exactly what you use as the `connection_name` parameter in your code. They must match exactly.
For this example, create the Google Calendar connector:
-- [ ] **Google Calendar connector**: Scalekit Dashboard → Agent Auth → Connections → Create Connection → Google Calendar → `Connection Name = MY_CALENDAR` → Save
+- [ ] **Google Calendar connector**: Scalekit Dashboard → AgentKit → Connections → Create Connection → Google Calendar → `Connection Name = MY_CALENDAR` → Save
## Step 1 — Set up your environment
diff --git a/plugins/agentkit/skills/integrating-agentkit/SKILL.md b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
index 7c37bdd..facd3c1 100644
--- a/plugins/agentkit/skills/integrating-agentkit/SKILL.md
+++ b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
@@ -3,7 +3,7 @@ name: integrating-agentkit
description: Integrates Scalekit AgentKit into a project to handle OAuth flows, token storage, and automatic refresh for third-party connectors (Gmail, Slack, Notion, Calendar, and 40+ more). Use when a user needs to connect to an external service, authorize OAuth access, fetch access or refresh tokens, execute API calls on behalf of a user, or build agents with LangChain or Google ADK.
---
-# Agent Auth Integration
+# AgentKit Integration
Scalekit handles the full OAuth lifecycle — authorization, token storage, and refresh — so agents can act on behalf of users in Gmail, Slack, Notion, Calendar, and other connectors.
@@ -16,7 +16,7 @@ Install the SDK and initialize the client:
> **Important**: Except for Gmail, all connectors must be configured in the Scalekit Dashboard first before creating authorization URLs.
>
-> To set up a connector: **Scalekit Dashboard → Agent Auth → Connections → + Create Connection → Select connector → Set Connection Name → Save**
+> To set up a connector: **Scalekit Dashboard → AgentKit → Connections → + Create Connection → Select connector → Set Connection Name → Save**
@@ -63,7 +63,7 @@ Before integrating with a connector, follow these steps in the Scalekit Dashboar
For all other connectors (Slack, Notion, Google Calendar, etc.):
-1. Go to **Scalekit Dashboard → Agent Auth → Connections**
+1. Go to **Scalekit Dashboard → AgentKit → Connections**
2. Click **+ Create Connection**
3. Select the connector you want to use
4. Enter a **Connection Name** (e.g., `MY_SLACK`, `MY_NOTION`)
@@ -83,7 +83,7 @@ For all other connectors (Slack, Notion, Google Calendar, etc.):
Copy this checklist and check off steps as you complete them:
```
-Agent Auth Integration Progress:
+AgentKit Integration Progress:
- [ ] Step 1: SDK installed and client initialized
- [ ] Step 2: Connected account created for the user
- [ ] Step 3: User has authorized the connection (status = ACTIVE)
diff --git a/plugins/saaskit/references/session-management-patterns.md b/plugins/saaskit/references/session-management-patterns.md
index 228a5d0..6421c8a 100644
--- a/plugins/saaskit/references/session-management-patterns.md
+++ b/plugins/saaskit/references/session-management-patterns.md
@@ -1,6 +1,6 @@
# Session Management Patterns
-Reference guide for evaluating and implementing session management with Scalekit. Covers audit checklists, implementation options (FSA, Modular SSO, Remote API, Agent Auth), and code patterns.
+Reference guide for evaluating and implementing session management with Scalekit. Covers audit checklists, implementation options (FSA, Modular SSO, Remote API, AgentKit), and code patterns.
Related references:
- [scalekit-user-profiles.md](scalekit-user-profiles.md) — attribute schema and SDK methods
@@ -210,7 +210,7 @@ await scalekit.sessions.revokeAll({ userId: req.user.id });
---
-### Option D: Agent Auth — Token Vault for AI Agent Scenarios
+### Option D: AgentKit — Token Vault for AI Agent Scenarios
**Best for:** AI apps where agents make API calls on behalf of users to third-party services.
```typescript
From 36ad3d9e95382fcd379936dfc815ca2b8d9e1bf8 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 18:07:21 +0530
Subject: [PATCH 10/39] Add Codex CLI check warning to install script
---
scripts/install.sh | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/install.sh b/scripts/install.sh
index a4da0bf..748b0b5 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -2,6 +2,12 @@
set -euo pipefail
+if ! command -v codex >/dev/null 2>&1; then
+ echo "Warning: Codex CLI is not installed or not on PATH." >&2
+ echo "The plugins will be copied, but you will need Codex to use them." >&2
+ echo
+fi
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
From e596e192d50f242b308f14eed4969667b235771e Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 18:08:52 +0530
Subject: [PATCH 11/39] Add usage beacon hooks to both plugins
- Add hooks/hooks.json and hooks/beacon.sh to agentkit and saaskit
- Beacon sends plugin_used event to PostHog on session stop
- Update AGENTS.md to reflect hooks support
---
AGENTS.md | 2 +-
plugins/agentkit/hooks/beacon.sh | 20 ++++++++++++++++++++
plugins/agentkit/hooks/hooks.json | 16 ++++++++++++++++
plugins/saaskit/hooks/beacon.sh | 20 ++++++++++++++++++++
plugins/saaskit/hooks/hooks.json | 16 ++++++++++++++++
5 files changed, 73 insertions(+), 1 deletion(-)
create mode 100755 plugins/agentkit/hooks/beacon.sh
create mode 100644 plugins/agentkit/hooks/hooks.json
create mode 100755 plugins/saaskit/hooks/beacon.sh
create mode 100644 plugins/saaskit/hooks/hooks.json
diff --git a/AGENTS.md b/AGENTS.md
index d5b1143..e9abc86 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -79,7 +79,7 @@ Codex plugins differ from Claude Code and Cursor plugins:
- **No `.claude-plugin/` or `.cursor-plugin/` directory.** Codex uses `~/.agents/plugins/marketplace.json` to discover marketplaces.
- **No rules (`.mdc` files).** Codex does not support Cursor-style rules. Use skill content and references instead.
- **No agents.** Codex does not support sub-agent definitions. Guidance that would be an agent in other auth stacks should be a skill or reference doc here.
-- **No hooks.** Codex does not support lifecycle hooks.
+- **Hooks.** Codex supports `hooks.json` for lifecycle hooks. Both plugins include a usage beacon hook.
- **No commands.** Codex does not support slash commands. Skills are the only entrypoint.
## Skill authoring rules
diff --git a/plugins/agentkit/hooks/beacon.sh b/plugins/agentkit/hooks/beacon.sh
new file mode 100755
index 0000000..eee1202
--- /dev/null
+++ b/plugins/agentkit/hooks/beacon.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+PLUGIN="${1:-unknown}"
+HOOK="${2:-stop}"
+INPUT=$(cat)
+
+SESSION_ID=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('session_id','anonymous'))" \
+ 2>/dev/null || echo "anonymous")
+
+TOOL_NAME=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" \
+ 2>/dev/null || echo "")
+
+curl -s -o /dev/null --max-time 5 \
+ -X POST https://ph.scalekit.com/i/v0/e/ \
+ -H "Content-Type: application/json" \
+ -d "{\"token\":\"phc_85pLP8gwYvRCQdxgLQP24iqXHPRGaLgEw4S4dgZHJZ\",\
+\"event\":\"plugin_used\",\
+\"distinct_id\":\"${SESSION_ID}\",\
+\"properties\":{\"plugin\":\"${PLUGIN}\",\"coding_agent\":\"codex\",\"hook\":\"${HOOK}\",\"tool_name\":\"${TOOL_NAME}\"}}"
diff --git a/plugins/agentkit/hooks/hooks.json b/plugins/agentkit/hooks/hooks.json
new file mode 100644
index 0000000..5c173a7
--- /dev/null
+++ b/plugins/agentkit/hooks/hooks.json
@@ -0,0 +1,16 @@
+{
+ "description": "Usage beacon for Scalekit agentkit plugin",
+ "hooks": {
+ "Stop": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "${CODEX_PLUGIN_ROOT}/hooks/beacon.sh agentkit stop",
+ "timeout": 10
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/plugins/saaskit/hooks/beacon.sh b/plugins/saaskit/hooks/beacon.sh
new file mode 100755
index 0000000..eee1202
--- /dev/null
+++ b/plugins/saaskit/hooks/beacon.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+PLUGIN="${1:-unknown}"
+HOOK="${2:-stop}"
+INPUT=$(cat)
+
+SESSION_ID=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('session_id','anonymous'))" \
+ 2>/dev/null || echo "anonymous")
+
+TOOL_NAME=$(echo "$INPUT" | python3 -c \
+ "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" \
+ 2>/dev/null || echo "")
+
+curl -s -o /dev/null --max-time 5 \
+ -X POST https://ph.scalekit.com/i/v0/e/ \
+ -H "Content-Type: application/json" \
+ -d "{\"token\":\"phc_85pLP8gwYvRCQdxgLQP24iqXHPRGaLgEw4S4dgZHJZ\",\
+\"event\":\"plugin_used\",\
+\"distinct_id\":\"${SESSION_ID}\",\
+\"properties\":{\"plugin\":\"${PLUGIN}\",\"coding_agent\":\"codex\",\"hook\":\"${HOOK}\",\"tool_name\":\"${TOOL_NAME}\"}}"
diff --git a/plugins/saaskit/hooks/hooks.json b/plugins/saaskit/hooks/hooks.json
new file mode 100644
index 0000000..a354231
--- /dev/null
+++ b/plugins/saaskit/hooks/hooks.json
@@ -0,0 +1,16 @@
+{
+ "description": "Usage beacon for Scalekit saaskit plugin",
+ "hooks": {
+ "Stop": [
+ {
+ "hooks": [
+ {
+ "type": "command",
+ "command": "${CODEX_PLUGIN_ROOT}/hooks/beacon.sh saaskit stop",
+ "timeout": 10
+ }
+ ]
+ }
+ ]
+ }
+}
From 85f90fd885065186c5bf05307c1531f23f3aa39f Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 18:11:20 +0530
Subject: [PATCH 12/39] Fix hooks for Codex format and add hooks to plugin
manifests
- Remove non-existent CODEX_PLUGIN_ROOT variable, use relative path
- Remove extra description field from hooks.json
- Add hooks field to both plugin.json manifests
---
plugins/agentkit/.codex-plugin/plugin.json | 1 +
plugins/agentkit/hooks/hooks.json | 3 +--
plugins/saaskit/.codex-plugin/plugin.json | 1 +
plugins/saaskit/hooks/hooks.json | 3 +--
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/plugins/agentkit/.codex-plugin/plugin.json b/plugins/agentkit/.codex-plugin/plugin.json
index 62612d8..0f71ec1 100644
--- a/plugins/agentkit/.codex-plugin/plugin.json
+++ b/plugins/agentkit/.codex-plugin/plugin.json
@@ -13,6 +13,7 @@
"keywords": ["scalekit", "agentkit", "agent-auth", "oauth", "connectors", "tool-calling"],
"skills": "./skills/",
"mcpServers": "./.mcp.json",
+ "hooks": "./hooks/hooks.json",
"interface": {
"displayName": "AgentKit",
"shortDescription": "Connect agents to third-party apps safely.",
diff --git a/plugins/agentkit/hooks/hooks.json b/plugins/agentkit/hooks/hooks.json
index 5c173a7..361d51d 100644
--- a/plugins/agentkit/hooks/hooks.json
+++ b/plugins/agentkit/hooks/hooks.json
@@ -1,12 +1,11 @@
{
- "description": "Usage beacon for Scalekit agentkit plugin",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
- "command": "${CODEX_PLUGIN_ROOT}/hooks/beacon.sh agentkit stop",
+ "command": "./hooks/beacon.sh agentkit stop",
"timeout": 10
}
]
diff --git a/plugins/saaskit/.codex-plugin/plugin.json b/plugins/saaskit/.codex-plugin/plugin.json
index 8bd3432..82e4c9b 100644
--- a/plugins/saaskit/.codex-plugin/plugin.json
+++ b/plugins/saaskit/.codex-plugin/plugin.json
@@ -13,6 +13,7 @@
"keywords": ["scalekit", "saaskit", "authentication", "sso", "scim", "mcp-auth", "sessions"],
"skills": "./skills/",
"mcpServers": "./.mcp.json",
+ "hooks": "./hooks/hooks.json",
"interface": {
"displayName": "SaaSKit",
"shortDescription": "Production-ready B2B SaaS authentication.",
diff --git a/plugins/saaskit/hooks/hooks.json b/plugins/saaskit/hooks/hooks.json
index a354231..0b35607 100644
--- a/plugins/saaskit/hooks/hooks.json
+++ b/plugins/saaskit/hooks/hooks.json
@@ -1,12 +1,11 @@
{
- "description": "Usage beacon for Scalekit saaskit plugin",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
- "command": "${CODEX_PLUGIN_ROOT}/hooks/beacon.sh saaskit stop",
+ "command": "./hooks/beacon.sh saaskit stop",
"timeout": 10
}
]
From 749642214fe9be23913b8d8620c7bc118ca45462 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 18:14:56 +0530
Subject: [PATCH 13/39] Make bootstrap installer resilient to missing execute
bit in tarball
---
install.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/install.sh b/install.sh
index dc4c90d..31c382a 100755
--- a/install.sh
+++ b/install.sh
@@ -27,9 +27,10 @@ tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR"
EXTRACTED_DIR="$(find "$TMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
-if [[ -z "$EXTRACTED_DIR" ]] || [[ ! -x "$EXTRACTED_DIR/scripts/install.sh" ]]; then
+if [[ -z "$EXTRACTED_DIR" ]] || [[ ! -f "$EXTRACTED_DIR/scripts/install.sh" ]]; then
echo "Failed to find installer in downloaded archive." >&2
exit 1
fi
+chmod +x "$EXTRACTED_DIR/scripts/install.sh"
exec "$EXTRACTED_DIR/scripts/install.sh"
From 7f8f40bb499c84cd2eaf7b2af0461da8ea092043 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 18:40:06 +0530
Subject: [PATCH 14/39] Add hooks enable and MCP login instructions to
post-install output
---
scripts/install.sh | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/scripts/install.sh b/scripts/install.sh
index 748b0b5..b77a07d 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -167,3 +167,15 @@ If you intentionally want this installer to replace your personal marketplace fi
FORCE_PERSONAL_MARKETPLACE=1 ./scripts/install.sh
EOF
fi
+
+cat <<'EOF'
+
+Optional setup:
+
+ To enable lifecycle hooks, add this to your Codex config.toml:
+ [features]
+ codex_hooks = true
+
+ To authenticate the Scalekit MCP server for Codex CLI:
+ codex mcp login scalekit
+EOF
From b11ff21d0a4c6ec3d7ba126c42acb089ff20d68e Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Wed, 13 May 2026 20:58:42 +0530
Subject: [PATCH 15/39] Remove agent-connectors directory, point to live docs
instead
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Per-connector docs are unmaintainable — live AgentKit metadata and
docs.scalekit.com/agentkit/connectors/ are the source of truth.
---
AGENTS.md | 2 +-
.../references/agent-connectors/README.md | 71 ----
.../references/agent-connectors/airtable.md | 3 -
.../references/agent-connectors/asana.md | 3 -
.../references/agent-connectors/attention.md | 3 -
.../references/agent-connectors/bigquery.md | 3 -
.../references/agent-connectors/chorus.md | 3 -
.../agent-connectors/clari_copilot.md | 3 -
.../references/agent-connectors/clickup.md | 3 -
.../references/agent-connectors/confluence.md | 3 -
.../references/agent-connectors/dropbox.md | 3 -
.../references/agent-connectors/fathom.md | 3 -
.../references/agent-connectors/freshdesk.md | 149 ---------
.../references/agent-connectors/github.md | 137 --------
.../references/agent-connectors/gmail.md | 79 -----
.../references/agent-connectors/gong.md | 3 -
.../references/agent-connectors/google_ads.md | 3 -
.../agent-connectors/google_docs.md | 3 -
.../agent-connectors/google_drive.md | 3 -
.../agent-connectors/google_forms.md | 3 -
.../agent-connectors/google_meets.md | 3 -
.../agent-connectors/google_sheets.md | 3 -
.../agent-connectors/google_slides.md | 32 --
.../agent-connectors/googlecalendar.md | 128 -------
.../references/agent-connectors/hubspot.md | 143 --------
.../references/agent-connectors/intercom.md | 3 -
.../references/agent-connectors/jira.md | 3 -
.../references/agent-connectors/linear.md | 58 ----
.../agent-connectors/microsoft_excel.md | 3 -
.../agent-connectors/microsoft_teams.md | 3 -
.../agent-connectors/microsoft_word.md | 3 -
.../references/agent-connectors/monday.md | 3 -
.../references/agent-connectors/notion.md | 189 -----------
.../references/agent-connectors/onedrive.md | 3 -
.../references/agent-connectors/onenote.md | 3 -
.../references/agent-connectors/outlook.md | 3 -
.../references/agent-connectors/salesforce.md | 316 ------------------
.../references/agent-connectors/servicenow.md | 3 -
.../references/agent-connectors/sharepoint.md | 3 -
.../references/agent-connectors/slack.md | 197 -----------
.../references/agent-connectors/snowflake.md | 3 -
.../references/agent-connectors/trello.md | 3 -
.../references/agent-connectors/zendesk.md | 3 -
.../references/agent-connectors/zoom.md | 3 -
plugins/agentkit/references/connectors.md | 4 +-
plugins/agentkit/references/tool-discovery.md | 2 +-
.../discovering-connector-tools/SKILL.md | 2 +-
.../skills/integrating-agentkit/SKILL.md | 2 +-
48 files changed, 6 insertions(+), 1601 deletions(-)
delete mode 100644 plugins/agentkit/references/agent-connectors/README.md
delete mode 100644 plugins/agentkit/references/agent-connectors/airtable.md
delete mode 100644 plugins/agentkit/references/agent-connectors/asana.md
delete mode 100644 plugins/agentkit/references/agent-connectors/attention.md
delete mode 100644 plugins/agentkit/references/agent-connectors/bigquery.md
delete mode 100644 plugins/agentkit/references/agent-connectors/chorus.md
delete mode 100644 plugins/agentkit/references/agent-connectors/clari_copilot.md
delete mode 100644 plugins/agentkit/references/agent-connectors/clickup.md
delete mode 100644 plugins/agentkit/references/agent-connectors/confluence.md
delete mode 100644 plugins/agentkit/references/agent-connectors/dropbox.md
delete mode 100644 plugins/agentkit/references/agent-connectors/fathom.md
delete mode 100644 plugins/agentkit/references/agent-connectors/freshdesk.md
delete mode 100644 plugins/agentkit/references/agent-connectors/github.md
delete mode 100644 plugins/agentkit/references/agent-connectors/gmail.md
delete mode 100644 plugins/agentkit/references/agent-connectors/gong.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_ads.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_docs.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_drive.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_forms.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_meets.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_sheets.md
delete mode 100644 plugins/agentkit/references/agent-connectors/google_slides.md
delete mode 100644 plugins/agentkit/references/agent-connectors/googlecalendar.md
delete mode 100644 plugins/agentkit/references/agent-connectors/hubspot.md
delete mode 100644 plugins/agentkit/references/agent-connectors/intercom.md
delete mode 100644 plugins/agentkit/references/agent-connectors/jira.md
delete mode 100644 plugins/agentkit/references/agent-connectors/linear.md
delete mode 100644 plugins/agentkit/references/agent-connectors/microsoft_excel.md
delete mode 100644 plugins/agentkit/references/agent-connectors/microsoft_teams.md
delete mode 100644 plugins/agentkit/references/agent-connectors/microsoft_word.md
delete mode 100644 plugins/agentkit/references/agent-connectors/monday.md
delete mode 100644 plugins/agentkit/references/agent-connectors/notion.md
delete mode 100644 plugins/agentkit/references/agent-connectors/onedrive.md
delete mode 100644 plugins/agentkit/references/agent-connectors/onenote.md
delete mode 100644 plugins/agentkit/references/agent-connectors/outlook.md
delete mode 100644 plugins/agentkit/references/agent-connectors/salesforce.md
delete mode 100644 plugins/agentkit/references/agent-connectors/servicenow.md
delete mode 100644 plugins/agentkit/references/agent-connectors/sharepoint.md
delete mode 100644 plugins/agentkit/references/agent-connectors/slack.md
delete mode 100644 plugins/agentkit/references/agent-connectors/snowflake.md
delete mode 100644 plugins/agentkit/references/agent-connectors/trello.md
delete mode 100644 plugins/agentkit/references/agent-connectors/zendesk.md
delete mode 100644 plugins/agentkit/references/agent-connectors/zoom.md
diff --git a/AGENTS.md b/AGENTS.md
index e9abc86..328f989 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -42,7 +42,7 @@ Skills:
- `exposing-agentkit-via-mcp` — expose AgentKit tools through MCP for compatible runtimes
- `production-readiness-agentkit` — production readiness checklist for AgentKit integrations
-References: `agent-connectors/` (connector docs), `connected-accounts.md`, `code-samples.md`, `connectors.md`, `connections.md`, `byoc.md`, `redirects.md`, `tool-discovery.md`
+References: `connected-accounts.md`, `code-samples.md`, `connectors.md`, `connections.md`, `byoc.md`, `redirects.md`, `tool-discovery.md`
### saaskit
diff --git a/plugins/agentkit/references/agent-connectors/README.md b/plugins/agentkit/references/agent-connectors/README.md
deleted file mode 100644
index 2a38c02..0000000
--- a/plugins/agentkit/references/agent-connectors/README.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Agent Connectors Reference
-
-This directory contains documentation for all supported agent connectors in the Scalekit AgentKit platform.
-
-## Available Connectors
-
-| Connector | Description | Auth Type |
-|-----------|-------------|-----------|
-| [Airtable](airtable.md) | Connect to Airtable bases for data management | OAuth 2.0 |
-| [Asana](asana.md) | Project management and task tracking | OAuth 2.0 |
-| [Attention](attention.md) | AI insights, conversations, teams, and workflows | API Key |
-| [BigQuery](bigquery.md) | Google BigQuery data warehouse | OAuth 2.0 |
-| [Chorus](chorus.md) | Sync calls, transcripts, conversation intelligence, and analytics | Basic Auth |
-| [Clari Copilot](clari_copilot.md) | Sales call transcripts, analytics, call data, and insights | API Key |
-| [ClickUp](clickup.md) | Project management and collaboration | OAuth 2.0 |
-| [Confluence](confluence.md) | Atlassian Confluence wiki pages | OAuth 2.0 |
-| [Dropbox](dropbox.md) | File storage and sharing | OAuth 2.0 |
-| [Fathom](fathom.md) | Website analytics | OAuth 2.0 |
-| [Freshdesk](freshdesk.md) | Customer support ticketing | OAuth 2.0 |
-| [GitHub](github.md) | Code repository and development tools | OAuth 2.0 |
-| [Gmail](gmail.md) | Google Gmail email service | OAuth 2.0 |
-| [Google Ads](google_ads.md) | Google advertising platform | OAuth 2.0 |
-| [Google Calendar](googlecalendar.md) | Google Calendar events and scheduling | OAuth 2.0 |
-| [Google Docs](google_docs.md) | Google Docs document editing | OAuth 2.0 |
-| [Google Drive](google_drive.md) | Google Drive file storage | OAuth 2.0 |
-| [Google Forms](google_forms.md) | Google Forms survey creation | OAuth 2.0 |
-| [Google Meet](google_meets.md) | Google Meet video conferencing | OAuth 2.0 |
-| [Google Sheets](google_sheets.md) | Google Sheets spreadsheet editing | OAuth 2.0 |
-| [Google Slides](google_slides.md) | Create, read, and modify presentations programmatically | OAuth 2.0 |
-| [Gong](gong.md) | Sales conversation intelligence | OAuth 2.0 |
-| [HubSpot](hubspot.md) | CRM and marketing automation | OAuth 2.0 |
-| [Intercom](intercom.md) | Customer messaging platform | OAuth 2.0 |
-| [Jira](jira.md) | Atlassian Jira issue tracking | OAuth 2.0 |
-| [Linear](linear.md) | Software development issue tracking | OAuth 2.0 |
-| [Microsoft Excel](microsoft_excel.md) | Microsoft Excel spreadsheet editing | OAuth 2.0 |
-| [Microsoft Teams](microsoft_teams.md) | Microsoft Teams collaboration | OAuth 2.0 |
-| [Microsoft Word](microsoft_word.md) | Microsoft Word document editing | OAuth 2.0 |
-| [Monday](monday.md) | Work management platform | OAuth 2.0 |
-| [Notion](notion.md) | Notion workspace and pages | OAuth 2.0 |
-| [OneDrive](onedrive.md) | Microsoft OneDrive file storage | OAuth 2.0 |
-| [OneNote](onenote.md) | Microsoft OneNote note-taking | OAuth 2.0 |
-| [Outlook](outlook.md) | Microsoft Outlook email | OAuth 2.0 |
-| [Salesforce](salesforce.md) | Salesforce CRM platform | OAuth 2.0 |
-| [ServiceNow](servicenow.md) | IT service management | OAuth 2.0 |
-| [SharePoint](sharepoint.md) | Microsoft SharePoint collaboration | OAuth 2.0 |
-| [Slack](slack.md) | Slack messaging and collaboration | OAuth 2.0 |
-| [Snowflake](snowflake.md) | Snowflake data warehouse | OAuth 2.0 |
-| [Trello](trello.md) | Trello project boards | OAuth 2.0 |
-| [Zendesk](zendesk.md) | Customer support platform | OAuth 2.0 |
-| [Zoom](zoom.md) | Zoom video conferencing | OAuth 2.0 |
-
-## Getting Started
-
-Each connector documentation includes:
-
-- Service description and capabilities
-- Authentication requirements
-- Complete API reference for all available tools
-- Parameter specifications and examples
-- Usage guidelines and best practices
-
-## Authentication
-
-Connectors support OAuth 2.0, API Key, or Basic Auth authentication through the AgentKit platform. You'll need to:
-
-1. Create a connection for the desired service
-2. Configure OAuth credentials in your connection
-3. Create connected accounts for your users
-4. Use the connection in your agent workflows
-
-For detailed authentication setup, see the [Connected Accounts](../connected-accounts.md) documentation.
\ No newline at end of file
diff --git a/plugins/agentkit/references/agent-connectors/airtable.md b/plugins/agentkit/references/agent-connectors/airtable.md
deleted file mode 100644
index f3acf0b..0000000
--- a/plugins/agentkit/references/agent-connectors/airtable.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Airtable. Manage databases, tables, records, and collaborate on structured data
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/asana.md b/plugins/agentkit/references/agent-connectors/asana.md
deleted file mode 100644
index cea2fc7..0000000
--- a/plugins/agentkit/references/agent-connectors/asana.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Asana. Manage tasks, projects, teams, and workflow automation
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/attention.md b/plugins/agentkit/references/agent-connectors/attention.md
deleted file mode 100644
index 9af975e..0000000
--- a/plugins/agentkit/references/agent-connectors/attention.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Attention for AI insights, conversations, teams, and workflows
-
-Supports authentication: API Key
diff --git a/plugins/agentkit/references/agent-connectors/bigquery.md b/plugins/agentkit/references/agent-connectors/bigquery.md
deleted file mode 100644
index 64b8a33..0000000
--- a/plugins/agentkit/references/agent-connectors/bigquery.md
+++ /dev/null
@@ -1,3 +0,0 @@
-BigQuery is Google Cloud’s fully-managed enterprise data warehouse for analytics at scale.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/chorus.md b/plugins/agentkit/references/agent-connectors/chorus.md
deleted file mode 100644
index b57dd23..0000000
--- a/plugins/agentkit/references/agent-connectors/chorus.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Chorus.ai to sync calls, transcripts, conversation intelligence, and analytics.
-
-Supports authentication: Basic Auth
diff --git a/plugins/agentkit/references/agent-connectors/clari_copilot.md b/plugins/agentkit/references/agent-connectors/clari_copilot.md
deleted file mode 100644
index 2949e94..0000000
--- a/plugins/agentkit/references/agent-connectors/clari_copilot.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Clari Copilot for sales call transcripts, analytics, call data, and insights.
-
-Supports authentication: API Key
diff --git a/plugins/agentkit/references/agent-connectors/clickup.md b/plugins/agentkit/references/agent-connectors/clickup.md
deleted file mode 100644
index dd7d216..0000000
--- a/plugins/agentkit/references/agent-connectors/clickup.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to ClickUp. Manage tasks, projects, workspaces, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/confluence.md b/plugins/agentkit/references/agent-connectors/confluence.md
deleted file mode 100644
index 96d699f..0000000
--- a/plugins/agentkit/references/agent-connectors/confluence.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Confluence. Manage spaces, pages, content, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/dropbox.md b/plugins/agentkit/references/agent-connectors/dropbox.md
deleted file mode 100644
index 1bfe1d3..0000000
--- a/plugins/agentkit/references/agent-connectors/dropbox.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Dropbox. Manage files, folders, sharing, and cloud storage workflows
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/fathom.md b/plugins/agentkit/references/agent-connectors/fathom.md
deleted file mode 100644
index 3408c98..0000000
--- a/plugins/agentkit/references/agent-connectors/fathom.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Fathom AI meeting assistant. Record, transcribe, and summarize meetings with AI-powered insights
-
-Supports authentication: API Key
diff --git a/plugins/agentkit/references/agent-connectors/freshdesk.md b/plugins/agentkit/references/agent-connectors/freshdesk.md
deleted file mode 100644
index 424a753..0000000
--- a/plugins/agentkit/references/agent-connectors/freshdesk.md
+++ /dev/null
@@ -1,149 +0,0 @@
-Connect to Freshdesk. Manage tickets, contacts, companies, and customer support workflows
-
-Supports authentication: Basic Auth
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `freshdesk_agent_create`
-
-Create a new agent in Freshdesk. Email is required and must be unique. Agent will receive invitation email to set up account. At least one role must be assigned.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `agent_type` | Type of agent (1=Support Agent, 2=Field Agent, 3=Collaborator) | number | null |
-| `email` | Email address of the agent (must be unique) | string |
-| `focus_mode` | Focus mode setting for the agent | boolean | null |
-| `group_ids` | Array of group IDs to assign the agent to | `array` | null |
-| `language` | Language preference of the agent | string | null |
-| `name` | Full name of the agent | string | null |
-| `occasional` | Whether the agent is occasional (true) or full-time (false) | boolean | null |
-| `role_ids` | Array of role IDs to assign to the agent (at least one required) | `array` |
-| `signature` | Agent email signature in HTML format | string | null |
-| `skill_ids` | Array of skill IDs to assign to the agent | `array` | null |
-| `ticket_scope` | Ticket permission level (1=Global Access, 2=Group Access, 3=Restricted Access) | number |
-| `time_zone` | Time zone of the agent | string | null |
-
-## `freshdesk_agent_delete`
-
-Delete an agent from Freshdesk. This action is irreversible and will remove the agent from the system. The agent will no longer have access to the helpdesk and all associated data will be permanently deleted.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `agent_id` | ID of the agent to delete | number |
-
-## `freshdesk_agents_list`
-
-Retrieve a list of agents from Freshdesk with filtering options. Returns agent details including IDs, contact information, roles, and availability status. Supports pagination with up to 100 agents per page.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `email` | Filter agents by email address | string | null |
-| `mobile` | Filter agents by mobile number | string | null |
-| `page` | Page number for pagination (starts from 1) | number | null |
-| `per_page` | Number of agents per page (max 100) | number | null |
-| `phone` | Filter agents by phone number | string | null |
-| `state` | Filter agents by state (fulltime or occasional) | string | null |
-
-## `freshdesk_contact_create`
-
-Create a new contact in Freshdesk. Email and name are required. Supports custom fields, company assignment, and contact segmentation.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `address` | Address of the contact | string | null |
-| `company_id` | Company ID to associate with the contact | number | null |
-| `custom_fields` | Key-value pairs for custom field values | `object` | null |
-| `description` | Description about the contact | string | null |
-| `email` | Email address of the contact | string |
-| `job_title` | Job title of the contact | string | null |
-| `language` | Language preference of the contact | string | null |
-| `mobile` | Mobile number of the contact | string | null |
-| `name` | Full name of the contact | string |
-| `phone` | Phone number of the contact | string | null |
-| `tags` | Array of tags to associate with the contact | `array` | null |
-| `time_zone` | Time zone of the contact | string | null |
-
-## `freshdesk_roles_list`
-
-Retrieve a list of all roles from Freshdesk. Returns role details including IDs, names, descriptions, default status, and timestamps. This endpoint provides information about the different permission levels and access controls available in the Freshdesk system.
-
-## `freshdesk_ticket_create`
-
-Create a new ticket in Freshdesk. Requires either requester_id, email, facebook_id, phone, twitter_id, or unique_external_id to identify the requester.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `cc_emails` | Array of email addresses to be added in CC | `array` | null |
-| `custom_fields` | Key-value pairs containing custom field names and values | `object` | null |
-| `description` | HTML content of the ticket describing the issue | string | null |
-| `email` | Email address of the requester. If no contact exists, will be added as new contact. | string | null |
-| `group_id` | ID of the group to which the ticket has been assigned | number | null |
-| `name` | Name of the requester | string | null |
-| `priority` | Priority of the ticket. 1=Low, 2=Medium, 3=High, 4=Urgent | number | null |
-| `requester_id` | User ID of the requester. For existing contacts, can be passed instead of email. | number | null |
-| `responder_id` | ID of the agent to whom the ticket has been assigned | number | null |
-| `source` | Channel through which ticket was created. 1=Email, 2=Portal, 3=Phone, 7=Chat, 9=Feedback Widget, 10=Outbound Email | number | null |
-| `status` | Status of the ticket. 2=Open, 3=Pending, 4=Resolved, 5=Closed | number | null |
-| `subject` | Subject of the ticket | string | null |
-| `tags` | Array of tags to be associated with the ticket | `array` | null |
-| `type` | Helps categorize the ticket according to different kinds of issues | string | null |
-
-## `freshdesk_ticket_get`
-
-Retrieve details of a specific ticket by ID. Includes ticket properties, conversations, and metadata.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `include` | Additional resources to include (stats, requester, company, conversations) | string | null |
-| `ticket_id` | ID of the ticket to retrieve | number |
-
-## `freshdesk_ticket_update`
-
-Update an existing ticket in Freshdesk. Note: Subject and description of outbound tickets cannot be updated.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `custom_fields` | Key-value pairs containing custom field names and values | `object` | null |
-| `description` | HTML content of the ticket (cannot be updated for outbound tickets) | string | null |
-| `group_id` | ID of the group to which the ticket has been assigned | number | null |
-| `name` | Name of the requester | string | null |
-| `priority` | Priority of the ticket. 1=Low, 2=Medium, 3=High, 4=Urgent | number | null |
-| `responder_id` | ID of the agent to whom the ticket has been assigned | number | null |
-| `status` | Status of the ticket. 2=Open, 3=Pending, 4=Resolved, 5=Closed | number | null |
-| `subject` | Subject of the ticket (cannot be updated for outbound tickets) | string | null |
-| `tags` | Array of tags to be associated with the ticket | `array` | null |
-| `ticket_id` | ID of the ticket to update | number |
-
-## `freshdesk_tickets_list`
-
-Retrieve a list of tickets with filtering and pagination. Supports filtering by status, priority, requester, and more. Returns 30 tickets per page by default.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company_id` | Filter by company ID | number | null |
-| `email` | Filter by requester email | string | null |
-| `filter` | Filter name (new_and_my_open, watching, spam, deleted) | string | null |
-| `include` | Additional resources to include (description, requester, company, stats) | string | null |
-| `page` | Page number for pagination (starts from 1) | number | null |
-| `per_page` | Number of tickets per page (max 100) | number | null |
-| `requester_id` | Filter by requester ID | number | null |
-| `updated_since` | Filter tickets updated since this timestamp (ISO 8601) | string | null |
-
-## `freshdesk_tickets_reply`
-
-Add a public reply to a ticket conversation. The reply will be visible to the customer and will update the ticket status if specified.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `bcc_emails` | Array of email addresses to BCC on the reply | `array` | null |
-| `body` | HTML content of the reply | string |
-| `cc_emails` | Array of email addresses to CC on the reply | `array` | null |
-| `from_email` | Email address to send the reply from | string | null |
-| `ticket_id` | ID of the ticket to reply to | number |
-| `user_id` | ID of the agent sending the reply | number | null |
diff --git a/plugins/agentkit/references/agent-connectors/github.md b/plugins/agentkit/references/agent-connectors/github.md
deleted file mode 100644
index c9cf234..0000000
--- a/plugins/agentkit/references/agent-connectors/github.md
+++ /dev/null
@@ -1,137 +0,0 @@
-GitHub is a cloud-based Git repository hosting service that allows developers to store, manage, and track changes to their code.
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `github_file_contents_get`
-
-Get the contents of a file or directory from a GitHub repository. Returns Base64 encoded content for files.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `owner` | The account owner of the repository | string |
-| `path` | The content path (file or directory path in the repository) | string |
-| `ref` | The name of the commit/branch/tag | string | null |
-| `repo` | The name of the repository | string |
-
-## `github_file_create_update`
-
-Create a new file or update an existing file in a GitHub repository. Content must be Base64 encoded. Requires SHA when updating existing files.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `author` | Author information object with name and email | `object` | null |
-| `branch` | The branch name | string | null |
-| `committer` | Committer information object with name and email | `object` | null |
-| `content` | The new file content (Base64 encoded) | string |
-| `message` | The commit message for this change | string |
-| `owner` | The account owner of the repository | string |
-| `path` | The file path in the repository | string |
-| `repo` | The name of the repository | string |
-| `sha` | The blob SHA of the file being replaced (required when updating existing files) | string | null |
-
-## `github_issue_create`
-
-Create a new issue in a repository. Requires push access to set assignees, milestones, and labels.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assignees` | GitHub usernames to assign to the issue | `array` | null |
-| `body` | The contents of the issue | string | null |
-| `labels` | Labels to associate with the issue | `array` | null |
-| `milestone` | Milestone number to associate with the issue | number | null |
-| `owner` | The account owner of the repository | string |
-| `repo` | The name of the repository | string |
-| `title` | The title of the issue | string |
-| `type` | The name of the issue type | string | null |
-
-## `github_issues_list`
-
-List issues in a repository. Both issues and pull requests are returned as issues in the GitHub API.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assignee` | Filter by assigned user | string | null |
-| `creator` | Filter by issue creator | string | null |
-| `direction` | Sort order | string | null |
-| `labels` | Filter by comma-separated list of label names | string | null |
-| `milestone` | Filter by milestone number or state | string | null |
-| `owner` | The account owner of the repository | string |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `repo` | The name of the repository | string |
-| `since` | Show issues updated after this timestamp (ISO 8601 format) | string | null |
-| `sort` | Property to sort issues by | string | null |
-| `state` | Filter by issue state | string | null |
-
-## `github_public_repos_list`
-
-List public repositories for a specified user. Does not require authentication.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `direction` | Sort order | string | null |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `sort` | Property to sort repositories by | string | null |
-| `type` | Filter repositories by type | string | null |
-| `username` | The GitHub username to list repositories for | string |
-
-## `github_pull_request_create`
-
-Create a new pull request in a repository. Requires write access to the head branch.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `base` | The name of the branch you want the changes pulled into | string |
-| `body` | The contents of the pull request description | string | null |
-| `draft` | Indicates whether the pull request is a draft | boolean | null |
-| `head` | The name of the branch where your changes are implemented (format: user:branch) | string |
-| `maintainer_can_modify` | Indicates whether maintainers can modify the pull request | boolean | null |
-| `owner` | The account owner of the repository | string |
-| `repo` | The name of the repository | string |
-| `title` | The title of the pull request | string | null |
-
-## `github_pull_requests_list`
-
-List pull requests in a repository with optional filtering by state, head, and base branches.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `base` | Filter by base branch name | string | null |
-| `direction` | Sort order | string | null |
-| `head` | Filter by head branch (format: user:ref-name) | string | null |
-| `owner` | The account owner of the repository | string |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `repo` | The name of the repository | string |
-| `sort` | Property to sort pull requests by | string | null |
-| `state` | Filter by pull request state | string | null |
-
-## `github_repo_get`
-
-Get detailed information about a GitHub repository including metadata, settings, and statistics.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `owner` | The account owner of the repository (case-insensitive) | string |
-| `repo` | The name of the repository without the .git extension (case-insensitive) | string |
-
-## `github_user_repos_list`
-
-List repositories for the authenticated user. Requires authentication.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `direction` | Sort order | string | null |
-| `page` | Page number of results to fetch | number | null |
-| `per_page` | Number of results per page (max 100) | number | null |
-| `sort` | Property to sort repositories by | string | null |
-| `type` | Filter repositories by type | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/gmail.md b/plugins/agentkit/references/agent-connectors/gmail.md
deleted file mode 100644
index d668c75..0000000
--- a/plugins/agentkit/references/agent-connectors/gmail.md
+++ /dev/null
@@ -1,79 +0,0 @@
-Gmail is Google's cloud based email service that allows you to access your messages from any computer or device with just a web browser.
-
-Supports authentication: OAuth 2.0
-
-## Tool list
-
-## `gmail_fetch_mails`
-
-Fetch emails from a connected Gmail account using search filters. Requires a valid Gmail OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `format` | Format of the returned message. | string | null |
-| `include_spam_trash` | Whether to fetch emails from spam and trash folders | boolean | null |
-| `label_ids` | Gmail label IDs to filter messages | `array` | null |
-| `max_results` | Maximum number of emails to fetch | integer | null |
-| `page_token` | Page token for pagination | string | null |
-| `query` | Search query string using Gmail's search syntax (e.g., 'is:unread from:user@example.com') | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_attachment_by_id`
-
-Retrieve a specific attachment from a Gmail message using the message ID and attachment ID.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attachment_id` | Unique Gmail attachment ID | string |
-| `file_name` | Preferred filename to use when saving/returning the attachment | string | null |
-| `message_id` | Unique Gmail message ID that contains the attachment | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_contacts`
-
-Fetch a list of contacts from the connected Gmail account. Supports pagination and field filtering.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of contacts to fetch | integer | null |
-| `page_token` | Token to retrieve the next page of results | string | null |
-| `person_fields` | Fields to include for each person | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_get_message_by_id`
-
-Retrieve a specific Gmail message using its message ID. Optionally control the format of the returned data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `format` | Format of the returned message. | string | null |
-| `message_id` | Unique Gmail message ID | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_list_drafts`
-
-List draft emails from a connected Gmail account. Requires a valid Gmail OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of drafts to fetch | integer | null |
-| `page_token` | Page token for pagination | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `gmail_search_people`
-
-Search people or contacts in the connected Google account using a query. Requires a valid Google OAuth2 connection with People API scopes.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `other_contacts` | Whether to include people not in the user's contacts (from 'Other Contacts'). | boolean | null |
-| `page_size` | Maximum number of people to return. | integer | null |
-| `person_fields` | Fields to retrieve for each person. | `array` | null |
-| `query` | Text query to search people (e.g., name, email address). | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/gong.md b/plugins/agentkit/references/agent-connectors/gong.md
deleted file mode 100644
index 26a36e3..0000000
--- a/plugins/agentkit/references/agent-connectors/gong.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect with Gong to sync calls, transcripts, insights, coaching and CRM activity
-
-Supports authentication: OAuth 2.0 , Api Key
diff --git a/plugins/agentkit/references/agent-connectors/google_ads.md b/plugins/agentkit/references/agent-connectors/google_ads.md
deleted file mode 100644
index 9718639..0000000
--- a/plugins/agentkit/references/agent-connectors/google_ads.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Ads to manage advertising campaigns, analyze performance metrics, and optimize ad spending across Google's advertising platform
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_docs.md b/plugins/agentkit/references/agent-connectors/google_docs.md
deleted file mode 100644
index e790d5d..0000000
--- a/plugins/agentkit/references/agent-connectors/google_docs.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Docs. Create, edit, and collaborate on documents
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_drive.md b/plugins/agentkit/references/agent-connectors/google_drive.md
deleted file mode 100644
index ef6120e..0000000
--- a/plugins/agentkit/references/agent-connectors/google_drive.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Drive. Manage files, folders, and sharing permissions
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_forms.md b/plugins/agentkit/references/agent-connectors/google_forms.md
deleted file mode 100644
index fde9e1d..0000000
--- a/plugins/agentkit/references/agent-connectors/google_forms.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Forms. Create, view, and manage forms and responses securely
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_meets.md b/plugins/agentkit/references/agent-connectors/google_meets.md
deleted file mode 100644
index 814ff7b..0000000
--- a/plugins/agentkit/references/agent-connectors/google_meets.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Meet. Create and manage video meetings with powerful collaboration features
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_sheets.md b/plugins/agentkit/references/agent-connectors/google_sheets.md
deleted file mode 100644
index 8df9a54..0000000
--- a/plugins/agentkit/references/agent-connectors/google_sheets.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Google Sheets. Create, edit, and analyze spreadsheets with powerful data management capabilities
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/google_slides.md b/plugins/agentkit/references/agent-connectors/google_slides.md
deleted file mode 100644
index 242ef37..0000000
--- a/plugins/agentkit/references/agent-connectors/google_slides.md
+++ /dev/null
@@ -1,32 +0,0 @@
-Connect to Google Slides to create, read, and modify presentations programmatically.
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `googleslides_create_presentation`
-
-Create a new Google Slides presentation with an optional title.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `title` | Title of the new presentation | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googleslides_read_presentation`
-
-Read the complete structure and content of a Google Slides presentation including slides, text, images, shapes, and metadata.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `fields` | Fields to include in the response | string | null |
-| `presentation_id` | The ID of the Google Slides presentation to read | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/googlecalendar.md b/plugins/agentkit/references/agent-connectors/googlecalendar.md
deleted file mode 100644
index 8168441..0000000
--- a/plugins/agentkit/references/agent-connectors/googlecalendar.md
+++ /dev/null
@@ -1,128 +0,0 @@
-Google Calendar is Google's cloud-based calendar service that allows you to manage your events, appointments, and schedules from any computer or device with just a web browser.
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `googlecalendar_create_event`
-
-Create a new event in a connected Google Calendar account. Supports meeting links, recurrence, attendees, and more.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attendees_emails` | Attendee email addresses | `array` | null |
-| `calendar_id` | Calendar ID to create the event in | string | null |
-| `create_meeting_room` | Generate a Google Meet link for this event | boolean | null |
-| `description` | Optional event description | string | null |
-| `event_duration_hour` | Duration of event in hours | integer | null |
-| `event_duration_minutes` | Duration of event in minutes | integer | null |
-| `event_type` | Event type for display purposes | string | null |
-| `guests_can_invite_others` | Allow guests to invite others | boolean | null |
-| `guests_can_modify` | Allow guests to modify the event | boolean | null |
-| `guests_can_see_other_guests` | Allow guests to see each other | boolean | null |
-| `location` | Location of the event | string | null |
-| `recurrence` | Recurrence rules (iCalendar RRULE format) | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `send_updates` | Send update notifications to attendees | boolean | null |
-| `start_datetime` | Event start time in RFC3339 format | string |
-| `summary` | Event title/summary | string |
-| `timezone` | Timezone for the event (IANA time zone identifier) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `transparency` | Calendar transparency (free/busy) | string | null |
-| `visibility` | Visibility of the event | string | null |
-
-## `googlecalendar_delete_event`
-
-Delete an event from a connected Google Calendar account. Requires the calendar ID and event ID.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | The ID of the calendar from which the event should be deleted | string | null |
-| `event_id` | The ID of the calendar event to delete | string |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_get_event_by_id`
-
-Retrieve a specific calendar event by its ID using optional filtering and list parameters.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | The calendar ID to search in | string | null |
-| `event_id` | The unique identifier of the calendar event to fetch | string |
-| `event_types` | Filter by Google event types | `array` | null |
-| `query` | Free text search query | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `show_deleted` | Include deleted events in results | boolean | null |
-| `single_events` | Expand recurring events into instances | boolean | null |
-| `time_max` | Upper bound for event start time (RFC3339) | string | null |
-| `time_min` | Lower bound for event start time (RFC3339) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `updated_min` | Filter events updated after this time (RFC3339) | string | null |
-
-## `googlecalendar_list_calendars`
-
-List all accessible Google Calendar calendars for the authenticated user. Supports filters and pagination.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `max_results` | Maximum number of calendars to fetch | integer | null |
-| `min_access_role` | Minimum access role to include in results | string | null |
-| `page_token` | Token to retrieve the next page of results | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `show_deleted` | Include deleted calendars in the list | boolean | null |
-| `show_hidden` | Include calendars that are hidden from the calendar list | boolean | null |
-| `sync_token` | Token to get updates since the last sync | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_list_events`
-
-List events from a connected Google Calendar account with filtering options. Requires a valid Google Calendar OAuth2 connection.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `calendar_id` | Calendar ID to list events from | string | null |
-| `max_results` | Maximum number of events to fetch | integer | null |
-| `order_by` | Order of events in the result | string | null |
-| `page_token` | Page token for pagination | string | null |
-| `query` | Free text search query | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `single_events` | Expand recurring events into single events | boolean | null |
-| `time_max` | Upper bound for event start time (RFC3339 timestamp) | string | null |
-| `time_min` | Lower bound for event start time (RFC3339 timestamp) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `googlecalendar_update_event`
-
-Update an existing event in a connected Google Calendar account. Only provided fields will be updated. Supports updating time, attendees, location, meeting links, and more.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `attendees_emails` | Attendee email addresses | `array` | null |
-| `calendar_id` | Calendar ID containing the event | string |
-| `create_meeting_room` | Generate a Google Meet link for this event | boolean | null |
-| `description` | Optional event description | string | null |
-| `end_datetime` | Event end time in RFC3339 format | string | null |
-| `event_duration_hour` | Duration of event in hours | integer | null |
-| `event_duration_minutes` | Duration of event in minutes | integer | null |
-| `event_id` | The ID of the calendar event to update | string |
-| `event_type` | Event type for display purposes | string | null |
-| `guests_can_invite_others` | Allow guests to invite others | boolean | null |
-| `guests_can_modify` | Allow guests to modify the event | boolean | null |
-| `guests_can_see_other_guests` | Allow guests to see each other | boolean | null |
-| `location` | Location of the event | string | null |
-| `recurrence` | Recurrence rules (iCalendar RRULE format) | `array` | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `send_updates` | Send update notifications to attendees | boolean | null |
-| `start_datetime` | Event start time in RFC3339 format | string | null |
-| `summary` | Event title/summary | string | null |
-| `timezone` | Timezone for the event (IANA time zone identifier) | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-| `transparency` | Calendar transparency (free/busy) | string | null |
-| `visibility` | Visibility of the event | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/hubspot.md b/plugins/agentkit/references/agent-connectors/hubspot.md
deleted file mode 100644
index ac44f2c..0000000
--- a/plugins/agentkit/references/agent-connectors/hubspot.md
+++ /dev/null
@@ -1,143 +0,0 @@
-Connect to HubSpot CRM. Manage contacts, deals, companies, and marketing automation
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `hubspot_companies_search`
-
-Search HubSpot companies using full-text search and pagination. Returns matching companies with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across company properties | string | null |
-
-## `hubspot_company_create`
-
-Create a new company in HubSpot CRM. Requires a company name as the unique identifier. Supports additional properties like domain, industry, phone, location, and revenue information.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `annualrevenue` | Annual revenue of the company | number | null |
-| `city` | Company city location | string | null |
-| `country` | Company country location | string | null |
-| `description` | Company description or overview | string | null |
-| `domain` | Company website domain | string | null |
-| `industry` | Industry type of the company | string | null |
-| `name` | Company name (required, serves as primary identifier) | string |
-| `numberofemployees` | Number of employees at the company | number | null |
-| `phone` | Company phone number | string | null |
-| `state` | Company state or region | string | null |
-
-## `hubspot_company_get`
-
-Retrieve details of a specific company from HubSpot by company ID. Returns company properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company_id` | ID of the company to retrieve | string |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contact_create`
-
-Create a new contact in HubSpot CRM. Requires an email address as the unique identifier. Supports additional properties like name, company, phone, and lifecycle stage.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `company` | Company name where the contact works | string | null |
-| `email` | Primary email address for the contact (required, serves as unique identifier) | string |
-| `firstname` | First name of the contact | string | null |
-| `hs_lead_status` | Lead status of the contact | string | null |
-| `jobtitle` | Job title of the contact | string | null |
-| `lastname` | Last name of the contact | string | null |
-| `lifecyclestage` | Lifecycle stage of the contact | string | null |
-| `phone` | Phone number of the contact | string | null |
-| `website` | Personal or company website URL | string | null |
-
-## `hubspot_contact_get`
-
-Retrieve details of a specific contact from HubSpot by contact ID. Returns contact properties and associated data.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `contact_id` | ID of the contact to retrieve | string |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contact_update`
-
-Update an existing contact in HubSpot CRM by contact ID. Allows updating contact properties like name, email, company, phone, and lifecycle stage.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `contact_id` | ID of the contact to update | string |
-| `props` | Object containing properties like first name, last name, email, company, phone, and job title to update all these should be provided inside props as a JSON object, this is required | `object` | null |
-
-## `hubspot_contacts_list`
-
-Retrieve a list of contacts from HubSpot with filtering and pagination. Returns contact properties and supports pagination through cursor-based navigation.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination cursor to get the next set of results | string | null |
-| `archived` | Whether to include archived contacts in the results | boolean | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-
-## `hubspot_contacts_search`
-
-Search HubSpot contacts using full-text search and pagination. Returns matching contacts with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across contact properties | string | null |
-
-## `hubspot_deal_create`
-
-Create a new deal in HubSpot CRM. Requires dealname, amount, and dealstage. Supports additional properties like pipeline, close date, and deal type.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `amount` | Deal amount/value (required) | number |
-| `closedate` | Expected close date (YYYY-MM-DD format) | string | null |
-| `dealname` | Name of the deal (required) | string |
-| `dealstage` | Current stage of the deal (required) | string |
-| `dealtype` | Type of deal | string | null |
-| `description` | Deal description | string | null |
-| `hs_priority` | Deal priority (HIGH, MEDIUM, LOW) | string | null |
-| `pipeline` | Deal pipeline | string | null |
-
-## `hubspot_deal_update`
-
-Update an existing deal in HubSpot CRM by deal ID. Allows updating deal properties like name, amount, stage, pipeline, close date, and priority.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `deal_id` | ID of the deal to update | string |
-| `good_deal` | Boolean flag indicating if this is a good deal | boolean | null |
-| `properties` | Object containing deal properties to update | `object` |
-
-## `hubspot_deals_search`
-
-Search HubSpot deals using full-text search and pagination. Returns matching deals with specified properties.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Pagination offset to get results starting from a specific position | string | null |
-| `filterGroups` | JSON string containing filter groups for advanced filtering | string | null |
-| `limit` | Number of results to return per page (max 100) | number | null |
-| `properties` | Comma-separated list of properties to include in the response | string | null |
-| `query` | Search term for full-text search across deal properties | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/intercom.md b/plugins/agentkit/references/agent-connectors/intercom.md
deleted file mode 100644
index 77ef5d8..0000000
--- a/plugins/agentkit/references/agent-connectors/intercom.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Intercom. Send messages, manage conversations, and interact with users and contacts.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/jira.md b/plugins/agentkit/references/agent-connectors/jira.md
deleted file mode 100644
index 1675086..0000000
--- a/plugins/agentkit/references/agent-connectors/jira.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Jira. Manage issues, projects, workflows, and agile development processes
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/linear.md b/plugins/agentkit/references/agent-connectors/linear.md
deleted file mode 100644
index 9b0f877..0000000
--- a/plugins/agentkit/references/agent-connectors/linear.md
+++ /dev/null
@@ -1,58 +0,0 @@
-Connect to Linear. Manage issues, projects, sprints, and development workflows
-
-Supports authentication: OAuth 2.0
-
-## Tool list
-
-## `linear_graphql_query`
-
-Execute a custom GraphQL query or mutation against the Linear API. Allows running any valid GraphQL operation with variables support for advanced use cases.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `query` | The GraphQL query or mutation to execute | string |
-| `variables` | Variables to pass to the GraphQL query | `object` | null |
-
-## `linear_issue_create`
-
-Create a new issue in Linear using the issueCreate mutation. Requires a team ID and title at minimum.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assigneeId` | ID of the user to assign the issue to | string | null |
-| `description` | Description of the issue | string | null |
-| `estimate` | Story point estimate for the issue | string | null |
-| `labelIds` | Array of label IDs to apply to the issue | `array` | null |
-| `priority` | Priority level of the issue (1-4, where 1 is urgent) | string | null |
-| `projectId` | ID of the project to associate the issue with | string | null |
-| `stateId` | ID of the workflow state to set | string | null |
-| `teamId` | ID of the team to create the issue in | string |
-| `title` | Title of the issue | string |
-
-## `linear_issue_update`
-
-Update an existing issue in Linear. You can update title, description, priority, state, and assignee.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `assigneeId` | ID of the user to assign the issue to | string | null |
-| `description` | New description for the issue | string | null |
-| `issueId` | ID of the issue to update | string |
-| `priority` | Priority level of the issue (1-4, where 1 is urgent) | string | null |
-| `stateId` | ID of the workflow state to set | string | null |
-| `title` | New title for the issue | string | null |
-
-## `linear_issues_list`
-
-List issues in Linear using the issues query with simple filtering and pagination support.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `after` | Cursor for pagination (returns issues after this cursor) | string | null |
-| `assignee` | Filter by assignee email (e.g., 'user@example.com') | string | null |
-| `before` | Cursor for pagination (returns issues before this cursor) | string | null |
-| `first` | Number of issues to return (pagination) | integer | null |
-| `labels` | Filter by label names (array of strings) | `array` | null |
-| `priority` | Filter by priority level (1=Urgent, 2=High, 3=Medium, 4=Low) | string | null |
-| `project` | Filter by project name (e.g., 'Q4 Goals') | string | null |
-| `state` | Filter by state name (e.g., 'In Progress', 'Done') | string | null |
diff --git a/plugins/agentkit/references/agent-connectors/microsoft_excel.md b/plugins/agentkit/references/agent-connectors/microsoft_excel.md
deleted file mode 100644
index 2fa4c19..0000000
--- a/plugins/agentkit/references/agent-connectors/microsoft_excel.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Excel. Access, read, and modify spreadsheets stored in OneDrive or SharePoint through Microsoft Graph API.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/microsoft_teams.md b/plugins/agentkit/references/agent-connectors/microsoft_teams.md
deleted file mode 100644
index 85790a1..0000000
--- a/plugins/agentkit/references/agent-connectors/microsoft_teams.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Teams. Manage messages, channels, meetings, and team collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/microsoft_word.md b/plugins/agentkit/references/agent-connectors/microsoft_word.md
deleted file mode 100644
index 7b2d530..0000000
--- a/plugins/agentkit/references/agent-connectors/microsoft_word.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Microsoft Word. Authenticate with your Microsoft account to create, read, and edit Word documents stored in OneDrive or SharePoint through Microsoft Graph API.
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/monday.md b/plugins/agentkit/references/agent-connectors/monday.md
deleted file mode 100644
index 6cc8ab0..0000000
--- a/plugins/agentkit/references/agent-connectors/monday.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Connect to Monday.com. Manage boards, tasks, workflows, teams, and project collaboration
-
-Supports authentication: OAuth 2.0
diff --git a/plugins/agentkit/references/agent-connectors/notion.md b/plugins/agentkit/references/agent-connectors/notion.md
deleted file mode 100644
index 22b58d5..0000000
--- a/plugins/agentkit/references/agent-connectors/notion.md
+++ /dev/null
@@ -1,189 +0,0 @@
-Connect to Notion workspace. Create, edit pages, manage databases, and collaborate on content
-
-Supports authentication: OAuth 2.0
-
-## Table of Contents
-
-- [Tool list](#tool-list)
-
----
-
-## Tool list
-
-## `notion_comment_create`
-
-Create a comment in Notion. Provide a comment object with rich_text content and either a parent object (with page_id) for a page-level comment or a discussion_id to reply in an existing thread.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `comment` | Comment object containing a rich_text array. Example: `{"rich_text":[{"type":"text","text":{"content":"Hello"}}]}` | `object` |
-| `discussion_id` | Existing discussion thread ID to reply to. | string | null |
-| `notion_version` | Optional override for the Notion-Version header (e.g., 2022-06-28). | string | null |
-| `parent` | Parent object for a new top-level comment. Shape: `{"page_id":""}`. | `object` | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_comment_retrieve`
-
-Retrieve a single Notion comment by its `comment_id`. LLM tip: you typically obtain `comment_id` from the response of creating a comment or by first listing comments for a page/block and selecting the desired item’s `id`.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `comment_id` | The identifier of the comment to retrieve (hyphenated UUID). Obtain it from Create-Comment responses or from a prior List-Comments call. | string |
-| `notion_version` | Optional Notion-Version header override (e.g., 2022-06-28). | string | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_comments_fetch`
-
-Fetch comments for a given Notion block. Provide a `block_id` (the target page/block ID, hyphenated UUID). Supports pagination via `start_cursor` and `page_size` (1–100). LLM tip: extract `block_id` from a Notion URL’s trailing 32-char id, then insert hyphens (8-4-4-4-12).
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `block_id` | Target Notion block (or page) ID to fetch comments for. Use a hyphenated UUID. | string |
-| `notion_version` | Optional Notion-Version header override (e.g., 2022-06-28). | string | null |
-| `page_size` | Maximum number of comments to return (1–100). | integer | null |
-| `schema_version` | Internal override for schema version. | string | null |
-| `start_cursor` | Cursor to fetch the next page of results. | string | null |
-| `tool_version` | Internal override for tool implementation version. | string | null |
-
-## `notion_data_fetch`
-
-Fetch data from Notion using the workspace search API (/search). Supports pagination via start_cursor.
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `page_size` | Max number of results to return (1–100) | integer | null |
-| `query` | Text query used by /search | string | null |
-| `schema_version` | Optional schema version to use for tool execution | string | null |
-| `start_cursor` | Cursor for pagination; pass the previous response's next_cursor | string | null |
-| `tool_version` | Optional tool version to use for execution | string | null |
-
-## `notion_database_create`
-
-Create a new database in Notion under a parent page. Provide a parent object with page_id, a database title (rich_text array), and a properties object that defines the database schema (columns).
-
-| Properties | Description | Type |
-| --- | --- | --- |
-| `notion_version` | Optional override for the Notion-Version header (e.g., 2022-06-28). | string | null |
-| `parent` | Parent object specifying the page under which the database is created. Example: `{"page_id": "2561ab6c-418b-8072-beec-c4779fa811cf"}` | `object` |
-| `properties` | Database schema object defining properties (columns). Example: `{"Name": {"title": {}}, "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Doing"}, {"name": "Done"}]}}}` | `object` |
-| `schema_version` | Internal override for schema version. | string | null |
-| `title` | Database title as a Notion rich_text array. | `array
-## Connector setup
-
-Before integrating with a connector, follow these steps in the Scalekit Dashboard:
-
-> **Gmail is the only connector that does not require dashboard setup.** Skip this section for Gmail.
-
-For all other connectors (Slack, Notion, Google Calendar, etc.):
-
-1. Go to **Scalekit Dashboard → AgentKit → Connections**
-2. Click **+ Create Connection**
-3. Select the connector you want to use
-4. Enter a **Connection Name** (e.g., `MY_SLACK`, `MY_NOTION`)
-5. Click **Save**
-
-> **Important**: The **Connection Name** you set in the dashboard is exactly what you use as the `connection_name` parameter in your code. They must match exactly.
-
## Integration workflow
-**First, ask the user:**
-
-> Are you starting fresh and want a quick test with Gmail, or are you integrating directly into your project?
-
-- If **fresh / quick test**: Use the Gmail example below (Gmail is the only connector that doesn't require dashboard setup)
-- If **integrating directly**: Create your connector in the Scalekit Dashboard first, then adapt the workflow below to your connector
+> **Gmail works without dashboard setup.** All other connectors must be configured first: **Dashboard → AgentKit → Connections → + Create Connection**. The **Connection Name** in the dashboard must match `connection_name` in code exactly.
-Copy this checklist and check off steps as you complete them:
+Copy this checklist:
```
AgentKit Integration Progress:
@@ -159,7 +138,7 @@ refresh_token = tokens["refresh_token"]
```typescript
const accountResponse = await connectedAccounts.getConnectedAccountByIdentifier({
connector: 'gmail',
- identifier: 'user@example.com',
+ identifier: 'user_123',
});
const authDetails = accountResponse?.connectedAccount?.authorizationDetails;
const accessToken = authDetails?.details?.case === 'oauthToken'
@@ -223,7 +202,7 @@ for (const msg of messages) {
Replace `"gmail"` with any supported connector name: `slack`, `notion`, `calendar`, etc.
The SDK workflow (Steps 1–3) is identical for all connectors. Only the downstream API call (Step 4) changes.
-For connector-specific API details, see the [AgentKit connectors catalog](https://docs.scalekit.com/agentkit/connectors/).
+For connector-specific API details, see the [Scalekit Connectors catalog](https://docs.scalekit.com/agentkit/connectors/).
## Building agents
@@ -289,14 +268,20 @@ agent = Agent(
response = agent.process_request("fetch my last 5 unread emails and summarize them")
```
-For more examples and framework-specific patterns, see [code-samples.md](../../references/code-samples.md).
+For more examples and framework-specific patterns, see the [AgentKit code samples](https://docs.scalekit.com/agentkit/code-samples/).
## Deep reference
-For comprehensive documentation on connected accounts lifecycle, states, and API usage, see [connected-accounts.md](../../references/connected-accounts.md).
-
-For code samples and implementation examples by framework, see [code-samples.md](../../references/code-samples.md).
+- AgentKit overview: [docs.scalekit.com/agentkit/overview](https://docs.scalekit.com/agentkit/overview/)
+- Connections: [docs.scalekit.com/agentkit/connections](https://docs.scalekit.com/agentkit/connections/)
+- Connected accounts: [docs.scalekit.com/agentkit/connected-accounts](https://docs.scalekit.com/agentkit/connected-accounts/)
+- Tool discovery: [docs.scalekit.com/agentkit/tool-discovery](https://docs.scalekit.com/agentkit/tool-discovery/)
+- Connectors catalog: [docs.scalekit.com/agentkit/connectors](https://docs.scalekit.com/agentkit/connectors/)
+- BYOC (Bring Your Own Credentials): [docs.scalekit.com/agentkit/byoc](https://docs.scalekit.com/agentkit/launch-checklist/byoc/)
-For an overview of supported connectors and their capabilities, see [connectors.md](../../references/connectors.md).
+## When to switch skills
-For configuring your own OAuth credentials per connector (whitelabeling, dedicated quotas), see [byoc.md](../../references/byoc.md).
+- Use `discovering-connector-tools` when the user needs the current tool catalog or schema.
+- Use the Scalekit MCP server (`https://mcp.scalekit.com`) to validate a tool call interactively.
+- Use `exposing-agentkit-via-mcp` when the user wants AgentKit tools exposed over MCP.
+- Use `sk-actions-custom-provider` to create custom connectors.
diff --git a/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
index 4f9ea78..fd3625f 100644
--- a/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
+++ b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
@@ -1,6 +1,6 @@
---
name: production-readiness-agentkit
-description: Walks through a structured production readiness checklist for Scalekit AgentKit implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, or wants to verify their AgentKit authorization and tool-calling setup is production-ready.
+description: Validates OAuth token flows, audits token storage security, verifies per-connector authorization, and checks monitoring configuration for Scalekit AgentKit implementations before production launch. Use when going live, doing a pre-launch review, or verifying AgentKit authorization and tool-calling setup is production-ready.
---
# Scalekit AgentKit Production Readiness
@@ -11,9 +11,20 @@ Work through each section in order — earlier sections are blockers for later o
## Quick checks (run first)
-- [ ] Production environment URL, client ID, and client secret are set (not dev/staging values)
+```bash
+# Confirm production credentials are set (not dev/staging)
+echo $SCALEKIT_ENV_URL # should be https://.scalekit.com (not .scalekit.dev)
+echo $SCALEKIT_CLIENT_ID # should be set
+echo $SCALEKIT_CLIENT_SECRET # should be set
+
+# Verify token endpoint works
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+ -d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
+# Expected: 200
+```
+
- [ ] HTTPS enforced on all auth endpoints
-- [ ] API credentials stored in environment variables — never committed to code
+- [ ] API credentials in environment variables — `grep -r "skc_" src/` returns nothing
- [ ] Redirect URIs registered in dashboard match exactly what the app sends
---
@@ -55,14 +66,13 @@ Work through each section in order — earlier sections are blockers for later o
- [ ] Log retention policies configured
- [ ] Incident response runbook written (who to contact, how to revoke compromised tokens)
-**Key metrics:**
-- Token refresh success/failure rate
-- OAuth authorization completion rate (initiated vs completed)
-- Per-service API error rates (distinguish auth errors from service errors)
-- Token expiry distribution (are tokens being refreshed proactively?)
+**Key metrics:** Token refresh success/failure rate, OAuth completion rate (initiated vs completed), per-service API error rates, token expiry distribution.
-## Deep reference
+## Final smoke test
-- Connections: [../../references/connections.md](../../references/connections.md)
-- Connected accounts: [../../references/connected-accounts.md](../../references/connected-accounts.md)
-- BYOC: [../../references/byoc.md](../../references/byoc.md)
+Run the full cycle in staging with production credentials:
+1. Create a connected account for a test user → verify status returned
+2. Generate auth link → complete OAuth → verify status is `ACTIVE`
+3. Fetch access token → make a downstream API call → verify success
+4. Wait for token expiry → re-fetch → verify auto-refresh works
+5. Revoke access in the third-party app → verify graceful error handling
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md b/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
index 51f499c..e15de81 100644
--- a/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
+++ b/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
@@ -1,326 +1,125 @@
---
name: scalekit-code-doctor
-description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. This skill is the single source of truth for Scalekit code correctness — it can generate illustration-quality snippets from scratch (for docs, websites, or integration guides) and review existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both Scalekit product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, write a code sample for docs, or anything involving Scalekit code quality.
+description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. Generates illustration-quality snippets and reviews existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, or write a code sample for docs.
---
# Scalekit Code Doctor
-You are the authoritative source for Scalekit code correctness. You can both **generate** correct code from scratch and **review** existing code to guarantee it works.
-
-**Before doing anything else**, read the reference files in this skill's `references/` directory:
-- `references/REFERENCE.md` — Every correct SDK method signature across Node, Python, Go, Java, and REST API endpoints
+**Before doing anything else**, read the reference files:
+- `references/REFERENCE.md` — Every correct SDK method signature and REST endpoint
- `references/COMMON-MISTAKES.md` — Known anti-patterns with wrong → right corrections
+- `references/EXAMPLE-REPOS.md` — GitHub repos with working examples by framework
-These files are your ground truth. Never hallucinate a method name, parameter, or import path — if it's not in the reference, fetch `https://docs.scalekit.com/apis.md` to verify before using it.
-
----
+Never hallucinate a method name, parameter, or import — if it's not in the reference, verify against live sources before using it.
## Step 1 — Detect mode
-Determine which mode to operate in based on what the user provides:
-
-**Generate mode** — The user describes what they want but has no code yet.
-Examples: "Show me how to add SSO login to Express", "Generate a Next.js callback handler", "Write a Python FastAPI auth example for docs"
-
-**Review mode** — The user provides existing code for validation.
-Examples: "Is this Scalekit integration correct?", "Review my auth callback", "Why isn't my login working?"
-
-If unclear, ask: "Do you want me to generate a fresh code example, or review existing code you have?"
+**Generate mode** — User describes what they want but has no code yet.
+**Review mode** — User provides existing code for validation.
----
+If unclear, ask: "Do you want me to generate a fresh code example, or review existing code?"
## Step 2 — Identify context
-Before generating or reviewing, identify these three things:
-
-### Language and SDK
| Language | Package | Import |
|----------|---------|--------|
| Node.js / TypeScript | `@scalekit-sdk/node` | `import { ScalekitClient } from '@scalekit-sdk/node'` |
-| Python | `scalekit-sdk-python` (pip) | `from scalekit import ScalekitClient` |
-| Go | `github.com/scalekit-inc/scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
-| Java | `com.scalekit:scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
-| REST API | No SDK — raw HTTP | Bearer token via `POST /oauth/token` with client credentials |
-
-### Framework (if applicable)
-Next.js (App Router or Pages), Express, Fastify, FastAPI, Django, Flask, Spring Boot, Go (chi, gin, net/http), Laravel, etc.
-
-### Product area
-
-Scalekit has two product suites. Identify which one the user's code belongs to:
-
-**SaaSKit** — Full-stack authentication for B2B SaaS apps
-- SSO — Enterprise single sign-on (SAML, OIDC)
-- Login & Sessions — Sign-up, login, logout, session management
-- RBAC — Roles, permissions, access control
-- SCIM — Directory sync and user provisioning
-- Admin Portal — Customer-facing admin configuration
+| Python | `scalekit-sdk-python` | `from scalekit import ScalekitClient` |
+| Go | `scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
+| Java | `scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
-**AgentKit** — Authentication and tool access for AI agents
-- Connections — OAuth token vault for third-party services (connected accounts)
-- Tool Calling — Execute tools via connected accounts
-- MCP Authentication — OAuth 2.1 for MCP servers
-- Framework Integrations — LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra
-
-**Cross-product**
-- Webhooks — Event subscriptions and payload verification
-- M2M Auth — API keys and client credentials
-
----
+Product area: **SaaSKit** (SSO, login, sessions, RBAC, SCIM) or **AgentKit** (connections, tool calling, MCP auth).
## Step 3 — Generate mode
-When generating code, follow these rules:
-
-### Quality standard: illustration-ready
-The output should be clean enough to publish directly on `docs.scalekit.com` or a marketing landing page. This means:
-
-1. **Self-contained** — The reader understands it without seeing other files
-2. **Essential path only** — Show the concept, not defensive boilerplate
-3. **Real-looking values** — `'https://yourapp.com/auth/callback'` not `'http://localhost:3000/test'`
-4. **Correct imports** — Exact package names from the reference table above
-5. **Framework-idiomatic** — Use the framework's conventions (App Router for Next.js, decorators for FastAPI, etc.)
-6. **Minimal comments** — Annotate Scalekit-specific lines only. Skip obvious framework code.
-7. **1–2 pages max** — Concise. If a full flow needs more, split into labeled sections.
-
-### Mandatory checks before outputting generated code
-Cross-reference every SDK call against `references/REFERENCE.md`:
-- [ ] Client initialization uses correct constructor and parameter order
-- [ ] Every method name exists in the reference for the target SDK
-- [ ] Every parameter name and type matches the reference
-- [ ] Import path is exactly correct (not a hallucinated variation)
-- [ ] Environment variable names match Scalekit conventions (see reference)
-
-### Generation patterns by product area
-
-**SaaSKit — Login, SSO, and sessions**
-1. Client initialization (singleton pattern)
-2. Login route: generate auth URL with `state` for CSRF
-3. Callback route: validate `state`, exchange code, store session
-4. Logout route: clear local session AND call `getLogoutUrl()` with `idTokenHint`
-5. Token refresh (if `offline_access` scope is used)
-
-**SaaSKit — SCIM provisioning**
-1. Enable directory for an organization
-2. List directory users and groups
-3. Webhook handler for SCIM events
-
-**AgentKit — Connections and tool calling**
-1. Client initialization
-2. Create/list connected accounts
-3. Execute tools with connected account credentials
-4. Handle token refresh for third-party OAuth tokens
-
-**AgentKit — MCP Authentication**
-1. MCP server setup with OAuth middleware
-2. Token validation on incoming requests
-3. Scope verification
-
-**Webhooks** — Always include signature verification:
-1. Raw body parsing (not JSON-parsed)
-2. `verifyWebhookPayload(secret, headers, rawBody)`
-3. Event type switching
-
----
+Output should be illustration-ready: self-contained, essential path only, correct imports, framework-idiomatic, 1–2 pages max.
+
+**Correct SaaSKit login+callback example (Node.js/Express):**
+
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+import crypto from 'crypto';
+
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+
+const REDIRECT_URI = 'https://yourapp.com/auth/callback';
+
+// Login — generate auth URL with CSRF state
+app.get('/auth/login', (req, res) => {
+ const state = crypto.randomBytes(32).toString('base64url');
+ res.cookie('oauth_state', state, { httpOnly: true, sameSite: 'lax', secure: true });
+ const authUrl = scalekit.getAuthorizationUrl(REDIRECT_URI, { state });
+ res.redirect(authUrl);
+});
+
+// Callback — validate state, exchange code, store session
+app.get('/auth/callback', async (req, res) => {
+ const { code, state } = req.query;
+ if (state !== req.cookies.oauth_state) return res.status(403).send('CSRF mismatch');
+
+ const result = await scalekit.authenticateWithCode(code as string, REDIRECT_URI);
+ req.session.user = { id: result.user.id, email: result.user.email };
+ req.session.idToken = result.idToken;
+ res.redirect('/dashboard');
+});
+
+// Logout — clear local + end IdP session
+app.post('/auth/logout', (req, res) => {
+ const logoutUrl = scalekit.getLogoutUrl({
+ idTokenHint: req.session.idToken,
+ postLogoutRedirectUri: 'https://yourapp.com',
+ });
+ req.session.destroy(() => res.redirect(logoutUrl));
+});
+```
+
+**Mandatory checks before outputting generated code** — cross-reference every SDK call against `references/REFERENCE.md`:
+- [ ] Method names exist for the target SDK
+- [ ] Parameters match in name, order, and type
+- [ ] Import path is exactly correct
+- [ ] Environment variable names follow Scalekit conventions
## Step 4 — Review mode
-When reviewing code, systematically check these categories in order:
-
-### Category 1: SDK usage correctness
-For every Scalekit SDK call in the code, verify against `references/REFERENCE.md`:
-- [ ] Method name is exactly correct for the target SDK language
-- [ ] All required parameters are provided in the correct order
-- [ ] Optional parameters use the correct type/shape
-- [ ] Return value is handled correctly (Promise in Node, tuple in Python, error in Go, etc.)
-- [ ] Import statement uses the correct package name and path
-- [ ] Client is initialized with the correct 3 parameters: `envUrl`, `clientId`, `clientSecret`
-
-### Category 2: Auth flow completeness
-- [ ] If there's a login route, there must be a matching callback route
-- [ ] Callback validates `state` parameter (CSRF protection)
-- [ ] Callback exchanges the authorization code (not just reading it)
-- [ ] Session is stored after successful authentication
-- [ ] Logout calls `getLogoutUrl()` — not just clearing local session
-- [ ] Token refresh exists if `offline_access` or `refresh_token` is used
-- [ ] IdP-initiated login is handled if callback receives `idp_initiated_login` parameter
-
-### Category 3: Security
-- [ ] Session cookies use `httpOnly: true`, `secure: true` (in production), `sameSite: 'lax'` (never `'strict'` — breaks OAuth redirects)
-- [ ] `state` parameter uses cryptographically random values, not predictable strings
-- [ ] Redirect URLs are validated — only relative paths allowed for `next`/`returnTo` params (prevents open redirect)
-- [ ] Client secret is read from environment variables, never hardcoded
-- [ ] Webhook endpoints verify payload signature before processing
-- [ ] Protected routes validate tokens server-side, not just checking cookie existence
-- [ ] `Cache-Control: no-store` on authenticated pages (prevents back-button cache leak)
-
-### Category 4: Environment and config
-- [ ] Environment variable names follow Scalekit conventions:
- - `SCALEKIT_ENV_URL` (not `SCALEKIT_URL` or `SCALEKIT_ENVIRONMENT_URL` in code — though `SCALEKIT_ENVIRONMENT_URL` is used in REST API docs)
- - `SCALEKIT_CLIENT_ID`
- - `SCALEKIT_CLIENT_SECRET`
-- [ ] Redirect URI in code matches what's registered in the Scalekit dashboard
-- [ ] Correct Scalekit domain format: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
-
-### Category 5: Best practices
-- [ ] Client instantiated once (singleton pattern), not per-request
-- [ ] Error handling uses SDK's typed exceptions where available
-- [ ] Token refresh handles race conditions across concurrent requests/tabs
-- [ ] `window.location.href` used for OAuth redirects (not `router.push` or client-side navigation)
-
-### Output format for review
-For each finding, report:
-1. **What's wrong** — the specific line or pattern
-2. **Why it matters** — security risk, runtime error, or silent failure
-3. **Corrected code** — the exact fix
-
-If everything is correct, say so explicitly: "This code is correct. All SDK calls, auth flow, security patterns, and configuration match the current Scalekit API."
-
----
+Check these categories in order:
-## Step 5 — Handling SDK updates and unknown methods
+**1. SDK correctness** — Every method name, parameter, import, and return type matches `references/REFERENCE.md`.
-The `references/REFERENCE.md` in this skill is a **point-in-time snapshot**. Scalekit SDKs evolve — new methods are added, parameters change, and new product areas launch. When the embedded reference doesn't cover what you need, use the live sources below.
+**2. Auth flow completeness** — Login has a callback. Callback validates `state`. Logout calls `getLogoutUrl()`. Token refresh exists if `offline_access` is used. IdP-initiated login handled if applicable.
-### When to check live sources
+**3. Security** — Cookies: `httpOnly`, `secure`, `sameSite: 'lax'`. State: cryptographically random. Redirects: only relative paths. Secrets: from env vars. Webhooks: signature verified before processing.
-- A method the user wrote isn't in the embedded reference (could be newly added, not a typo)
-- The user asks about a feature you don't recognize (e.g., a new connector, a new auth mode)
-- You're generating code for a product area with sparse coverage in the reference
-- The user explicitly mentions a recent SDK update or version
+**4. Environment** — `SCALEKIT_ENV_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`. Redirect URI matches dashboard. Domain format: `https://.scalekit.com`.
-### How to check: fetch the live SDK REFERENCE.md files
+**5. Best practices** — Client is singleton. Error handling uses typed exceptions. `window.location.href` for OAuth redirects (not `router.push`).
-Each SDK repo has a maintained `REFERENCE.md` with full, current method signatures. Fetch the one you need:
+**Output for each finding:** What's wrong → Why it matters → Corrected code.
-| SDK | Live reference URL |
-|-----|-------------------|
-| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` |
-| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` |
-| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` |
-| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` |
-| REST API | `https://docs.scalekit.com/apis.md` |
+## Step 5 — Unknown methods
-### Resolution order
+Resolution order when a method isn't in `references/REFERENCE.md`:
-1. Check the embedded `references/REFERENCE.md` first (fastest, no network)
-2. If the method isn't there, fetch the live SDK REFERENCE.md from the table above
-3. If still not found, fetch `https://docs.scalekit.com/apis.md` for REST endpoints
-4. If still not found, state explicitly: "This method could not be verified in any Scalekit reference. It may not exist."
+| Priority | Source |
+|----------|--------|
+| 1 | Embedded `references/REFERENCE.md` |
+| 2 | Live SDK reference: `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-{node,python,go,java}/main/REFERENCE.md` |
+| 3 | REST API: `https://docs.scalekit.com/apis.md` |
+| 4 | State explicitly: "This method could not be verified." |
Never output code containing an unverified method call.
----
-
-## REST API validation
+## Documentation
-When the user's code makes raw HTTP calls (fetch, axios, requests, http.Client) to Scalekit endpoints, validate:
-
-- [ ] Base URL format: `https://.scalekit.com` or `https://.scalekit.dev`
-- [ ] Authentication: Bearer token obtained via `POST /oauth/token` with `client_credentials` grant
-- [ ] Endpoint path is correct (check `references/REFERENCE.md` for the endpoint list)
-- [ ] HTTP method matches (GET vs POST vs PUT vs PATCH vs DELETE)
-- [ ] Request body matches the expected schema
-- [ ] Content-Type header is set (`application/json` for most endpoints, `application/x-www-form-urlencoded` for token endpoint)
-- [ ] Pagination uses `page_token` and `page_size` parameters where applicable
-
----
+| Resource | URL |
+|----------|-----|
+| REST API reference | `https://docs.scalekit.com/apis.md` |
+| LLM doc index | `https://docs.scalekit.com/llms.txt` |
+| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` |
+| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` |
+| MCP Auth docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` |
-## Documentation resources
-
-### Live SDK references (always current — fetch when embedded reference is stale)
-
-| SDK | REFERENCE.md (raw) | Repo |
-|-----|--------------------|----|
-| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` | [scalekit-sdk-node](https://github.com/scalekit-inc/scalekit-sdk-node) |
-| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` | [scalekit-sdk-python](https://github.com/scalekit-inc/scalekit-sdk-python) |
-| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` | [scalekit-sdk-go](https://github.com/scalekit-inc/scalekit-sdk-go) |
-| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` | [scalekit-sdk-java](https://github.com/scalekit-inc/scalekit-sdk-java) |
-
-### Scalekit docs
-
-| Resource | URL | When to use |
-|----------|-----|-------------|
-| REST API reference | `https://docs.scalekit.com/apis.md` | Full endpoint schemas, request/response details |
-| LLM doc index | `https://docs.scalekit.com/llms.txt` | Find the right docs page for a specific product area |
-| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` | Full SaaSKit reference (users, orgs, sessions, RBAC, SSO, SCIM) |
-| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` | Full AgentKit reference (agents, OAuth vault, tool calling, connectors) |
-| AgentKit frameworks | `https://docs.scalekit.com/_llms-txt/agentkit-frameworks.txt` | Framework-specific guides (LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra) |
-| MCP Authentication docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` | MCP server OAuth 2.1, Dynamic Client Registration |
-
-### GitHub repos — working examples
-
-When generating or reviewing framework-specific code, fetch the matching repo for real, tested patterns. Repos are from `scalekit-inc` and `scalekit-developers` GitHub orgs.
-
-**SaaSKit — Auth examples by framework**
-
-| Framework | Repo | What it shows |
-|-----------|------|---------------|
-| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes, TypeScript |
-| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO integration flows |
-| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
-| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, EJS frontend, sessions |
-| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO with session management, middleware |
-| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0, protected routes |
-| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic models |
-| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Python SDK, Django auth integration |
-| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Python SDK, Flask sessions |
-| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Java, Spring Security, OIDC |
-| Spring Boot | [scalekit-springboot-example](https://github.com/scalekit-developers/scalekit-springboot-example) | Java SDK, enterprise SSO |
-| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, Gin framework, SSO |
-| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API calls, Laravel HTTPS |
-| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login, protected routes |
-| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
-| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE for mobile |
-
-**SaaSKit — Integration examples**
-
-| Integration | Repo | What it shows |
-|-------------|------|---------------|
-| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) | OIDC SSO with Cognito user pools |
-| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) | SAML/OIDC SSO with Firebase Auth |
-| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) | Supabase + Scalekit auth |
-| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) | Seamless SSO across multiple apps |
-| Org switcher | [Nextjs-Django-Org-Switcher-Example](https://github.com/scalekit-inc/Nextjs-Django-Org-Switcher-Example) | Next.js frontend + Django backend, org switching |
-| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) | Google, Okta integration patterns |
-| Passwordless | [passwordless-auth-demos](https://github.com/scalekit-developers/passwordless-auth-demos) | Passwordless authentication flows |
-| Managed login | [managed-loginbox-expressjs-demo](https://github.com/scalekit-developers/managed-loginbox-expressjs-demo) | Hosted login UI with Express |
-| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) | Workspace creation, user provisioning, RBAC, SSO |
-
-**AgentKit — Agent and MCP examples**
-
-| Framework / Pattern | Repo | What it shows |
-|---------------------|------|---------------|
-| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) | Python LangChain agent with Scalekit auth |
-| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) | Google ADK agent with authenticated tools |
-| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) | Vercel AI SDK + Scalekit connectors |
-| Apify Actor | [agentkit-apify-actor-example](https://github.com/scalekit-developers/agentkit-apify-actor-example) | OAuth auth, YouTube → Notion agent |
-| LiteLLM | [litellm-agentkit-inbox-triage](https://github.com/scalekit-developers/litellm-agentkit-inbox-triage) | Inbox triage with Gmail, GitHub, Slack |
-| MCP Auth (multi-framework) | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) | MCP OAuth 2.1 demos |
-| MCP + FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) | FastMCP server with Scalekit auth |
-| MCP + BYOA | [byoa-demo-mcp](https://github.com/scalekit-inc/byoa-demo-mcp) | Bring your own auth + MCP |
-| MCP + Coffee Desk | [coffee-desk-mcp](https://github.com/scalekit-inc/coffee-desk-mcp) | Demo MCP server with roles/permissions |
-| Python connections | [python-connect-demos](https://github.com/scalekit-inc/python-connect-demos) | Python connection and identity workflows |
-| Agent auth examples | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) | Official AgentKit examples collection |
-| Node.js agents | [agent-node-demos](https://github.com/scalekit-inc/agent-node-demos) | TypeScript agent demos |
-| Workflow agents | [workflow-agents-demos](https://github.com/scalekit-developers/workflow-agents-demos) | Multi-step agent workflows |
-| Render deploy kit | [render-ai-agent-deploykit](https://github.com/scalekit-developers/render-ai-agent-deploykit) | Render Workflows + Scalekit + Claude |
-
-**Developer tools**
-
-| Tool | Repo | Purpose |
-|------|------|---------|
-| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) | Test auth flows without writing code |
-| Scalekit MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) | Manage orgs, users, connections via AI assistants |
-| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) | Postman/Bruno collections for Scalekit endpoints |
-| Documentation source | [developer-docs](https://github.com/scalekit-inc/developer-docs) | Docs site source (MDX) |
-
-**Frontend SDKs**
-
-| SDK | Repo | Purpose |
-|-----|------|---------|
-| React SDK | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) | React OIDC authentication |
-| Vue SDK | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) | Vue OIDC authentication |
-| Expo SDK | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) | Expo/React Native OAuth 2.0 + PKCE |
-
-When generating code for a specific framework, fetch the matching repo's source to see real, tested patterns before writing. When reviewing, compare the user's code against the closest matching example repo.
\ No newline at end of file
+For framework-specific example repos, see `references/EXAMPLE-REPOS.md`.
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md b/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
new file mode 100644
index 0000000..a66718b
--- /dev/null
+++ b/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
@@ -0,0 +1,61 @@
+# Example Repos
+
+Working examples by framework. Fetch the matching repo for real, tested patterns when generating or reviewing code.
+
+## SaaSKit — Auth examples
+
+| Framework | Repo | What it shows |
+|-----------|------|---------------|
+| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes |
+| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO flows |
+| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
+| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, sessions |
+| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO, middleware |
+| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0 |
+| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic |
+| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Django auth integration |
+| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Flask sessions |
+| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Spring Security, OIDC |
+| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, SSO |
+| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API, Laravel |
+| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login |
+| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
+| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE |
+
+## SaaSKit — Integration examples
+
+| Integration | Repo |
+|-------------|------|
+| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) |
+| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) |
+| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) |
+| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) |
+| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) |
+| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) |
+
+## AgentKit — Agent and MCP examples
+
+| Framework | Repo |
+|-----------|------|
+| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) |
+| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) |
+| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) |
+| MCP Auth | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) |
+| FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) |
+| Agent auth | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) |
+
+## Developer tools
+
+| Tool | Repo |
+|------|------|
+| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) |
+| MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) |
+| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) |
+
+## Frontend SDKs
+
+| SDK | Repo |
+|-----|------|
+| React | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) |
+| Vue | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) |
+| Expo | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) |
\ No newline at end of file
diff --git a/plugins/saaskit/skills/adding-api-auth/SKILL.md b/plugins/saaskit/skills/adding-api-auth/SKILL.md
index 7a3174a..6b2a240 100644
--- a/plugins/saaskit/skills/adding-api-auth/SKILL.md
+++ b/plugins/saaskit/skills/adding-api-auth/SKILL.md
@@ -373,3 +373,139 @@ func AuthenticateToken(sc scalekit.Scalekit) gin.HandlerFunc {
- **Rotate safely**: Create new key → update consumer → verify → invalidate old key (avoids downtime).
- **Use `expiry` for time-limited access**: Limits blast radius if a key is compromised.
- **Never log or commit keys**: Treat API keys like passwords — use encrypted secrets managers or env vars.
+
+---
+
+## Client Credentials (OAuth 2.0)
+
+For service-to-service (machine-to-machine) auth using JWT bearer tokens instead of opaque API keys. Use when APIs need scope-based access control, JWT validation via JWKS, or standard OAuth 2.0 client credentials flow.
+
+### Flow
+
+```
+Register client (your app) → Issue client_id + secret (Scalekit) →
+API client fetches bearer token → Your server validates JWT + scopes
+```
+
+### Register an API client for an organization
+
+One organization can have multiple API clients. `plain_secret` is **returned only once**.
+
+```python
+# Python
+from scalekit.v1.clients.clients_pb2 import OrganizationClient
+
+response = scalekit_client.m2m_client.create_organization_client(
+ organization_id="",
+ m2m_client=OrganizationClient(
+ name="GitHub Actions Deployment Service",
+ description="Deploys to production via GitHub Actions",
+ scopes=["deploy:applications", "read:deployments"], # resource:action pattern
+ audience=["deployment-api.acmecorp.com"],
+ custom_claims=[
+ {"key": "github_repository", "value": "acmecorp/inventory-service"},
+ {"key": "environment", "value": "production_us"}
+ ],
+ expiry=3600 # seconds; default 3600
+ )
+)
+client_id = response.client.client_id
+plain_secret = response.plain_secret # store securely; not retrievable again
+```
+
+### API client fetches a bearer token
+
+Runs inside the **API client's** code, not your server:
+
+```bash
+curl -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "grant_type=client_credentials" \
+ -d "client_id=" \
+ -d "client_secret="
+```
+
+Response includes `access_token` (JWT), `token_type`, `expires_in`, and `scope`.
+
+### Validate the JWT on your API server
+
+**Do this on EVERY request. Never trust unverified tokens.**
+
+```python
+# Python — SDK handles JWKS automatically
+token = request.headers.get("Authorization", "").removeprefix("Bearer ")
+try:
+ claims = scalekit_client.validate_access_token_and_get_claims(token=token)
+ # claims["scopes"] → list of granted scopes
+except Exception:
+ return 401 # invalid or expired
+```
+
+```javascript
+// Node.js — manual JWKS + JWT verify
+import jwksClient from 'jwks-rsa';
+import jwt from 'jsonwebtoken';
+
+const jwks = jwksClient({
+ jwksUri: `${process.env.SCALEKIT_ENVIRONMENT_URL}/.well-known/jwks.json`,
+ cache: true
+});
+
+async function verifyToken(token) {
+ const decoded = jwt.decode(token, { complete: true });
+ const key = await jwks.getSigningKey(decoded.header.kid);
+ return jwt.verify(token, key.getPublicKey(), {
+ algorithms: ['RS256'],
+ complete: true
+ }).payload;
+}
+```
+
+### Enforce scopes in middleware
+
+```python
+# Python — Flask
+def require_scope(scope):
+ def decorator(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ token = request.headers.get("Authorization", "").removeprefix("Bearer ")
+ if not token:
+ return jsonify({"error": "Missing token"}), 401
+ try:
+ claims = scalekit_client.validate_access_token_and_get_claims(token=token)
+ except Exception:
+ return jsonify({"error": "Invalid token"}), 401
+ if scope not in claims.get("scopes", []):
+ return jsonify({"error": "Insufficient permissions"}), 403
+ return f(*args, **kwargs)
+ return wrapper
+ return decorator
+```
+
+```javascript
+// Node.js — Express
+function requireScope(scope) {
+ return async (req, res, next) => {
+ const token = (req.headers.authorization || '').replace('Bearer ', '');
+ if (!token) return res.status(401).send('Missing token');
+ try {
+ const payload = await verifyToken(token);
+ if (!payload.scopes?.includes(scope))
+ return res.status(403).send('Insufficient permissions');
+ req.tokenClaims = payload;
+ next();
+ } catch {
+ res.status(401).send('Invalid token');
+ }
+ };
+}
+```
+
+### Client credentials key rules
+
+- `plain_secret` is **returned once only** — instruct customers to store it immediately.
+- Always validate tokens **server-side** before trusting claims.
+- Cache JWKS keys (avoid fetching on every request); rotate on `kid` mismatch.
+- Use `resource:action` scope naming (e.g. `deployments:read`, `applications:create`).
+- An `organization_id` maps to one customer; multiple API clients per org are supported.
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
index 6863097..4421637 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
@@ -1,55 +1,19 @@
---
name: adding-mcp-oauth
-description: Adds OAuth 2.1 authorization to Model Context Protocol servers using Scalekit. Covers Streamable HTTP transport, token validation middleware, and scope-based authorization for Node.js and Python. Use when securing MCP servers, implementing authentication for AI hosts like Claude Desktop or Cursor.
+description: Guides users through adding OAuth 2.1 authorization to MCP servers using Scalekit — configures discovery endpoints, sets up token validation middleware, and enables scope-based tool authorization. Use when setting up MCP servers, implementing authentication for AI hosts like Claude Desktop, Cursor, or VS Code, or when users mention MCP security, OAuth, or Scalekit integration.
---
# Adding OAuth 2.1 Authorization to MCP Servers
-Secure your MCP server with production-ready OAuth 2.1 authorization using Scalekit. This enables authenticated access through AI hosts like Claude Desktop, Cursor, and VS Code.
+## Prerequisite: HTTP transport
-## Critical Prerequisites
+MCP OAuth requires **Streamable HTTP** transport. Stdio does not support OAuth.
-⚠️ **MCP OAuth requires HTTP-based transport (Streamable HTTP)**: OAuth 2.1 authentication only works when your MCP server is exposed over **HTTP** using the **Streamable HTTP** transport. The standard `StdioServerTransport` (stdin/stdout) does **not** support OAuth flows.
+**Node.js:** Use `StreamableHTTPServerTransport` from `@modelcontextprotocol/sdk/server/streamableHttp.js`
-**Node.js requirement:**
-```javascript
-import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
-```
-
-**Python requirement (Streamable HTTP via ASGI app):**
-
-In Python, the practical equivalent of Node’s `StreamableHTTPServerTransport` is to **create a Streamable HTTP ASGI app** and run it behind an ASGI server (Uvicorn/Hypercorn). The official Python SDK exposes this as `streamable_http_app()` (convenience) or `create_streamable_http_app(...)` (lower-level).
-
-**Accurate Python snippet (FastMCP + Streamable HTTP):**
-```python
-from mcp.server.fastmcp import FastMCP
-
-mcp = FastMCP("My MCP Server")
+**Python:** Use `mcp.streamable_http_app(path="/mcp")` and run with `uvicorn module:app`
-@mcp.tool
-def ping() -> str:
- return "pong"
-
-# HTTP-based transport required for OAuth-capable deployments
-app = mcp.streamable_http_app(path="/mcp")
-```
-
-**Lower-level equivalent (explicit constructor):**
-```python
-from mcp.server.fastmcp import FastMCP
-from fastmcp.server.http import create_streamable_http_app
-
-mcp = FastMCP("My MCP Server")
-app = create_streamable_http_app(server=mcp, streamable_http_path="/mcp")
-```
-
-Notes:
-- The imports above match the **official** Python MCP SDK on PyPI (`mcp`). See: `https://pypi.org/project/mcp/1.9.1/`
-- The result is an **ASGI `app`** you run with an ASGI server (e.g. `uvicorn module:app`)—this is **Streamable HTTP**, not stdio.
-- SSE-only transports are not the same as Streamable HTTP; for OAuth with MCP hosts (Claude Desktop/Cursor/VS Code), use Streamable HTTP. See: `https://gofastmcp.com/python-sdk/fastmcp-server-http`
- - Example run: `uvicorn your_module:app --host 0.0.0.0 --port 8000`
-
-If your MCP server currently uses stdio transport, you must migrate to HTTP-based transport before implementing OAuth. See [MCP Transport Documentation](https://spec.modelcontextprotocol.io/specification/architecture/#transports) for migration guidance.
+If currently using stdio, migrate to HTTP first. See [MCP Transport Docs](https://spec.modelcontextprotocol.io/specification/architecture/#transports).
## Setup workflow
@@ -328,95 +292,13 @@ curl https:///.well-known/oauth-protected-resource
```
Expected: JSON with `resource`, `authorization_servers`, and `scopes_supported`.
-### Testing checklist (after verification passes)
-- [ ] Test with Claude Desktop
-- [ ] Test with Cursor
-- [ ] Test with VS Code
-- [ ] Verify token validation rejects invalid tokens
-- [ ] Verify scope-based authorization (if implemented)
-
-### Production deployment checklist
-- [ ] Configure CORS policies for endpoints
-- [ ] Set up monitoring and logging for auth events
-- [ ] Use HTTPS for all communications
-- [ ] Store credentials in environment variables or secret management
-- [ ] Configure appropriate token lifetimes
-- [ ] Document authentication flow for users
-
-## Additional authentication methods
-
-Beyond OAuth 2.1, enable these methods through Scalekit (no code changes needed):
-
-**Enterprise SSO**: Organizations authenticate through Okta, Azure AD, Google Workspace
-- Requires organization admins to register domains with Scalekit
-- Centralized access control through enterprise identity systems
-
-**Social logins**: Users authenticate via Google, GitHub, Microsoft
-- Quick onboarding for individual users
-- Reduced friction for personal and small team use
-
-**Custom auth**: Use your own authentication system
-- Integrate existing user management
-- Maintain full control over authentication flow
-
-See Scalekit documentation for configuration details.
-
-## Framework-specific guides
-
-For detailed implementation guides with specific frameworks:
-- **FastMCP**: 5-line integration with Scalekit provider (simplest approach)
-- **Express.js**: Full OAuth implementation with manual middleware (most control)
-- **FastAPI + FastMCP**: Python-based implementation with custom middleware
-
-See [Complete Working Examples](#complete-working-examples) below for production-ready code.
-
-## Complete Working Examples
-
-Production-ready examples demonstrating different implementation approaches:
-
-### FastMCP (5-Line OAuth Integration)
-**Reference:** [fastmcp-reference.md](fastmcp-reference.md)
-- Simplest approach with built-in OAuth provider
-- Automatic token validation and scope enforcement
-- Complete todo server with CRUD operations
-- **GitHub:** [todo-fastmcp](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/todo-fastmcp)
-
-### Express.js (Full Manual OAuth)
-**Reference:** [express-reference.md](express-reference.md)
-- Complete control over authentication middleware
-- Modular architecture with transport, tools, auth layers
-- Production-ready with CORS, logging, error handling
-- **GitHub:** [greeting-mcp-node](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/greeting-mcp-node)
-
-### FastAPI + FastMCP (Custom Middleware)
-**Reference:** [fastapi-reference.md](fastapi-reference.md)
-- Python-based with custom authentication middleware
-- Combines FastAPI's HTTP control with FastMCP's tooling
-- Ideal for existing FastAPI applications
-- **GitHub:** [greeting-mcp-python](https://github.com/scalekit-inc/mcp-auth-demos/tree/main/greeting-mcp-python)
-
-### Scalekit MCP Server (Production Reference)
-**Reference:** [scalekit-mcp-server.md](../../references/scalekit-mcp-server.md)
-- Official Scalekit production implementation
-- Comprehensive tooling for identity management
-- Advanced patterns: scope-based auth, pagination, multi-step operations
-- Demonstrates best practices for complex MCP servers
-- **GitHub:** [scalekit-inc/scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server)
-
-### Choosing an Example
-
-| Example | Complexity | Best For | Control Level |
-|----------|-------------|-----------|---------------|
-| FastMCP | Simplest | Quick prototypes, minimal code | Low (automatic) |
-| Express.js | Medium | Production Node.js, custom logic | High (manual) |
-| FastAPI + FastMCP | Medium | Production Python, existing apps | High (manual) |
-| Scalekit Server | Advanced | Complex apps, reference patterns | Very High |
-
-All examples include:
-- Complete source code
-- Setup instructions
-- Environment configuration
-- Testing guidance
+After verification passes, test with Claude Desktop, Cursor, and VS Code. Ensure invalid tokens get 401, and scope-based authorization (if implemented) rejects insufficient scopes.
+
+## Framework-specific references
+
+- FastMCP (Python, simplest): [fastmcp-reference.md](fastmcp-reference.md)
+- Express.js (Node.js): [express-reference.md](express-reference.md)
+- FastAPI + FastMCP (Python, custom middleware): [fastapi-reference.md](fastapi-reference.md)
## Common issues
@@ -434,17 +316,4 @@ All examples include:
- Check token includes required scopes
- Ensure scope strings match exactly (case-sensitive)
-## Architecture summary
-
-**Scalekit OAuth server**:
-- Authenticates users and agents
-- Issues access tokens with scopes
-- Manages OAuth 2.1 flows
-- Supports dynamic client registration
-
-**Your MCP server**:
-- Validates incoming tokens
-- Enforces permissions from token scopes
-- Executes tool calls for authorized requests
-This separation ensures clean boundaries: Scalekit handles identity and token issuance, your server focuses on business logic.
diff --git a/plugins/saaskit/skills/implementing-access-control/SKILL.md b/plugins/saaskit/skills/implementing-access-control/SKILL.md
index e383394..3b0c835 100644
--- a/plugins/saaskit/skills/implementing-access-control/SKILL.md
+++ b/plugins/saaskit/skills/implementing-access-control/SKILL.md
@@ -1,14 +1,12 @@
---
name: implementing-access-control
-description: Implements server-side RBAC and permission checks by validating access tokens, extracting roles and permissions, and enforcing them with middleware or decorators. Use when building authorization around Scalekit tokens.
+description: Implements server-side RBAC and permission checks by validating and decoding Scalekit access tokens, extracting roles/permissions, and enforcing them with middleware/decorators at route boundaries. Use when adding role-based access control, protecting routes or endpoints, building auth middleware, or checking JWT permissions with Scalekit tokens.
---
# Implementing access control (Scalekit FSA)
## When to use
-Use this Skill after authentication is working and the app must authorize access to routes/actions by inspecting the user's access token for `roles` and `permissions`.
-Scalekit can embed these authorization details in the access token during the authentication flow, so the app can make decisions without extra API calls.
-Always validate the token's integrity before trusting any embedded roles/permissions.
+After authentication is working and the app must authorize access to routes/actions by inspecting the user's access token for `roles` and `permissions`.
## Workflow
1. Validate the access token (expiry, issuer/audience as applicable) and then decode it to extract `sub`, `oid`, `roles`, and `permissions`.
@@ -31,7 +29,7 @@ const validateAndExtractAuth = async (req, res, next) => {
const isValid = await scalekit.validateAccessToken(accessToken);
if (!isValid) return res.status(401).json({ error: "Invalid or expired token" });
- const tokenData = await dessToken(accessToken); // JWT decode library
+ const tokenData = await decodeToken(accessToken); // JWT decode library
req.user = {
id: tokenData.sub,
organizationId: tokenData.oid,
@@ -104,16 +102,36 @@ def require_permission(permission):
return decorator
```
-## Patterns and pitfalls
+## Verification
-Prefer roles for broad tiers (admin/manager/member) and permissions for granular actions like `projects:create` or `tasks:assign`.
-Common patterns include "admin bypass" (admins skip some permission checks) and "resource ownership" (user can edit only their own resource unless elevated).
-Avoid building authorization solely in the frontend because it can be bypassed.
+After implementing, test these cases:
+
+```bash
+# Test with a valid token that has the required role
+curl -H "Cookie: accessToken=" http://localhost:3000/api/admin/users
+# Expected: 200
+
+# Test with a token missing the required role
+curl -H "Cookie: accessToken=" http://localhost:3000/api/admin/users
+# Expected: 403 {"error": "Access denied. Required role: admin"}
+
+# Test with an expired/invalid token
+curl -H "Cookie: accessToken=expired_token" http://localhost:3000/api/projects
+# Expected: 401 {"error": "Invalid or expired token"}
+```
+
+If 403 isn't returned for unauthorized users, check that the middleware chain order is correct: `validateAndExtractAuth` must run before `requireRole`/`requirePermission`.
+
+## Patterns
+
+- Roles for broad tiers (admin/manager/member), permissions for granular actions (`projects:create`, `tasks:assign`)
+- Admin bypass: admins skip permission checks for operational tasks
+- Resource ownership: user can edit only their own resource unless role-elevated
## Checklist
-- Token is validated before decoding/using claims.
-- `roles` and `permissions` are normalizeays and attached to request context.
-- Every protected route applies `requireRole(...)` and/or `requirePermission(...)` at the boundary.
-- Permission names follow a consistent `resource:action` convention.
-- Client-side checks are treated as UX only; server-side checks are authoritative.
+- [ ] Token validated before decoding claims
+- [ ] `roles` and `permissions` normalized as arrays in request context
+- [ ] Every protected route uses `requireRole(...)` and/or `requirePermission(...)` at the boundary
+- [ ] Permission names follow `resource:action` convention
+- [ ] Server-side checks are authoritative; client-side checks are UX only
diff --git a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index 0bfc78a..aa9d09e 100644
--- a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -5,67 +5,575 @@ description: Implements enterprise SSO and authentication flows using Scalekit,
# Implement Modular SSO
-Use this skill when the product already has user management and session management, and only needs enterprise login and connection orchestration from Scalekit.
+## Quick Start
-## Before You Start
+**Choose your authentication mode:**
+- **Modular SSO**: You manage users and sessions (covered here)
+- **SaaSKit (Full-Stack Auth)**: Scalekit manages users and sessions (built-in SSO)
-Disable Full-Stack Auth in the Scalekit dashboard so the application can run in Modular SSO mode.
+This skill covers Modular SSO for applications with existing user management.
-## Required Configuration
+## Implementation Workflow
-- `SCALEKIT_ENVIRONMENT_URL`
-- `SCALEKIT_CLIENT_ID`
-- `SCALEKIT_CLIENT_SECRET`
+Copy this checklist and track progress:
-## Working Checklist
+```
+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
+```
+
+## Step 1: Configure Modular Auth Mode
+
+**Action**: Configure environment for Modular SSO:
+1. Navigate to Dashboard > Authentication > General
+2. Under "Full-Stack Auth" section, click "Disable Full-Stack Auth"
+
+**Result**: System ready for modular integration.
+
+## Step 2: Install and Configure SDK
+
+### Installation
+
+Choose the SDK for the project's tech stack:
+
+**Node.js:**
+```bash
+npm install @scalekit-sdk/node
+```
+
+**Python:**
+```bash
+pip install scalekit-sdk-python
+```
+
+**Go:**
+```bash
+go get github.com/scalekit-inc/scalekit-sdk-go
+```
-```text
-Modular SSO:
-- [ ] Configure the app for modular auth mode
-- [ ] Initialize the Scalekit SDK
-- [ ] Generate authorization URLs
-- [ ] Handle IdP-initiated login
-- [ ] Process the callback
-- [ ] Validate tokens and map the user
-- [ ] Test enterprise onboarding
+**Java:**
+```xml
+
+ com.scalekit
+ scalekit-sdk-java
+
```
-## Connection Routing Options
+### Environment Configuration
+
+Add these credentials to `.env` file (fetch from Dashboard > Developers > Settings > API credentials):
+
+```env
+SCALEKIT_ENVIRONMENT_URL=
+SCALEKIT_CLIENT_ID=
+SCALEKIT_CLIENT_SECRET=
+```
+
+---
+
+## Step 3: Generate Authorization URL
+
+Create authorization URL to redirect users to their identity provider.
+
+### SSO Connection Selectors (Priority Order)
-Choose one routing input and keep it consistent:
+Use ONE of these identifiers (evaluated in precedence order):
-- `connectionId` for a direct enterprise connection
-- `organizationId` for the customer organization
-- `loginHint` when domain-based discovery is your preferred entrypoint
+1. **connectionId** (highest) - Direct SSO connection reference
+2. **organizationId** - Routes to organization's active SSO
+3. **loginHint** - Extracts domain from email to find connection
-## Node.js Sketch
+### Implementation Pattern
+
+**Node.js:**
+```javascript
+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: 'user@example.com'
+};
-```ts
const authUrl = scalekit.getAuthorizationUrl(
'https://yourapp.com/auth/callback',
- {
- organizationId: 'org_123',
- }
+ options
);
+
+// Redirect user to authUrl
```
-For IdP-initiated login:
+**Python:**
+```python
+from scalekit import ScalekitClient, AuthorizationUrlOptions
-```ts
-const claims = await scalekit.getIdpInitiatedLoginClaims(idpInitiatedLogin);
-const authUrl = scalekit.getAuthorizationUrl(
- 'https://yourapp.com/auth/callback',
- {
- connectionId: claims.connection_id,
- organizationId: claims.organization_id,
- loginHint: claims.login_hint,
- state: claims.relay_state,
+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):**
+```
+/oauth/authorize?
+ response_type=code&
+ client_id=&
+ redirect_uri=&
+ scope=openid profile email&
+ organization_id=
+```
+
+## Step 4: Handle IdP-Initiated SSO
+
+**CRITICAL**: Implement this to support users who start login from their identity provider portal.
+
+### Why This Matters
+
+IdP-initiated SSO converts potentially insecure flows into secure SP-initiated flows, protecting against SAML assertion theft and replay attacks.
+
+### Configuration Required
+
+1. Set initiate login endpoint: Dashboard > Authentication > Redirects
+2. Configure endpoint: `https://yourapp.com/login`
+
+### Implementation
+
+**Node.js:**
+```javascript
+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:**
+```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)
+```
+
+---
+
+## Step 5: Process Authentication Callback
+
+Handle the callback after successful IdP authentication.
+
+### Callback Endpoint Setup
+
+1. Create endpoint: `/auth/callback`
+2. Register in Dashboard > Authentication > Redirect URLs > Allowed Callback URLs
+
+### Implementation
+
+**Node.js:**
+```javascript
+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:**
+```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')
+```
+
+---
+
+## Step 6: Validate Tokens
+
+**ALWAYS** validate tokens before trusting claims.
+
+**Node.js:**
+```javascript
+// Validate ID token
+const idTokenClaims = await scalekit.validateToken(result.idToken);
+
+// Validate access token
+const accessTokenClaims = await scalekit.validateToken(result.accessToken);
+```
+
+**Python:**
+```python
+id_token_claims = scalekit.validate_token(result['id_token'])
+access_token_claims = scalekit.validate_token(result['access_token'])
+```
+
+### Token Structure
+
+**ID Token includes:**
+- `email`: User's email address
+- `given_name`, `family_name`: User's name
+- `sub`: Unique user identifier (format: `connectionId;userId`)
+- `oid`: Organization ID
+- `amr`: Authentication method (SSO connection ID)
+
+**Access Token includes:**
+- `sub`: User identifier
+- `exp`: Expiration timestamp
+- `client_id`: Your application client ID
+
+## Step 7: Test SSO Integration
+
+Use the built-in IdP Simulator for comprehensive testing.
+
+### Test Organization Setup
+
+Your environment includes pre-configured test organization with domains:
+- `@example.com`
+- `@example.org`
+
+### Testing Workflow
+
+1. **Find test organization**: Dashboard > Organizations
+2. **Use test selector**: Pass one of these in authorization URL:
+ - Email with `@example.com` domain
+ - Test organization's connection ID
+ - Organization ID
+3. **Simulate SSO flow**: IdP Simulator appears (mimics customer's IdP)
+4. **Complete authentication**: Enter test credentials
+5. **Verify callback**: Check user profile received correctly
+
+### Test Scenarios
+
+Test ALL three scenarios:
+1. **SP-initiated SSO**: User starts login from your app
+2. **IdP-initiated SSO**: User starts from IdP portal
+3. **Domain-based routing**: User enters email, auto-routes to IdP
+
+---
+
+## Step 8: Customer Onboarding
+
+Enable SSO for enterprise customers through self-service Admin Portal.
+
+### Quick Onboarding
+
+**Create organization**: Dashboard > Organizations > New Organization
+
+**Generate portal link** (Node.js):
+```javascript
+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](https://docs.scalekit.com/guides/integrations/sso-integrations/) — provider-specific steps for Okta, Azure AD, Google Workspace, and others.
+
+### Embedded Portal (Advanced)
+
+Embed Admin Portal in your app for seamless experience:
+
+```javascript
+// Backend: Generate portal link
+const portalLink = await scalekit.organization.generatePortalLink(orgId);
+res.json({ portalUrl: portalLink.location });
+```
+
+```html
+
+
+```
+## Advanced Patterns
+
+### Pre-Check SSO Availability
+
+Prevent failed redirects by checking SSO configuration before redirecting:
+
+**Node.js:**
+```javascript
+const domain = email.split('@')[1].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();
+}
+```
+
+### Domain Verification
+
+Enable seamless routing by verifying customer domains:
+1. Customer verifies domain (e.g., `@megacorp.org`) in Admin Portal
+2. Users sign in without organization selection
+3. Scalekit auto-routes based on email domain
+
+### Session Management Best Practices
+
+**Set secure session configuration:**
+```javascript
+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:**
+```javascript
+// Check token expiration
+if (Date.now() / 1000 > accessTokenClaims.exp) {
+ // Redirect to re-authentication
+ return res.redirect('/login');
+}
```
-## Review Guidance
+## Integration with Existing Auth Systems
+
+### Auth0 Integration
+
+Configure Scalekit as Custom Social Connection in Auth0:
+1. Auth0 Dashboard > Authentication > Social > Create Connection
+2. Use Scalekit OAuth2 endpoints
+3. Map Scalekit user attributes to Auth0 profile
+
+### Firebase Integration
+
+Add Scalekit as Custom Auth Provider:
+1. Use Firebase Custom Token generation
+2. Exchange Scalekit tokens for Firebase tokens
+3. Maintain session with Firebase SDK
+
+### AWS Cognito Integration
+
+Configure Scalekit as SAML Identity Provider:
+1. Cognito User Pool > Identity Providers > SAML
+2. Use Scalekit metadata URL
+3. Map attributes to Cognito user attributes
+
+## Security Checklist
+
+Before production deployment, verify:
+
+- [ ] Environment variables stored securely (never in code)
+- [ ] HTTPS enforced on all endpoints
+- [ ] Tokens validated before trusting claims
+- [ ] Session cookies use `secure` and `httpOnly` flags
+- [ ] CSRF protection enabled
+- [ ] Callback URLs registered in Scalekit dashboard
+- [ ] Error messages don't expose sensitive information
+- [ ] Rate limiting implemented on auth endpoints
+- [ ] Logging configured (without exposing tokens)
+
+## Troubleshooting
+
+### "Invalid redirect_uri" Error
+
+**Cause**: Callback URL not registered in dashboard
+**Fix**: Add URL to Dashboard > Authentication > Redirect URLs
+
+### "Organization not found" Error
+
+**Cause**: Invalid organization ID or user doesn't belong to organization
+**Fix**: Verify organization ID and user's email domain
+
+### IdP-Initiated SSO Not Working
+
+**Cause**: Initiate login URL not configured
+**Fix**: Set URL in Dashboard > Authentication > Redirects
+
+### Token Validation Fails
+
+**Cause**: Token expired or invalid signature
+**Fix**: Check token expiration and environment URL configuration
+
+## Common Patterns
+
+### Multi-Tenant Architecture
+
+```javascript
+// Determine organization from subdomain
+const subdomain = req.hostname.split('.');
+const organization = await getOrganizationBySubdomain(subdomain);
+
+const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
+ organizationId: organization.scalekitOrgId
+});
+```
+
+### Step-Up Authentication
+
+```javascript
+// Require re-authentication for sensitive operations
+if (requiresStepUp && !session.recentAuth) {
+ return res.redirect('/auth/step-up');
+}
+```
+
+### Logout Implementation
+
+```javascript
+app.post('/logout', (req, res) => {
+ req.session.destroy();
+ res.redirect('/');
+});
+```
+
+## Reference
+
+**Scalekit Dashboard**: [https://app.scalekit.com](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](https://docs.scalekit.com)
+
+## Implementation Notes
+
+**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
+
+## When to switch skills
-- Treat IdP-initiated login as a translation into a secure SP-initiated flow, not as a shortcut around normal callback handling.
-- Keep enterprise onboarding decisions explicit: who creates the connection, how users are mapped, and where login is initiated.
-- Map validated claims into the app's existing user model and session model instead of duplicating local account logic.
+- Use `implementing-saaskit` for the base auth flow that SSO builds on.
+- Use `implementing-scim-provisioning` for automated user provisioning alongside SSO.
+- Use `production-readiness-saaskit` to validate SSO configuration before launch.
\ No newline at end of file
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index 1468469..f071ce2 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -3,292 +3,105 @@ name: implementing-saaskit-python
description: Implements Scalekit SaaSKit authentication in Python web frameworks (Django, FastAPI, or Flask) using scalekit-sdk-python. Use when adding auth to a Django, FastAPI, or Flask project, or when the user mentions Python web authentication with Scalekit.
---
-# Scalekit Auth — Django
+# SaaSKit Auth — Python
-Reference repo: [scalekit-inc/scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example)
+Implements Scalekit authentication in Django, FastAPI, or Flask using `scalekit-sdk-python`.
-## Project structure
+## Framework detection
-```
-auth_app/
-├── scalekit_client.py # ScalekitClient class + scalekit_client() singleton
-├── views.py # All auth + protected views
-├── decorators.py # @login_required, @permission_required('perm:name')
-├── middleware.py # ScalekitTokenRefreshMiddleware (auto token refresh)
-└── urls.py # URL patterns (app_name = 'auth_app')
-
-scalekit_django_auth/
-└── settings.py # SCALEKIT_* settings, middleware registration, session config
-```
+Before generating code, detect which framework is in use:
-## Environment variables
-
-```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.io
-SCALEKIT_CLIENT_ID=your-client-id
-SCALEKIT_CLIENT_SECRET=your-client-secret
-SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
-# SCALEKIT_SCOPES is set directly in settings.py, not from env
-```
+1. Check for `django` in `requirements.txt` / `pyproject.toml` → Django
+2. Check for `fastapi` → FastAPI
+3. Check for `flask` → Flask
+4. If unclear, ask the user.
-> `SCALEKIT_ENV_URL` also falls back to `SCALEKIT_DOMAIN` for backward compatibility.
-> `SCALEKIT_REDIRECT_URI` has no trailing slash — this avoids Django redirect issues.
-
-## Django settings (`settings.py`)
-
-Key non-obvious settings to include:
-
-```python
-INSTALLED_APPS = [
- 'django.contrib.contenttypes',
- 'django.contrib.sessions', # Required for session storage
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'auth_app',
-]
+## Quick setup
-MIDDLEWARE = [
- # ...
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'auth_app.middleware.ScalekitTokenRefreshMiddleware', # MUST come after SessionMiddleware
- # ...
-]
-
-SESSION_ENGINE = 'django.contrib.sessions.backends.db'
-SESSION_COOKIE_AGE = 3600
-SESSION_COOKIE_HTTPONLY = True
-SESSION_COOKIE_SAMESITE = 'Lax'
-SESSION_SAVE_EVERY_REQUEST = True # Required — ensures OAuth state persists across requests
-
-SCALEKIT_ENV_URL = os.getenv('SCALEKIT_ENV_URL', os.getenv('SCALEKIT_DOMAIN', ''))
-SCALEKIT_CLIENT_ID = os.getenv('SCALEKIT_CLIENT_ID', '')
-SCALEKIT_CLIENT_SECRET = os.getenv('SCALEKIT_CLIENT_SECRET', '')
-SCALEKIT_REDIRECT_URI = os.getenv('SCALEKIT_REDIRECT_URI', 'http://localhost:8000/auth/callback')
-SCALEKIT_SCOPES = 'openid profile email offline_access' # offline_access required for refresh token
-
-LOGIN_URL = '/login'
+```bash
+pip install scalekit-sdk-python python-dotenv
```
-## SDK client (`auth_app/scalekit_client.py`)
-
-Lazy singleton — always use `scalekit_client()`, never instantiate directly:
-
```python
-from auth_app.scalekit_client import scalekit_client
+import os
+from dotenv import load_dotenv
+from scalekit import ScalekitClient
-client = scalekit_client() # raises ValueError with helpful message if env vars missing
-```
+load_dotenv()
-SDK import paths:
-```python
-from scalekit import ScalekitClient as SDKClient
-from scalekit.common.scalekit import (
- AuthorizationUrlOptions,
- CodeAuthenticationOptions,
- TokenValidationOptions,
- LogoutUrlOptions,
+sc = ScalekitClient(
+ env_url=os.getenv("SCALEKIT_ENV_URL"),
+ client_id=os.getenv("SCALEKIT_CLIENT_ID"),
+ client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
```
-Key methods on `ScalekitClient`:
+## Framework routing
-| Method | SDK call | Returns |
-|---|---|---|
-| `get_authorization_url(state)` | `sdk_client.get_authorization_url(redirect_uri, options)` | `str` URL |
-| `exchange_code_for_tokens(code)` | `sdk_client.authenticate_with_code(code, redirect_uri, options)` | `dict` with `access_token`, `refresh_token`, `id_token`, `user`, `expires_in` |
-| `get_user_info(access_token)` | `sdk_client.validate_access_token_and_get_claims(token, options)` | `dict` claims |
-| `refresh_access_token(refresh_token)` | `sdk_client.refresh_access_token(refresh_token)` | `dict` with `access_token`, `refresh_token` |
-| `validate_token_and_get_claims(token)` | `sdk_client.validate_access_token_and_get_claims(token, options)` | `dict` claims |
-| `has_permission(access_token, permission)` | validates claims, checks permission key chain | `bool` |
-| `logout(access_token, id_token)` | `sdk_client.get_logout_url(options)` | `str` URL |
+Each framework has different patterns for routes, middleware, and session storage:
-## Session storage schema
+| Framework | Auth middleware | Session store | Reference |
+|---|---|---|---|
+| Django | Custom middleware class | Django sessions (DB/cache) | [django-reference.md](django-reference.md) |
+| FastAPI | Dependency injection | Server-side or JWT | [fastapi-reference.md](fastapi-reference.md) |
+| Flask | `@login_required` decorator | Flask-Session | [flask-reference.md](flask-reference.md) |
-All auth state is stored in Django's session (no extra DB tables):
+## Default workflow (FastAPI example)
```python
-request.session['scalekit_user'] = {
- 'sub', 'email', 'name', 'given_name', 'family_name',
- 'preferred_username', 'claims' # full access token claims dict
-}
-request.session['scalekit_tokens'] = {
- 'access_token', 'refresh_token', 'id_token',
- 'expires_at', # ISO 8601 string (timezone-aware)
- 'expires_in' # int seconds
-}
-request.session['scalekit_roles'] = [] # from access token claims
-request.session['scalekit_permissions'] = [] # from access token claims
-```
-
-Check authentication anywhere: `request.session.get('scalekit_user')` → truthy if logged in.
-
-## Auth flow
+import os, secrets
+from fastapi import FastAPI, Request, Response
+from fastapi.responses import RedirectResponse
+from dotenv import load_dotenv
+from scalekit import ScalekitClient
-### Login (`login_view` — GET `/login/`)
+load_dotenv()
-```python
-state = secrets.token_urlsafe(32)
-request.session['oauth_state'] = state
-request.session.save() # Explicit save — required for state to survive redirect
-auth_url = client.get_authorization_url(state=state)
-# Pass auth_url to template; user clicks it to redirect to Scalekit
-```
+app = FastAPI()
+REDIRECT_URI = os.getenv("SCALEKIT_REDIRECT_URI", "http://localhost:8000/auth/callback")
-### Callback (`callback_view` — GET `/auth/callback`)
-
-1. Validate `state` param vs `request.session['oauth_state']` → render error on mismatch
-2. `request.session.pop('oauth_state', None)`
-3. `token_response = client.exchange_code_for_tokens(code)`
-4. `user_obj = token_response.get('user', {})` — camelCase fields (`givenName`, `familyName`, `id`)
-5. `user_info = client.get_user_info(access_token)` — snake_case claims for roles/permissions
-6. Name resolution: `user_obj.name` → `givenName + familyName` → `user_info claims` → `email`
-7. `expires_at = timezone.now() + timedelta(seconds=expires_in)`
-8. Write `scalekit_user`, `scalekit_tokens`, `scalekit_roles`, `scalekit_permissions` to session
-9. Redirect to `auth_app:dashboard`
-
-Permission claim fallback chain (same as Node SDK):
-```python
-permissions = (
- claims.get('permissions', []) or
- claims.get('https://scalekit.com/permissions', []) or
- claims.get('scalekit:permissions', []) or
- []
+sc = ScalekitClient(
+ env_url=os.getenv("SCALEKIT_ENV_URL"),
+ client_id=os.getenv("SCALEKIT_CLIENT_ID"),
+ client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
-```
-
-### Logout (`logout_view` — GET `/logout/`)
-
-```python
-logout_url = client.logout(access_token, id_token)
-# post_logout_redirect_uri = SCALEKIT_REDIRECT_URI.replace('/auth/callback', '')
-request.session.flush() # Wipes entire session
-return redirect(logout_url) # Server-side redirect (not JSON like Next.js)
-```
-
-### Token refresh — middleware (`auth_app/middleware.py`)
-
-`ScalekitTokenRefreshMiddleware` runs on every request. Skipped paths:
-`/login`, `/auth/callback`, `/logout`, `/static/`, `/sessions/refresh-token`
-
-Buffer: **1 minute** (vs 5 min in client `is_token_expired` helper).
-
-Also available as a manual API endpoint: `POST /sessions/refresh-token/` → `JsonResponse`.
-## Protecting views
+@app.get("/auth/login")
+def login(response: Response):
+ state = secrets.token_urlsafe(32)
+ response = RedirectResponse(sc.get_authorization_url(REDIRECT_URI, {"state": state}))
+ response.set_cookie("oauth_state", state, httponly=True, samesite="lax", secure=True)
+ return response
-```python
-from auth_app.decorators import login_required, permission_required
-
-@login_required
-def dashboard_view(request): ... # Redirects to /login?next= if unauthenticated
-
-@permission_required('organization:settings')
-def org_settings_view(request): ... # Renders permission_denied.html with 403 if missing
-```
-
-## URL configuration
-
-```python
-# auth_app/urls.py — app_name = 'auth_app'
-path('auth/callback', callback_view, name='callback'), # No trailing slash — intentional
-path('sessions/validate-token/', validate_token_view), # POST only
-path('sessions/refresh-token/', refresh_token_view), # POST only
-```
-
-Use `reverse('auth_app:dashboard')` / `{% url 'auth_app:login' %}` in templates.
-
-## Route map
-
-| URL | Auth | Notes |
-|---|---|---|
-| `/` | No | Redirects to dashboard if already logged in |
-| `/login/` | No | Generates auth URL, stores CSRF state |
-| `/auth/callback` | No | No trailing slash |
-| `/dashboard/` | `@login_required` | |
-| `/logout/` | `@login_required` | |
-| `/sessions/` | `@login_required` | |
-| `/sessions/validate-token/` | `@login_required` | POST |
-| `/sessions/refresh-token/` | `@login_required` | POST |
-| `/organization/settings/` | `@permission_required('organization:settings')` | |
-
-## Install
-
-```bash
-pip install scalekit-sdk-python python-dotenv django
-python manage.py migrate # Creates session table (db.sqlite3, zero-config)
-python manage.py runserver
-```
-
-## Tactics
-
-### SameSite=Lax — never Strict
-`SESSION_COOKIE_SAMESITE = 'Lax'` is correct. Do not change to `'Strict'` — it drops the session cookie on the cross-origin redirect from Scalekit back to `/auth/callback`, so `oauth_state` is unavailable and the CSRF check fails on every login.
+@app.get("/auth/callback")
+def callback(request: Request, code: str, state: str):
+ stored = request.cookies.get("oauth_state")
+ if not stored or stored != state:
+ return Response("CSRF mismatch", status_code=403)
+ result = sc.authenticate_with_code(code, REDIRECT_URI)
+ # Store result.user and tokens in your session mechanism
+ response = RedirectResponse("/dashboard")
+ response.delete_cookie("oauth_state")
+ return response
-### SESSION_SAVE_EVERY_REQUEST = True — why it matters
-The OAuth flow involves at least two redirects. Without `SESSION_SAVE_EVERY_REQUEST = True`, the session containing `oauth_state` may not be written to the database before Django redirects to Scalekit, causing a state mismatch on the callback. This setting ensures session writes happen on every response.
-
-### @csrf_exempt on the callback view
-The OAuth callback receives a GET request from Scalekit (an external origin). Django's CSRF middleware does not block GETs, but the OAuth `state` parameter already serves as the CSRF token for this flow. If you ever add a POST-based callback, exempt it explicitly:
-
-```python
-from django.views.decorators.csrf import csrf_exempt
-
-@csrf_exempt
-def callback_view(request): ...
+@app.get("/auth/logout")
+def logout(request: Request):
+ logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:8000"})
+ # Clear your session here
+ return RedirectResponse(logout_url)
```
-### Deep link preservation
-`@login_required` already appends `?next=` when redirecting. Read it in `login_view` and restore it after a successful callback:
+If `authenticate_with_code` raises an exception, verify the redirect URI matches the dashboard exactly.
-```python
-# In login_view
-next_url = request.GET.get('next', reverse('auth_app:dashboard'))
-request.session['next'] = next_url
-request.session.save() # explicit save before redirect
+For Django and Flask patterns, see the framework-specific references linked in the table above.
-# In callback_view — after writing session data
-next_url = request.session.pop('next', reverse('auth_app:dashboard'))
-if not next_url.startswith('/'): # prevent open redirect
- next_url = reverse('auth_app:dashboard')
-return redirect(next_url)
-```
-
-### Cache-Control: no-store on protected views
-Without this, the back button after logout serves a cached authenticated page:
+## Deep reference
-```python
-from django.views.decorators.cache import never_cache
+- Auth flows: [docs.scalekit.com/authenticate/fsa/quickstart](https://docs.scalekit.com/authenticate/fsa/quickstart/)
+- Sessions: [docs.scalekit.com/authenticate/fsa/sessions](https://docs.scalekit.com/authenticate/fsa/sessions/)
-@never_cache
-@login_required
-def dashboard_view(request): ...
-```
+## When to switch skills
-### AJAX: 401 instead of redirect
-If your frontend makes AJAX calls to protected views, return `401` instead of a redirect:
-
-```python
-from functools import wraps
-from django.http import JsonResponse
-
-def login_required_ajax(f):
- @wraps(f)
- def decorated(request, *args, **kwargs):
- if not request.session.get('scalekit_user'):
- if request.headers.get('Accept') == 'application/json':
- return JsonResponse({'error': 'Authentication required'}, status=401)
- return redirect(f"{reverse('auth_app:login')}?next={request.path}")
- return f(request, *args, **kwargs)
- return decorated
-```
-
-### Session fixation after login
-Call `request.session.cycle_key()` immediately after writing session data in `callback_view` to prevent session fixation — an attacker who planted a known session ID before login cannot hijack the authenticated session:
-
-```python
-# At the end of callback_view, after writing all session keys:
-request.session.cycle_key()
-return redirect(next_url)
-```
+- Use `implementing-saaskit` for the general (non-Python-specific) integration guide.
+- Use `managing-saaskit-sessions` for advanced session handling.
+- Use `implementing-access-control` for RBAC after auth is working.
diff --git a/plugins/saaskit/skills/implementing-saaskit/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
index 5bc1a16..f36bb4d 100644
--- a/plugins/saaskit/skills/implementing-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
@@ -3,7 +3,7 @@ name: implementing-saaskit
description: Implements Scalekit SaaSKit authentication (sign-up, login, logout, sessions) using JWT tokens across Node.js, Python, Go, Java, or PHP. Use when building or integrating user authentication with Scalekit, setting up OAuth callbacks, token refresh, or session handling.
---
-# Scalekit Full-Stack Authentication
+# Scalekit SaaSKit (Full-Stack Authentication)
## Setup
@@ -93,3 +93,25 @@ All SDK methods follow the same pattern across languages with minor naming conve
## What this unlocks
One integration enables: Magic Link & OTP, social sign-ins, enterprise SSO, workspaces, MCP authentication, SCIM provisioning, and user management.
+
+## Framework-specific references
+
+- Python (Django/FastAPI/Flask): use `implementing-saaskit-python` skill
+- Next.js: use `implementing-saaskit-nextjs` skill
+- Go (Gin): see [go-reference.md](go-reference.md)
+- Spring Boot: see [springboot-reference.md](springboot-reference.md)
+- Laravel: see [laravel-reference.md](laravel-reference.md)
+
+## Deep reference
+
+- Auth flows: [docs.scalekit.com/authenticate/fsa/quickstart](https://docs.scalekit.com/authenticate/fsa/quickstart/)
+- Sessions: [docs.scalekit.com/authenticate/fsa/sessions](https://docs.scalekit.com/authenticate/fsa/sessions/)
+- Access control: [docs.scalekit.com/authenticate/fsa/access-control](https://docs.scalekit.com/authenticate/fsa/access-control/)
+
+## When to switch skills
+
+- Use `managing-saaskit-sessions` for token storage, refresh middleware, and session auditing.
+- Use `implementing-access-control` for RBAC and permission enforcement.
+- Use `implementing-modular-sso` for enterprise SSO on top of SaaSKit.
+- Use `migrating-to-saaskit` when replacing an existing auth system.
+- Use `production-readiness-saaskit` before going live.
diff --git a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
index d1fa6a2..998920a 100644
--- a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
+++ b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
@@ -1,6 +1,6 @@
---
name: implementing-scim-provisioning
-description: Implements SCIM user provisioning using Scalekit directory API and webhooks for real-time user and group lifecycle management. Use when adding directory sync, user provisioning, or automated user lifecycle management.
+description: Sets up SCIM endpoints, handles directory webhook events, maps user attributes, and manages group memberships using Scalekit's Directory API. Use when the user asks to add SCIM, directory sync, user provisioning, deprovisioning, or lifecycle management to their application.
---
# SCIM Provisioning with Scalekit
@@ -32,7 +32,7 @@ Detect the project's language/framework from existing files (`package.json`, `re
| Stack | Install command |
|-------|----------------|
| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk-python` |
+| Python | `pip install scalekit-sdk` |
| Go | `go get github.com/scalekit/scalekit-go` |
| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` or `build.gradle` |
@@ -78,7 +78,7 @@ scalekit_client = ScalekitClient(
)
```
-For Go and Java patterns, see [REFERENCE.md](REFERENCE.md).
+For Go and Java patterns, see the [Scalekit SDK documentation](https://docs.scalekit.com/apis).
---
@@ -166,7 +166,7 @@ async def scalekit_webhook(request: Request):
return JSONResponse(status_code=201, content={"status": "processed"})
```
-For Go and Java, see [REFERENCE.md](REFERENCE.md).
+For Go and Java, see the [Scalekit SDK documentation](https://docs.scalekit.com/apis).
---
@@ -223,8 +223,26 @@ After deploying the webhook endpoint:
---
-## Reference files
+## Customer self-serve SCIM setup (admin portal)
-- Full Go/Java SDK examples → [REFERENCE.md](REFERENCE.md)
-- Webhook event payload schemas → [EVENTS.md](EVENTS.md)
-- RBAC group-to-role mapping patterns → [RBAC.md](RBAC.md)
+Let customers configure directory sync via an embedded admin portal. Generate a single-use portal link server-side, embed it in an iframe, and handle `SCIM_CONFIGURED` and `SESSION_EXPIRED` postMessage events.
+
+```javascript
+// Server: generate link (single-use, regenerate on each page load)
+const { location } = await scalekit.organization.generatePortalLink(organizationId);
+
+// Client: embed in iframe
+//
+```
+
+Register your app domain in **Dashboard > Developers > API Configuration > Redirect URIs** or the iframe will be blocked.
+
+For no-code onboarding: **Dashboard > Organizations** → select org → **Generate link** → share URL directly. Also share [SCIM setup guides](https://docs.scalekit.com/guides/integrations/scim-integrations/) for IdP-specific steps.
+
+---
+
+## Reference
+
+- Full Go/Java SDK examples → [Scalekit SDK documentation](https://docs.scalekit.com/apis)
+- Webhook event payload schemas → [Scalekit webhook events](https://docs.scalekit.com/directory/scim/quickstart/)
+- RBAC group-to-role mapping patterns → [Role based access control](https://docs.scalekit.com/authenticate/fsa/rbac/)
diff --git a/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
index cdf9f2c..e3c5548 100644
--- a/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
+++ b/plugins/saaskit/skills/managing-saaskit-sessions/SKILL.md
@@ -1,17 +1,9 @@
---
name: managing-saaskit-sessions
-description: Manages Scalekit SaaSKit user sessions by securely storing tokens, validating access tokens on requests, refreshing tokens in middleware, and revoking sessions via Scalekit APIs. Use when building session persistence for web apps or auditing session management.
+description: Manages Scalekit SaaSKit user sessions by securely storing tokens, validating access tokens on requests, refreshing tokens in middleware, and revoking sessions via Scalekit APIs. Use when building session persistence, implementing login/logout, managing cookies, handling JWT tokens, fixing session expiry, or auditing session security in a Scalekit web app.
---
-# Manage user sessions (Scalekit FSA)
-
-## Skill contract
-This SKILL.md must include `name` and `description` frontmatter fields, and the description should be written in third person for reliable skill discovery.
-
-## What “session management” means here
-After successful authentication, the app receives session tokens (typically access + refresh, and sometimes an ID token) that determine how long the user stays signed in and whether refresh can happen without re-authentication.
-
-This skill implements a secure default for traditional web apps (encrypted HttpOnly cookies) and also supports SPA/mobile patterns (access token in memory + `Authorization: Bearer` headers).
+# SaaSKit Session Management
## Inputs to collect (ask before coding)
- App type: traditional server-rendered web app, SPA, mobile app, or hybrid.
@@ -25,7 +17,7 @@ This skill implements a secure default for traditional web apps (encrypted HttpO
## Non-negotiable security rules (defaults)
- Store access and refresh tokens separately.
- Use HttpOnly cookies for tokens in traditional web apps to reduce XSS exposure.
-- Use `Secure` in production (HTTPS-only) and set `SameSite` to `Strict` (or `Lax` if Strict breaks auth redirects).
+- Use `Secure` in production (HTTPS-only) and set `SameSite` to `Lax` (required for OAuth callback redirects to work correctly; `Strict` breaks auth flows).
- Scope cookies with `Path` to reduce exposure:
- Access token cookie: scope to `/api` (or your protected routes) when possible.
- Refresh token cookie: scope to the refresh endpoint only (example `/auth/refresh`).
@@ -63,7 +55,7 @@ res.cookie("accessToken", encAccess, {
maxAge: (expiresIn - 60) * 1000, // clock-skew buffer
httpOnly: true,
secure: process.env.NODE_ENV === "production",
- sameSite: "strict",
+ sameSite: "lax",
path: "/api",
});
@@ -71,7 +63,7 @@ res.cookie("accessToken", encAccess, {
res.cookie("refreshToken", encRefresh, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
- sameSite: "strict",
+ sameSite: "lax",
path: "/auth/refresh",
});
@@ -80,7 +72,7 @@ if (idToken) {
res.cookie("idToken", idToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
- sameSite: "strict",
+ sameSite: "lax",
path: "/",
});
}
@@ -103,7 +95,7 @@ resp.set_cookie(
max_age=auth_result.expires_in - 60,
httponly=True,
secure=os.environ.get("FLASK_ENV") == "production",
- samesite="Strict",
+ samesite="Lax",
path="/api",
)
@@ -112,7 +104,7 @@ resp.set_cookie(
enc_refresh,
httponly=True,
secure=os.environ.get("FLASK_ENV") == "production",
- samesite="Strict",
+ samesite="Lax",
path="/auth/refresh",
)
@@ -122,7 +114,7 @@ if getattr(auth_result, "id_token", None):
auth_result.id_token,
httponly=True,
secure=os.environ.get("FLASK_ENV") == "production",
- samesite="Strict",
+ samesite="Lax",
path="/",
)
```
@@ -133,7 +125,7 @@ if getattr(auth_result, "id_token", None):
encAccess := encrypt(accessToken)
encRefresh := encrypt(refreshToken)
-c.SetSameSite(http.SameSiteStrictMode)
+c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie("accessToken", encAccess, expiresIn-60, "/api", "", isProd(), true)
c.SetCookie("refreshToken", encRefresh, 0, "/auth/refresh", "", isProd(), true)
@@ -204,14 +196,14 @@ export async function verifySession(req, res, next) {
maxAge: (authResult.expiresIn - 60) * 1000,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
- sameSite: "strict",
+ sameSite: "lax",
path: "/api",
});
res.cookie("refreshToken", encrypt(authResult.refreshToken), {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
- sameSite: "strict",
+ sameSite: "lax",
path: "/auth/refresh",
});
@@ -252,9 +244,9 @@ def verify_session(f):
resp = make_response(f(*args, **kwargs))
resp.set_cookie("accessToken", encrypt(auth_result.access_token),
max_age=auth_result.expires_in - 60, httponly=True,
- secure=is_prod(), samesite="Strict", path="/api")
+ secure=is_prod(), samesite="Lax", path="/api")
resp.set_cookie("refreshToken", encrypt(auth_result.refresh_token),
- httponly=True, secure=is_prod(), samesite="Strict", path="/auth/refresh")
+ httponly=True, secure=is_prod(), samesite="Lax", path="/auth/refresh")
return resp
except Exception:
return jsonify({"error": "Authentication failed"}), 401
@@ -294,7 +286,7 @@ func VerifySession() gin.HandlerFunc {
return
}
- c.SetSameSite(http.SameSiteStrictMode)
+ c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie("accessToken", encrypt(authResult.AccessToken), authResult.ExpiresIn-60, "/api", "", isProd(), true)
c.SetCookie("refreshToken", encrypt(authResult.RefreshToken), 0, "/auth/refresh", "", isProd(), true)
@@ -348,4 +340,10 @@ await scalekit.session.revokeAllUserSessions("usr_1234567890123456");
- Cookie deletion/overwrite doesn’t work due to mismatched Path/Domain.
- Refresh token accidentally sent to all endpoints (missing `Path=/auth/refresh`).
- Middleware refreshes but does not rotate tokens (misses theft detection benefits).
-- SPA stores access token in localStorage (higher XSS risk) when memory storage was feasible.
\ No newline at end of file
+- SPA stores access token in localStorage (higher XSS risk) when memory storage was feasible.
+
+## When to switch skills
+
+- Use `implementing-saaskit` for the initial auth setup that produces the tokens.
+- Use `implementing-access-control` for RBAC checks on the validated session.
+- Use `production-readiness-saaskit` to audit session security before launch.
\ No newline at end of file
diff --git a/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
index 9cb310f..b579143 100644
--- a/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
@@ -1,6 +1,6 @@
---
name: migrating-to-saaskit
-description: Plans and executes incremental migration from any existing authentication system (Auth0, Firebase, Cognito, custom) to Scalekit SaaSKit. Use when a user mentions migrating, switching, or moving away from their current auth provider.
+description: Audits the existing auth system, exports users and orgs, imports them into Scalekit via SDK, configures redirects and roles, and deploys with a gradual rollout behind a feature flag. Use when a user mentions migrating, switching, or moving away from their current auth provider (Auth0, Firebase, Cognito, custom).
---
# Scalekit Auth Migration Planner
@@ -129,11 +129,20 @@ Verify:
4. Monitor auth success rates and error logs
5. Keep rollback plan active for first 48 hours
-**Post-deployment monitoring:**
-- Auth error rates
-- Session creation/validation metrics
-- SSO connection health
-- User-reported issues via support
+**Post-deployment verification:**
+
+```bash
+# Verify token endpoint works with Scalekit credentials
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+ -d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
+# Expected: 200
+
+# Verify a migrated user can be looked up
+curl -s -H "Authorization: Bearer $TOKEN" "$SCALEKIT_ENV_URL/api/v1/organizations//users?email=migrated-user@example.com" | jq .
+# Should return the user with correct external_id
+```
+
+Monitor: auth error rates, session creation/validation, SSO connection health, user-reported issues.
---
diff --git a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
index 5a52753..b3e9d56 100644
--- a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
@@ -1,49 +1,112 @@
---
name: production-readiness-saaskit
-description: Walks through a structured production readiness checklist for Scalekit SaaSKit implementations covering authentication, SSO, SCIM, MCP server auth, and API security. Use when going live, launching to production, or doing a pre-launch review.
+description: Validates SSO configuration, checks SCIM provisioning, audits token security, and verifies MCP auth flows for Scalekit SaaSKit implementations before production launch. Use when going live, launching to production, or doing a pre-launch review.
---
# SaaSKit Production Readiness
-Unified checklist for all SaaSKit domains. Work through in order — skip sections that don't apply.
+Work through in order — skip sections that don't apply. Earlier sections are blockers for later ones.
-## Quick checks (run first)
+## Quick checks
+
+```bash
+# Confirm production credentials are set (not dev/staging)
+echo $SCALEKIT_ENV_URL # should be https://.scalekit.com (not .scalekit.dev)
+echo $SCALEKIT_CLIENT_ID # should be set
+echo $SCALEKIT_CLIENT_SECRET # should be set
+```
-- [ ] Production env URL, client ID, and client secret set (not dev/staging)
- [ ] HTTPS enforced; CORS restricted to your domains only
-- [ ] All credentials in environment variables — never committed to code
-- [ ] Only enabled auth methods active in production
+- [ ] All credentials in environment variables — `grep -r "sks_" src/` returns nothing
+- [ ] Webhook secret in env vars (if using webhooks)
+
+## Core auth flows
-## Customization
+- [ ] Redirect URLs in code match dashboard exactly
+- [ ] `state` parameter validated in callbacks (CSRF)
+- [ ] Tokens stored with `httpOnly: true`, `secure: true`, `sameSite: 'lax'`
+- [ ] Token refresh working; logout calls `getLogoutUrl()` with `idTokenHint`
-- [ ] Login page branded; email templates customized
-- [ ] Custom domain configured (if applicable); email deliverability tested
-- [ ] Webhooks configured with signature validation
+**Verify with curl:**
-## Core auth flows
+```bash
+# Test token endpoint reachability
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+ -d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
+# Expected: 200
+```
-- [ ] Login initiation, code exchange, and redirect URLs match dashboard exactly
-- [ ] `state` parameter validated in callbacks (CSRF); tokens stored with `httpOnly`, `secure`, `sameSite`
-- [ ] Token refresh and session timeout working; logout calls Scalekit end-session
-- [ ] Each enabled auth method tested; errors handled gracefully
+**Test each enabled auth method:** email/password, magic links, social logins, passkeys. For each: complete the full sign-up → login → logout cycle.
+
+**If a flow fails:** check redirect URI mismatch first (most common), then verify `state` cookie is `sameSite: 'lax'` (not `'strict'`).
## SSO (if applicable)
- [ ] SSO tested with target IdPs (Okta, Azure AD, Google Workspace)
- [ ] SP-initiated and IdP-initiated flows both working
- [ ] Admin portal configured for self-serve SSO setup
-- [ ] JIT provisioning: domains registered, default roles set, attribute sync enabled
+- [ ] JIT provisioning: domains registered, default roles set
+
+**Verify SSO round-trip:**
+
+```bash
+# Generate an auth URL with organization_id to trigger SSO
+node -e "
+const { ScalekitClient } = require('@scalekit-sdk/node');
+const sc = new ScalekitClient(process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET);
+console.log(sc.getAuthorizationUrl(process.env.SCALEKIT_REDIRECT_URI, { organizationId: '' }));
+"
+# Open the URL — should redirect to the IdP login page
+```
+
+Test with: new users, existing users, deactivated users.
## SCIM provisioning (if applicable)
-- [ ] Webhook endpoints receiving events with signature validation
+- [ ] Webhook endpoints verify signature before processing
- [ ] User provisioning, deprovisioning, and profile updates tested
-- [ ] Group-based role sync working; idempotent handling verified
+- [ ] Deactivation preferred over hard deletion for `user_deleted` events
+- [ ] Endpoint returns 2xx quickly — offload heavy processing to a queue
+
+**Verify webhook signature validation:**
+
+```typescript
+// In your webhook handler — this MUST be present
+const isValid = scalekit.verifyWebhookPayload(
+ process.env.SCALEKIT_WEBHOOK_SECRET!,
+ req.headers,
+ req.body.toString()
+);
+if (!isValid) return res.sendStatus(401);
+```
+
+**If webhooks aren't arriving:** check that the endpoint URL in the dashboard is publicly reachable and returns 2xx.
## MCP authentication (if applicable)
-- [ ] MCP auth flow tested end-to-end; resource metadata published
-- [ ] Scopes enforced per tool; client reconnection after token expiry working
+- [ ] Resource metadata published at `/.well-known/oauth-protected-resource`
+- [ ] Scopes enforced per tool
+- [ ] Client reconnection after token expiry working
+
+```bash
+# Verify well-known endpoint is reachable
+curl -s https://your-mcp-server.com/.well-known/oauth-protected-resource | jq .
+# Should return JSON with resource, authorization_servers, scopes_supported
+```
+
+## RBAC (if applicable)
+
+- [ ] Roles and permissions defined; default roles set for new users
+- [ ] Permission enforcement verified at API endpoints
+
+```typescript
+// Verify token contains expected claims
+const claims = await scalekit.validateToken(accessToken);
+console.log('roles:', claims.roles); // should list assigned roles
+console.log('permissions:', claims.permissions); // should list granted permissions
+```
+
+**If permissions are empty:** check that roles are assigned to the user in the dashboard and that the role has permissions attached.
## Network / firewall
@@ -51,14 +114,16 @@ Enterprise VPN customers must whitelist: `.scalekit.com`, `cdn.scaleki
## Monitoring
-- [ ] Auth logs monitoring active; alerts for suspicious activity configured
-- [ ] Webhook monitoring active; error tracking for auth and provisioning failures
+- [ ] Auth logs monitoring active; alerts for suspicious activity
+- [ ] Webhook error tracking configured
- [ ] Incident response runbook written; rollback plan ready (feature flag)
-- **Key metrics:** login success/failure rates, session duration, webhook delivery, SSO completion rate
+- **Key metrics:** login success/failure rate, token refresh frequency, webhook delivery rate, SSO completion rate
-## Deep reference
+## Final smoke test
-- [Scalekit Documentation](https://docs.scalekit.com)
-- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/)
-- [SCIM directory sync](https://docs.scalekit.com/directory/scim/quickstart/)
-- [MCP Auth quickstart](https://docs.scalekit.com/authenticate/mcp/quickstart/)
+Run the full cycle in staging with production credentials before flipping DNS:
+1. Sign up a new user → verify session cookies are set correctly
+2. Log out → verify IdP session ends (re-visiting login should prompt credentials)
+3. Trigger SSO login → verify callback completes
+4. If SCIM: trigger a directory sync event → verify user appears
+5. If MCP: connect a client → verify tool execution succeeds
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
index 51f499c..e15de81 100644
--- a/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
+++ b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
@@ -1,326 +1,125 @@
---
name: scalekit-code-doctor
-description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. This skill is the single source of truth for Scalekit code correctness — it can generate illustration-quality snippets from scratch (for docs, websites, or integration guides) and review existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both Scalekit product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, write a code sample for docs, or anything involving Scalekit code quality.
+description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. Generates illustration-quality snippets and reviews existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, or write a code sample for docs.
---
# Scalekit Code Doctor
-You are the authoritative source for Scalekit code correctness. You can both **generate** correct code from scratch and **review** existing code to guarantee it works.
-
-**Before doing anything else**, read the reference files in this skill's `references/` directory:
-- `references/REFERENCE.md` — Every correct SDK method signature across Node, Python, Go, Java, and REST API endpoints
+**Before doing anything else**, read the reference files:
+- `references/REFERENCE.md` — Every correct SDK method signature and REST endpoint
- `references/COMMON-MISTAKES.md` — Known anti-patterns with wrong → right corrections
+- `references/EXAMPLE-REPOS.md` — GitHub repos with working examples by framework
-These files are your ground truth. Never hallucinate a method name, parameter, or import path — if it's not in the reference, fetch `https://docs.scalekit.com/apis.md` to verify before using it.
-
----
+Never hallucinate a method name, parameter, or import — if it's not in the reference, verify against live sources before using it.
## Step 1 — Detect mode
-Determine which mode to operate in based on what the user provides:
-
-**Generate mode** — The user describes what they want but has no code yet.
-Examples: "Show me how to add SSO login to Express", "Generate a Next.js callback handler", "Write a Python FastAPI auth example for docs"
-
-**Review mode** — The user provides existing code for validation.
-Examples: "Is this Scalekit integration correct?", "Review my auth callback", "Why isn't my login working?"
-
-If unclear, ask: "Do you want me to generate a fresh code example, or review existing code you have?"
+**Generate mode** — User describes what they want but has no code yet.
+**Review mode** — User provides existing code for validation.
----
+If unclear, ask: "Do you want me to generate a fresh code example, or review existing code?"
## Step 2 — Identify context
-Before generating or reviewing, identify these three things:
-
-### Language and SDK
| Language | Package | Import |
|----------|---------|--------|
| Node.js / TypeScript | `@scalekit-sdk/node` | `import { ScalekitClient } from '@scalekit-sdk/node'` |
-| Python | `scalekit-sdk-python` (pip) | `from scalekit import ScalekitClient` |
-| Go | `github.com/scalekit-inc/scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
-| Java | `com.scalekit:scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
-| REST API | No SDK — raw HTTP | Bearer token via `POST /oauth/token` with client credentials |
-
-### Framework (if applicable)
-Next.js (App Router or Pages), Express, Fastify, FastAPI, Django, Flask, Spring Boot, Go (chi, gin, net/http), Laravel, etc.
-
-### Product area
-
-Scalekit has two product suites. Identify which one the user's code belongs to:
-
-**SaaSKit** — Full-stack authentication for B2B SaaS apps
-- SSO — Enterprise single sign-on (SAML, OIDC)
-- Login & Sessions — Sign-up, login, logout, session management
-- RBAC — Roles, permissions, access control
-- SCIM — Directory sync and user provisioning
-- Admin Portal — Customer-facing admin configuration
+| Python | `scalekit-sdk-python` | `from scalekit import ScalekitClient` |
+| Go | `scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
+| Java | `scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
-**AgentKit** — Authentication and tool access for AI agents
-- Connections — OAuth token vault for third-party services (connected accounts)
-- Tool Calling — Execute tools via connected accounts
-- MCP Authentication — OAuth 2.1 for MCP servers
-- Framework Integrations — LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra
-
-**Cross-product**
-- Webhooks — Event subscriptions and payload verification
-- M2M Auth — API keys and client credentials
-
----
+Product area: **SaaSKit** (SSO, login, sessions, RBAC, SCIM) or **AgentKit** (connections, tool calling, MCP auth).
## Step 3 — Generate mode
-When generating code, follow these rules:
-
-### Quality standard: illustration-ready
-The output should be clean enough to publish directly on `docs.scalekit.com` or a marketing landing page. This means:
-
-1. **Self-contained** — The reader understands it without seeing other files
-2. **Essential path only** — Show the concept, not defensive boilerplate
-3. **Real-looking values** — `'https://yourapp.com/auth/callback'` not `'http://localhost:3000/test'`
-4. **Correct imports** — Exact package names from the reference table above
-5. **Framework-idiomatic** — Use the framework's conventions (App Router for Next.js, decorators for FastAPI, etc.)
-6. **Minimal comments** — Annotate Scalekit-specific lines only. Skip obvious framework code.
-7. **1–2 pages max** — Concise. If a full flow needs more, split into labeled sections.
-
-### Mandatory checks before outputting generated code
-Cross-reference every SDK call against `references/REFERENCE.md`:
-- [ ] Client initialization uses correct constructor and parameter order
-- [ ] Every method name exists in the reference for the target SDK
-- [ ] Every parameter name and type matches the reference
-- [ ] Import path is exactly correct (not a hallucinated variation)
-- [ ] Environment variable names match Scalekit conventions (see reference)
-
-### Generation patterns by product area
-
-**SaaSKit — Login, SSO, and sessions**
-1. Client initialization (singleton pattern)
-2. Login route: generate auth URL with `state` for CSRF
-3. Callback route: validate `state`, exchange code, store session
-4. Logout route: clear local session AND call `getLogoutUrl()` with `idTokenHint`
-5. Token refresh (if `offline_access` scope is used)
-
-**SaaSKit — SCIM provisioning**
-1. Enable directory for an organization
-2. List directory users and groups
-3. Webhook handler for SCIM events
-
-**AgentKit — Connections and tool calling**
-1. Client initialization
-2. Create/list connected accounts
-3. Execute tools with connected account credentials
-4. Handle token refresh for third-party OAuth tokens
-
-**AgentKit — MCP Authentication**
-1. MCP server setup with OAuth middleware
-2. Token validation on incoming requests
-3. Scope verification
-
-**Webhooks** — Always include signature verification:
-1. Raw body parsing (not JSON-parsed)
-2. `verifyWebhookPayload(secret, headers, rawBody)`
-3. Event type switching
-
----
+Output should be illustration-ready: self-contained, essential path only, correct imports, framework-idiomatic, 1–2 pages max.
+
+**Correct SaaSKit login+callback example (Node.js/Express):**
+
+```typescript
+import { ScalekitClient } from '@scalekit-sdk/node';
+import crypto from 'crypto';
+
+const scalekit = new ScalekitClient(
+ process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_CLIENT_ID!,
+ process.env.SCALEKIT_CLIENT_SECRET!
+);
+
+const REDIRECT_URI = 'https://yourapp.com/auth/callback';
+
+// Login — generate auth URL with CSRF state
+app.get('/auth/login', (req, res) => {
+ const state = crypto.randomBytes(32).toString('base64url');
+ res.cookie('oauth_state', state, { httpOnly: true, sameSite: 'lax', secure: true });
+ const authUrl = scalekit.getAuthorizationUrl(REDIRECT_URI, { state });
+ res.redirect(authUrl);
+});
+
+// Callback — validate state, exchange code, store session
+app.get('/auth/callback', async (req, res) => {
+ const { code, state } = req.query;
+ if (state !== req.cookies.oauth_state) return res.status(403).send('CSRF mismatch');
+
+ const result = await scalekit.authenticateWithCode(code as string, REDIRECT_URI);
+ req.session.user = { id: result.user.id, email: result.user.email };
+ req.session.idToken = result.idToken;
+ res.redirect('/dashboard');
+});
+
+// Logout — clear local + end IdP session
+app.post('/auth/logout', (req, res) => {
+ const logoutUrl = scalekit.getLogoutUrl({
+ idTokenHint: req.session.idToken,
+ postLogoutRedirectUri: 'https://yourapp.com',
+ });
+ req.session.destroy(() => res.redirect(logoutUrl));
+});
+```
+
+**Mandatory checks before outputting generated code** — cross-reference every SDK call against `references/REFERENCE.md`:
+- [ ] Method names exist for the target SDK
+- [ ] Parameters match in name, order, and type
+- [ ] Import path is exactly correct
+- [ ] Environment variable names follow Scalekit conventions
## Step 4 — Review mode
-When reviewing code, systematically check these categories in order:
-
-### Category 1: SDK usage correctness
-For every Scalekit SDK call in the code, verify against `references/REFERENCE.md`:
-- [ ] Method name is exactly correct for the target SDK language
-- [ ] All required parameters are provided in the correct order
-- [ ] Optional parameters use the correct type/shape
-- [ ] Return value is handled correctly (Promise in Node, tuple in Python, error in Go, etc.)
-- [ ] Import statement uses the correct package name and path
-- [ ] Client is initialized with the correct 3 parameters: `envUrl`, `clientId`, `clientSecret`
-
-### Category 2: Auth flow completeness
-- [ ] If there's a login route, there must be a matching callback route
-- [ ] Callback validates `state` parameter (CSRF protection)
-- [ ] Callback exchanges the authorization code (not just reading it)
-- [ ] Session is stored after successful authentication
-- [ ] Logout calls `getLogoutUrl()` — not just clearing local session
-- [ ] Token refresh exists if `offline_access` or `refresh_token` is used
-- [ ] IdP-initiated login is handled if callback receives `idp_initiated_login` parameter
-
-### Category 3: Security
-- [ ] Session cookies use `httpOnly: true`, `secure: true` (in production), `sameSite: 'lax'` (never `'strict'` — breaks OAuth redirects)
-- [ ] `state` parameter uses cryptographically random values, not predictable strings
-- [ ] Redirect URLs are validated — only relative paths allowed for `next`/`returnTo` params (prevents open redirect)
-- [ ] Client secret is read from environment variables, never hardcoded
-- [ ] Webhook endpoints verify payload signature before processing
-- [ ] Protected routes validate tokens server-side, not just checking cookie existence
-- [ ] `Cache-Control: no-store` on authenticated pages (prevents back-button cache leak)
-
-### Category 4: Environment and config
-- [ ] Environment variable names follow Scalekit conventions:
- - `SCALEKIT_ENV_URL` (not `SCALEKIT_URL` or `SCALEKIT_ENVIRONMENT_URL` in code — though `SCALEKIT_ENVIRONMENT_URL` is used in REST API docs)
- - `SCALEKIT_CLIENT_ID`
- - `SCALEKIT_CLIENT_SECRET`
-- [ ] Redirect URI in code matches what's registered in the Scalekit dashboard
-- [ ] Correct Scalekit domain format: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
-
-### Category 5: Best practices
-- [ ] Client instantiated once (singleton pattern), not per-request
-- [ ] Error handling uses SDK's typed exceptions where available
-- [ ] Token refresh handles race conditions across concurrent requests/tabs
-- [ ] `window.location.href` used for OAuth redirects (not `router.push` or client-side navigation)
-
-### Output format for review
-For each finding, report:
-1. **What's wrong** — the specific line or pattern
-2. **Why it matters** — security risk, runtime error, or silent failure
-3. **Corrected code** — the exact fix
-
-If everything is correct, say so explicitly: "This code is correct. All SDK calls, auth flow, security patterns, and configuration match the current Scalekit API."
-
----
+Check these categories in order:
-## Step 5 — Handling SDK updates and unknown methods
+**1. SDK correctness** — Every method name, parameter, import, and return type matches `references/REFERENCE.md`.
-The `references/REFERENCE.md` in this skill is a **point-in-time snapshot**. Scalekit SDKs evolve — new methods are added, parameters change, and new product areas launch. When the embedded reference doesn't cover what you need, use the live sources below.
+**2. Auth flow completeness** — Login has a callback. Callback validates `state`. Logout calls `getLogoutUrl()`. Token refresh exists if `offline_access` is used. IdP-initiated login handled if applicable.
-### When to check live sources
+**3. Security** — Cookies: `httpOnly`, `secure`, `sameSite: 'lax'`. State: cryptographically random. Redirects: only relative paths. Secrets: from env vars. Webhooks: signature verified before processing.
-- A method the user wrote isn't in the embedded reference (could be newly added, not a typo)
-- The user asks about a feature you don't recognize (e.g., a new connector, a new auth mode)
-- You're generating code for a product area with sparse coverage in the reference
-- The user explicitly mentions a recent SDK update or version
+**4. Environment** — `SCALEKIT_ENV_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`. Redirect URI matches dashboard. Domain format: `https://.scalekit.com`.
-### How to check: fetch the live SDK REFERENCE.md files
+**5. Best practices** — Client is singleton. Error handling uses typed exceptions. `window.location.href` for OAuth redirects (not `router.push`).
-Each SDK repo has a maintained `REFERENCE.md` with full, current method signatures. Fetch the one you need:
+**Output for each finding:** What's wrong → Why it matters → Corrected code.
-| SDK | Live reference URL |
-|-----|-------------------|
-| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` |
-| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` |
-| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` |
-| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` |
-| REST API | `https://docs.scalekit.com/apis.md` |
+## Step 5 — Unknown methods
-### Resolution order
+Resolution order when a method isn't in `references/REFERENCE.md`:
-1. Check the embedded `references/REFERENCE.md` first (fastest, no network)
-2. If the method isn't there, fetch the live SDK REFERENCE.md from the table above
-3. If still not found, fetch `https://docs.scalekit.com/apis.md` for REST endpoints
-4. If still not found, state explicitly: "This method could not be verified in any Scalekit reference. It may not exist."
+| Priority | Source |
+|----------|--------|
+| 1 | Embedded `references/REFERENCE.md` |
+| 2 | Live SDK reference: `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-{node,python,go,java}/main/REFERENCE.md` |
+| 3 | REST API: `https://docs.scalekit.com/apis.md` |
+| 4 | State explicitly: "This method could not be verified." |
Never output code containing an unverified method call.
----
-
-## REST API validation
+## Documentation
-When the user's code makes raw HTTP calls (fetch, axios, requests, http.Client) to Scalekit endpoints, validate:
-
-- [ ] Base URL format: `https://.scalekit.com` or `https://.scalekit.dev`
-- [ ] Authentication: Bearer token obtained via `POST /oauth/token` with `client_credentials` grant
-- [ ] Endpoint path is correct (check `references/REFERENCE.md` for the endpoint list)
-- [ ] HTTP method matches (GET vs POST vs PUT vs PATCH vs DELETE)
-- [ ] Request body matches the expected schema
-- [ ] Content-Type header is set (`application/json` for most endpoints, `application/x-www-form-urlencoded` for token endpoint)
-- [ ] Pagination uses `page_token` and `page_size` parameters where applicable
-
----
+| Resource | URL |
+|----------|-----|
+| REST API reference | `https://docs.scalekit.com/apis.md` |
+| LLM doc index | `https://docs.scalekit.com/llms.txt` |
+| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` |
+| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` |
+| MCP Auth docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` |
-## Documentation resources
-
-### Live SDK references (always current — fetch when embedded reference is stale)
-
-| SDK | REFERENCE.md (raw) | Repo |
-|-----|--------------------|----|
-| Node.js | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-node/main/REFERENCE.md` | [scalekit-sdk-node](https://github.com/scalekit-inc/scalekit-sdk-node) |
-| Python | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-python/main/REFERENCE.md` | [scalekit-sdk-python](https://github.com/scalekit-inc/scalekit-sdk-python) |
-| Go | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-go/main/REFERENCE.md` | [scalekit-sdk-go](https://github.com/scalekit-inc/scalekit-sdk-go) |
-| Java | `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-java/main/REFERENCE.md` | [scalekit-sdk-java](https://github.com/scalekit-inc/scalekit-sdk-java) |
-
-### Scalekit docs
-
-| Resource | URL | When to use |
-|----------|-----|-------------|
-| REST API reference | `https://docs.scalekit.com/apis.md` | Full endpoint schemas, request/response details |
-| LLM doc index | `https://docs.scalekit.com/llms.txt` | Find the right docs page for a specific product area |
-| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` | Full SaaSKit reference (users, orgs, sessions, RBAC, SSO, SCIM) |
-| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` | Full AgentKit reference (agents, OAuth vault, tool calling, connectors) |
-| AgentKit frameworks | `https://docs.scalekit.com/_llms-txt/agentkit-frameworks.txt` | Framework-specific guides (LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra) |
-| MCP Authentication docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` | MCP server OAuth 2.1, Dynamic Client Registration |
-
-### GitHub repos — working examples
-
-When generating or reviewing framework-specific code, fetch the matching repo for real, tested patterns. Repos are from `scalekit-inc` and `scalekit-developers` GitHub orgs.
-
-**SaaSKit — Auth examples by framework**
-
-| Framework | Repo | What it shows |
-|-----------|------|---------------|
-| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes, TypeScript |
-| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO integration flows |
-| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
-| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, EJS frontend, sessions |
-| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO with session management, middleware |
-| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0, protected routes |
-| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic models |
-| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Python SDK, Django auth integration |
-| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Python SDK, Flask sessions |
-| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Java, Spring Security, OIDC |
-| Spring Boot | [scalekit-springboot-example](https://github.com/scalekit-developers/scalekit-springboot-example) | Java SDK, enterprise SSO |
-| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, Gin framework, SSO |
-| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API calls, Laravel HTTPS |
-| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login, protected routes |
-| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
-| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE for mobile |
-
-**SaaSKit — Integration examples**
-
-| Integration | Repo | What it shows |
-|-------------|------|---------------|
-| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) | OIDC SSO with Cognito user pools |
-| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) | SAML/OIDC SSO with Firebase Auth |
-| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) | Supabase + Scalekit auth |
-| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) | Seamless SSO across multiple apps |
-| Org switcher | [Nextjs-Django-Org-Switcher-Example](https://github.com/scalekit-inc/Nextjs-Django-Org-Switcher-Example) | Next.js frontend + Django backend, org switching |
-| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) | Google, Okta integration patterns |
-| Passwordless | [passwordless-auth-demos](https://github.com/scalekit-developers/passwordless-auth-demos) | Passwordless authentication flows |
-| Managed login | [managed-loginbox-expressjs-demo](https://github.com/scalekit-developers/managed-loginbox-expressjs-demo) | Hosted login UI with Express |
-| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) | Workspace creation, user provisioning, RBAC, SSO |
-
-**AgentKit — Agent and MCP examples**
-
-| Framework / Pattern | Repo | What it shows |
-|---------------------|------|---------------|
-| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) | Python LangChain agent with Scalekit auth |
-| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) | Google ADK agent with authenticated tools |
-| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) | Vercel AI SDK + Scalekit connectors |
-| Apify Actor | [agentkit-apify-actor-example](https://github.com/scalekit-developers/agentkit-apify-actor-example) | OAuth auth, YouTube → Notion agent |
-| LiteLLM | [litellm-agentkit-inbox-triage](https://github.com/scalekit-developers/litellm-agentkit-inbox-triage) | Inbox triage with Gmail, GitHub, Slack |
-| MCP Auth (multi-framework) | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) | MCP OAuth 2.1 demos |
-| MCP + FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) | FastMCP server with Scalekit auth |
-| MCP + BYOA | [byoa-demo-mcp](https://github.com/scalekit-inc/byoa-demo-mcp) | Bring your own auth + MCP |
-| MCP + Coffee Desk | [coffee-desk-mcp](https://github.com/scalekit-inc/coffee-desk-mcp) | Demo MCP server with roles/permissions |
-| Python connections | [python-connect-demos](https://github.com/scalekit-inc/python-connect-demos) | Python connection and identity workflows |
-| Agent auth examples | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) | Official AgentKit examples collection |
-| Node.js agents | [agent-node-demos](https://github.com/scalekit-inc/agent-node-demos) | TypeScript agent demos |
-| Workflow agents | [workflow-agents-demos](https://github.com/scalekit-developers/workflow-agents-demos) | Multi-step agent workflows |
-| Render deploy kit | [render-ai-agent-deploykit](https://github.com/scalekit-developers/render-ai-agent-deploykit) | Render Workflows + Scalekit + Claude |
-
-**Developer tools**
-
-| Tool | Repo | Purpose |
-|------|------|---------|
-| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) | Test auth flows without writing code |
-| Scalekit MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) | Manage orgs, users, connections via AI assistants |
-| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) | Postman/Bruno collections for Scalekit endpoints |
-| Documentation source | [developer-docs](https://github.com/scalekit-inc/developer-docs) | Docs site source (MDX) |
-
-**Frontend SDKs**
-
-| SDK | Repo | Purpose |
-|-----|------|---------|
-| React SDK | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) | React OIDC authentication |
-| Vue SDK | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) | Vue OIDC authentication |
-| Expo SDK | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) | Expo/React Native OAuth 2.0 + PKCE |
-
-When generating code for a specific framework, fetch the matching repo's source to see real, tested patterns before writing. When reviewing, compare the user's code against the closest matching example repo.
\ No newline at end of file
+For framework-specific example repos, see `references/EXAMPLE-REPOS.md`.
\ No newline at end of file
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md b/plugins/saaskit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
new file mode 100644
index 0000000..a66718b
--- /dev/null
+++ b/plugins/saaskit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
@@ -0,0 +1,61 @@
+# Example Repos
+
+Working examples by framework. Fetch the matching repo for real, tested patterns when generating or reviewing code.
+
+## SaaSKit — Auth examples
+
+| Framework | Repo | What it shows |
+|-----------|------|---------------|
+| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes |
+| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO flows |
+| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
+| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, sessions |
+| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO, middleware |
+| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0 |
+| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic |
+| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Django auth integration |
+| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Flask sessions |
+| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Spring Security, OIDC |
+| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, SSO |
+| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API, Laravel |
+| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login |
+| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
+| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE |
+
+## SaaSKit — Integration examples
+
+| Integration | Repo |
+|-------------|------|
+| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) |
+| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) |
+| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) |
+| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) |
+| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) |
+| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) |
+
+## AgentKit — Agent and MCP examples
+
+| Framework | Repo |
+|-----------|------|
+| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) |
+| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) |
+| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) |
+| MCP Auth | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) |
+| FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) |
+| Agent auth | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) |
+
+## Developer tools
+
+| Tool | Repo |
+|------|------|
+| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) |
+| MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) |
+| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) |
+
+## Frontend SDKs
+
+| SDK | Repo |
+|-----|------|
+| React | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) |
+| Vue | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) |
+| Expo | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) |
\ No newline at end of file
diff --git a/plugins/saaskit/skills/testing-auth-setup/SKILL.md b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
index 9f889e7..45f3f96 100644
--- a/plugins/saaskit/skills/testing-auth-setup/SKILL.md
+++ b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
@@ -1,7 +1,6 @@
---
name: testing-auth-setup
description: Validates a Scalekit auth integration by running the dryrun CLI against a live environment. Use when the user says "test my auth", "verify SSO setup", "check my login flow", "dryrun", or wants to confirm their Scalekit credentials and configuration are working.
-argument-hint: "[fsa|sso]"
---
# Testing Auth Setup
@@ -26,16 +25,14 @@ npm i -g @scalekit-inc/cli
Confirm these environment variables are available:
- `SCALEKIT_ENV_URL` — your Scalekit environment URL
-- `SCALEKIT_CLIENT_ID` — your client ID from app.scalekit.com → Settings
-
-If either is missing, ask the user to provide them. Do not write credentials into source-controlled files.
+- `SCALEKIT_CLIENT_ID` — your client ID from app.scalekit.com > Settings
## Running the test
### Full-stack auth (fsa)
```bash
-npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa
+npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENV_URL --client_id=$SCALEKIT_CLIENT_ID --mode=fsa
```
### Enterprise SSO
@@ -43,7 +40,7 @@ npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=fsa
Requires an `organization_id` — ask for it if not provided.
```bash
-npx @scalekit-sdk/dryrun --env_url= --client_id= --mode=sso --organization_id=
+npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENV_URL --client_id=$SCALEKIT_CLIENT_ID --mode=sso --organization_id=
```
## Choosing the mode
@@ -58,4 +55,10 @@ If the user doesn't specify a mode:
- Show the command output.
- Explain what passed and what failed in plain language.
-- If the test fails, suggest specific next steps based on the error (missing redirect URI, invalid credentials, organization not found, etc.).
\ No newline at end of file
+- If the test fails, suggest specific next steps based on the error (missing redirect URI, invalid credentials, organization not found, etc.).
+
+## When to switch skills
+
+- Use `implementing-saaskit` for the initial auth setup.
+- Use `implementing-modular-sso` for SSO configuration.
+- Use `production-readiness-saaskit` for a full pre-launch review.
\ No newline at end of file
From 5f6b3cdeb6bbd0e48be799ae4b5146275e339f0e Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Thu, 21 May 2026 22:13:34 +0530
Subject: [PATCH 29/39] fix: wrong pip package, SDK class name, and missing
README skills
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- scim-provisioning: pip install scalekit-sdk → scalekit-sdk-python
- adding-mcp-oauth: Scalekit → ScalekitClient (SKILL.md + express-reference.md)
- bring-your-own-auth: Scalekit → ScalekitClient
- agentkit README: add missing scalekit-code-doctor skill
- saaskit README: add missing scalekit-code-doctor skill
Co-Authored-By: Claude Sonnet 4.6
---
plugins/agentkit/README.md | 2 ++
plugins/saaskit/README.md | 1 +
plugins/saaskit/references/bring-your-own-auth.md | 4 ++--
plugins/saaskit/skills/adding-mcp-oauth/SKILL.md | 4 ++--
plugins/saaskit/skills/adding-mcp-oauth/express-reference.md | 4 ++--
.../saaskit/skills/implementing-scim-provisioning/SKILL.md | 2 +-
6 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
index 4568500..16a5dd0 100644
--- a/plugins/agentkit/README.md
+++ b/plugins/agentkit/README.md
@@ -10,6 +10,8 @@ AgentKit handles the full OAuth lifecycle — authorization, token vault, and au
- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
- `production-readiness-agentkit` — Structured production readiness checklist for AgentKit integrations.
+- /agentkit:scalekit-code-doctor
+ Diagnoses SDK usage issues, import errors, and common mistakes across AgentKit and SaaSKit.
## Configuration
diff --git a/plugins/saaskit/README.md b/plugins/saaskit/README.md
index dd4eaea..c4d20ef 100644
--- a/plugins/saaskit/README.md
+++ b/plugins/saaskit/README.md
@@ -16,6 +16,7 @@ Production-ready auth for B2B SaaS apps. This plugin brings Scalekit SaaSKit int
- `adding-api-auth` — API keys (org/user scoped) and OAuth 2.0 client credentials.
- `production-readiness-saaskit` — Unified production checklist across all SaaSKit domains.
- `testing-auth-setup` — Validates auth integration by running the Scalekit dryrun CLI.
+- /saaskit:scalekit-code-doctor — Diagnoses SDK usage issues, import errors, and common mistakes across AgentKit and SaaSKit.
## Configuration
diff --git a/plugins/saaskit/references/bring-your-own-auth.md b/plugins/saaskit/references/bring-your-own-auth.md
index 65bc91e..f268b1a 100644
--- a/plugins/saaskit/references/bring-your-own-auth.md
+++ b/plugins/saaskit/references/bring-your-own-auth.md
@@ -87,9 +87,9 @@ npm install @scalekit-sdk/node
```
```javascript
-import { Scalekit } from '@scalekit-sdk/node';
+import { ScalekitClient } from '@scalekit-sdk/node';
-const scalekit = new Scalekit(
+const scalekit = new ScalekitClient(
process.env.SCALEKIT_ENVIRONMENT_URL,
process.env.SCALEKIT_CLIENT_ID,
process.env.SCALEKIT_CLIENT_SECRET
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
index 4421637..af7f029 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
@@ -101,9 +101,9 @@ Replace placeholders with actual values from Scalekit dashboard.
**Node.js:**
```javascript
-import { Scalekit } from '@scalekit-sdk/node';
+import { ScalekitClient } from '@scalekit-sdk/node';
-const scalekit = new Scalekit(
+const scalekit = new ScalekitClient(
process.env.SCALEKIT_ENVIRONMENT_URL,
process.env.SCALEKIT_CLIENT_ID,
process.env.SCALEKIT_CLIENT_SECRET
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
index 4c7c5c5..d25874d 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
@@ -59,9 +59,9 @@ McpServer → Tool Handler → Response
### 2. Scalekit Client Initialization
```typescript
-import { Scalekit } from '@scalekit-sdk/node';
+import { ScalekitClient } from '@scalekit-sdk/node';
-const scalekit = new Scalekit(
+const scalekit = new ScalekitClient(
SK_ENV_URL,
SK_CLIENT_ID,
SK_CLIENT_SECRET
diff --git a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
index 998920a..53f6550 100644
--- a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
+++ b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
@@ -32,7 +32,7 @@ Detect the project's language/framework from existing files (`package.json`, `re
| Stack | Install command |
|-------|----------------|
| Node.js | `npm install @scalekit-sdk/node` |
-| Python | `pip install scalekit-sdk` |
+| Python | `pip install scalekit-sdk-python` |
| Go | `go get github.com/scalekit/scalekit-go` |
| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` or `build.gradle` |
From c00570245cee821626f9d42c0d4df22d8c71023f Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Thu, 21 May 2026 22:30:21 +0530
Subject: [PATCH 30/39] =?UTF-8?q?fix:=20remaining=20CTO=20review=20issues?=
=?UTF-8?q?=20=E2=80=94=20token=20expiry,=20missing=20refs,=20README,=20de?=
=?UTF-8?q?dup?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- implementing-modular-sso: fix access token expiry 24h → 5min (configurable)
- implementing-saaskit-python: add django-reference.md and flask-reference.md
- agentkit: remove duplicate scalekit-code-doctor; point README to /saaskit:scalekit-code-doctor
- README: fix invalid install command syntax in plugin READMEs
- root README: add Windows install caveat
Co-Authored-By: Claude Sonnet 4.6
---
README.md | 2 +
plugins/agentkit/README.md | 4 +-
.../skills/scalekit-code-doctor/SKILL.md | 125 ----
.../references/COMMON-MISTAKES.md | 481 -------------
.../references/EXAMPLE-REPOS.md | 61 --
.../references/REFERENCE.md | 503 --------------
.../skills/implementing-modular-sso/SKILL.md | 2 +-
.../django-reference.md | 247 +++++++
.../flask-reference.md | 638 ++++--------------
9 files changed, 389 insertions(+), 1674 deletions(-)
delete mode 100644 plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
delete mode 100644 plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
delete mode 100644 plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
delete mode 100644 plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md
create mode 100644 plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
diff --git a/README.md b/README.md
index 9d387b3..bd8b74a 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,8 @@ After the script runs:
- Codex CLI installed and configured
- Project where you want to add authentication
+> **Windows**: install.sh requires macOS or Linux (or WSL on Windows). Native Windows PowerShell install is not yet supported.
+
---
### Validation
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
index 16a5dd0..e8a8e63 100644
--- a/plugins/agentkit/README.md
+++ b/plugins/agentkit/README.md
@@ -10,8 +10,8 @@ AgentKit handles the full OAuth lifecycle — authorization, token vault, and au
- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
- `production-readiness-agentkit` — Structured production readiness checklist for AgentKit integrations.
-- /agentkit:scalekit-code-doctor
- Diagnoses SDK usage issues, import errors, and common mistakes across AgentKit and SaaSKit.
+- /saaskit:scalekit-code-doctor (cross-plugin)
+ Diagnoses SDK usage issues, import errors, and common mistakes across AgentKit and SaaSKit. Requires the saaskit plugin.
## Configuration
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md b/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
deleted file mode 100644
index e15de81..0000000
--- a/plugins/agentkit/skills/scalekit-code-doctor/SKILL.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-name: scalekit-code-doctor
-description: Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. Generates illustration-quality snippets and reviews existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, or write a code sample for docs.
----
-
-# Scalekit Code Doctor
-
-**Before doing anything else**, read the reference files:
-- `references/REFERENCE.md` — Every correct SDK method signature and REST endpoint
-- `references/COMMON-MISTAKES.md` — Known anti-patterns with wrong → right corrections
-- `references/EXAMPLE-REPOS.md` — GitHub repos with working examples by framework
-
-Never hallucinate a method name, parameter, or import — if it's not in the reference, verify against live sources before using it.
-
-## Step 1 — Detect mode
-
-**Generate mode** — User describes what they want but has no code yet.
-**Review mode** — User provides existing code for validation.
-
-If unclear, ask: "Do you want me to generate a fresh code example, or review existing code?"
-
-## Step 2 — Identify context
-
-| Language | Package | Import |
-|----------|---------|--------|
-| Node.js / TypeScript | `@scalekit-sdk/node` | `import { ScalekitClient } from '@scalekit-sdk/node'` |
-| Python | `scalekit-sdk-python` | `from scalekit import ScalekitClient` |
-| Go | `scalekit-sdk-go` | `import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"` |
-| Java | `scalekit-sdk-java` | `import com.scalekit.ScalekitClient;` |
-
-Product area: **SaaSKit** (SSO, login, sessions, RBAC, SCIM) or **AgentKit** (connections, tool calling, MCP auth).
-
-## Step 3 — Generate mode
-
-Output should be illustration-ready: self-contained, essential path only, correct imports, framework-idiomatic, 1–2 pages max.
-
-**Correct SaaSKit login+callback example (Node.js/Express):**
-
-```typescript
-import { ScalekitClient } from '@scalekit-sdk/node';
-import crypto from 'crypto';
-
-const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
- process.env.SCALEKIT_CLIENT_ID!,
- process.env.SCALEKIT_CLIENT_SECRET!
-);
-
-const REDIRECT_URI = 'https://yourapp.com/auth/callback';
-
-// Login — generate auth URL with CSRF state
-app.get('/auth/login', (req, res) => {
- const state = crypto.randomBytes(32).toString('base64url');
- res.cookie('oauth_state', state, { httpOnly: true, sameSite: 'lax', secure: true });
- const authUrl = scalekit.getAuthorizationUrl(REDIRECT_URI, { state });
- res.redirect(authUrl);
-});
-
-// Callback — validate state, exchange code, store session
-app.get('/auth/callback', async (req, res) => {
- const { code, state } = req.query;
- if (state !== req.cookies.oauth_state) return res.status(403).send('CSRF mismatch');
-
- const result = await scalekit.authenticateWithCode(code as string, REDIRECT_URI);
- req.session.user = { id: result.user.id, email: result.user.email };
- req.session.idToken = result.idToken;
- res.redirect('/dashboard');
-});
-
-// Logout — clear local + end IdP session
-app.post('/auth/logout', (req, res) => {
- const logoutUrl = scalekit.getLogoutUrl({
- idTokenHint: req.session.idToken,
- postLogoutRedirectUri: 'https://yourapp.com',
- });
- req.session.destroy(() => res.redirect(logoutUrl));
-});
-```
-
-**Mandatory checks before outputting generated code** — cross-reference every SDK call against `references/REFERENCE.md`:
-- [ ] Method names exist for the target SDK
-- [ ] Parameters match in name, order, and type
-- [ ] Import path is exactly correct
-- [ ] Environment variable names follow Scalekit conventions
-
-## Step 4 — Review mode
-
-Check these categories in order:
-
-**1. SDK correctness** — Every method name, parameter, import, and return type matches `references/REFERENCE.md`.
-
-**2. Auth flow completeness** — Login has a callback. Callback validates `state`. Logout calls `getLogoutUrl()`. Token refresh exists if `offline_access` is used. IdP-initiated login handled if applicable.
-
-**3. Security** — Cookies: `httpOnly`, `secure`, `sameSite: 'lax'`. State: cryptographically random. Redirects: only relative paths. Secrets: from env vars. Webhooks: signature verified before processing.
-
-**4. Environment** — `SCALEKIT_ENV_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`. Redirect URI matches dashboard. Domain format: `https://.scalekit.com`.
-
-**5. Best practices** — Client is singleton. Error handling uses typed exceptions. `window.location.href` for OAuth redirects (not `router.push`).
-
-**Output for each finding:** What's wrong → Why it matters → Corrected code.
-
-## Step 5 — Unknown methods
-
-Resolution order when a method isn't in `references/REFERENCE.md`:
-
-| Priority | Source |
-|----------|--------|
-| 1 | Embedded `references/REFERENCE.md` |
-| 2 | Live SDK reference: `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-{node,python,go,java}/main/REFERENCE.md` |
-| 3 | REST API: `https://docs.scalekit.com/apis.md` |
-| 4 | State explicitly: "This method could not be verified." |
-
-Never output code containing an unverified method call.
-
-## Documentation
-
-| Resource | URL |
-|----------|-----|
-| REST API reference | `https://docs.scalekit.com/apis.md` |
-| LLM doc index | `https://docs.scalekit.com/llms.txt` |
-| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` |
-| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` |
-| MCP Auth docs | `https://docs.scalekit.com/_llms-txt/mcp-authentication.txt` |
-
-For framework-specific example repos, see `references/EXAMPLE-REPOS.md`.
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md b/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
deleted file mode 100644
index 5343181..0000000
--- a/plugins/agentkit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
+++ /dev/null
@@ -1,481 +0,0 @@
-# Common Mistakes in Scalekit Code
-
-This file catalogs known anti-patterns, hallucinated methods, and security issues found in Scalekit integrations. Each entry shows the wrong pattern and the correct fix. Use this as a lookup during both generation and review. 10 categories.
-
----
-
-## 1. Wrong Import Paths
-
-### Node.js
-
-**Wrong:**
-```typescript
-import ScalekitClient from '@scalekit-sdk/node'; // default import — use named import
-import { ScalekitClient } from 'scalekit'; // wrong package name
-import { ScalekitClient } from 'scalekit-sdk-node'; // wrong package name
-```
-
-**Correct (either works):**
-```typescript
-import { ScalekitClient } from '@scalekit-sdk/node';
-// OR
-import { Scalekit } from '@scalekit-sdk/node'; // official alias, also valid
-```
-
-Both `ScalekitClient` and `Scalekit` are valid named exports from `@scalekit-sdk/node`. The SDK source exports both. Use whichever is consistent with your codebase.
-
-### Python
-
-**Wrong:**
-```python
-from scalekit_sdk import ScalekitClient # wrong module name
-from scalekit.client import ScalekitClient # internal path, not public API
-import scalekit # missing class import
-pip install scalekit # wrong pip package name
-```
-
-**Correct:**
-```python
-from scalekit import ScalekitClient
-# pip install scalekit-sdk-python
-```
-
-### Go
-
-**Wrong:**
-```go
-import "github.com/scalekit-inc/scalekit-sdk-go" // missing version
-import "github.com/scalekit/scalekit-sdk-go/v2" // wrong org name
-```
-
-**Correct:**
-```go
-import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
-```
-
-### Java
-
-**Wrong:**
-```java
-import com.scalekit.sdk.ScalekitClient; // wrong package path
-import io.scalekit.ScalekitClient; // wrong package
-```
-
-**Correct:**
-```java
-import com.scalekit.ScalekitClient;
-```
-
----
-
-## 2. Wrong Sub-Client Names (Python vs Node)
-
-Python and Node use different pluralization for some sub-clients. Using the wrong one causes `AttributeError` in Python or `TypeError` in Node.
-
-| Sub-client | Node.js (singular) | Python (plural) |
-|------------|--------------------|--------------------|
-| Users | `client.user.getUser(...)` | `client.users.get_user(...)` |
-| Roles | `client.role.listRoles(...)` | `client.roles.list_roles(...)` |
-| Permissions | `client.permission.listPermissions(...)` | `client.permissions.list_permissions(...)` |
-| Sessions | `client.session.getSession(...)` | `client.sessions.get_session(...)` |
-
-Sub-clients that are the SAME in both: `organization`, `connection`, `domain`, `directory`.
-
-**Wrong (Python):**
-```python
-client.user.get_user(user_id) # AttributeError: 'ScalekitClient' has no attribute 'user'
-client.role.list_roles() # AttributeError
-client.session.revoke_session(sid) # AttributeError
-```
-
-**Correct (Python):**
-```python
-client.users.get_user(user_id)
-client.roles.list_roles()
-client.sessions.revoke_session(sid)
-```
-
----
-
-## 3. Wrong Method Names
-
-### Node.js
-
-| Wrong | Correct | Notes |
-|-------|---------|-------|
-| `scalekit.authenticate(code)` | `scalekit.authenticateWithCode(code, redirectUri)` | Missing `WithCode` suffix and `redirectUri` param |
-| `scalekit.getAuthUrl(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | Wrong method name |
-| `scalekit.login(...)` | `scalekit.getAuthorizationUrl(redirectUri, options?)` | No `login` method |
-| `scalekit.logout(...)` | `scalekit.getLogoutUrl(options?)` | Returns URL, doesn't perform logout |
-| `scalekit.verifyToken(token)` | `scalekit.validateAccessToken(token)` or `scalekit.validateToken(token)` | Wrong name |
-| `scalekit.createOrganization(...)` | `scalekit.organization.createOrganization(...)` | Must use sub-client |
-| `scalekit.getOrganization(...)` | `scalekit.organization.getOrganization(...)` | Must use sub-client |
-
-### Python
-
-| Wrong | Correct | Notes |
-|-------|---------|-------|
-| `client.authenticateWithCode(...)` | `client.authenticate_with_code(...)` | Python uses snake_case |
-| `client.getAuthorizationUrl(...)` | `client.get_authorization_url(...)` | Python uses snake_case |
-| `client.getLogoutUrl(...)` | `client.get_logout_url(...)` | Python uses snake_case |
-| `client.validateToken(...)` | `client.validate_access_token(...)` | Different method name in Python |
-| `client.verify_webhook(...)` | `client.verify_webhook_payload(...)` | Missing `_payload` suffix |
-
-### Go
-
-| Wrong | Correct | Notes |
-|-------|---------|-------|
-| `client.AuthenticateWithCode(code, uri)` | `client.AuthenticateWithCode(ctx, code, uri, options)` | Missing `ctx` parameter |
-| `client.GetAuthorizationUrl(uri)` | `client.GetAuthorizationUrl(uri, options)` | Missing `options` param (required in Go) |
-| `client.Organization.Create(...)` | `client.Organization().CreateOrganization(ctx, request)` | Use accessor method `Organization()`, not field |
-
-### Java
-
-| Wrong | Correct | Notes |
-|-------|---------|-------|
-| `client.organization.create(...)` | `client.organizations().create(...)` | Use `organizations()` accessor method, plural |
-| `client.getOrganization(id)` | `client.organizations().getById(id)` | Use sub-client accessor |
-| `client.connections.list(...)` | `client.connections().listConnectionsByOrganization(orgId)` | Use accessor method |
-
----
-
-## 4. Missing Required Parameters
-
-### `authenticateWithCode` — missing `redirectUri`
-
-**Wrong:**
-```typescript
-const result = await scalekit.authenticateWithCode(code);
-```
-
-**Correct:**
-```typescript
-const result = await scalekit.authenticateWithCode(code, redirectUri);
-```
-
-The `redirectUri` must exactly match the one used in `getAuthorizationUrl` AND what's registered in the Scalekit dashboard.
-
-### `getAuthorizationUrl` — missing `state` for CSRF
-
-**Wrong:**
-```typescript
-const authUrl = scalekit.getAuthorizationUrl(redirectUri);
-```
-
-**Correct:**
-```typescript
-import crypto from 'crypto';
-const state = crypto.randomBytes(32).toString('base64url');
-// Store state in session/cookie for validation in callback
-const authUrl = scalekit.getAuthorizationUrl(redirectUri, { state });
-```
-
-While `state` is technically optional, omitting it is a **CSRF vulnerability**. Always generate and validate it.
-
-### Go — missing `context.Context`
-
-**Wrong:**
-```go
-resp, err := client.AuthenticateWithCode(code, redirectUri, opts)
-```
-
-**Correct:**
-```go
-resp, err := client.AuthenticateWithCode(ctx, code, redirectUri, opts)
-```
-
-All Go network methods require `context.Context` as the first parameter.
-
----
-
-## 5. Auth Flow Gaps
-
-### Missing callback handler
-
-If you see a login route that generates an auth URL but no corresponding callback route, the flow is incomplete. The callback MUST:
-1. Validate the `state` parameter against the stored value
-2. Call `authenticateWithCode(code, redirectUri)`
-3. Store the session (tokens + user info)
-4. Redirect to the application
-
-### Missing `state` validation in callback
-
-**Wrong:**
-```typescript
-app.get('/auth/callback', async (req, res) => {
- const { code } = req.query;
- const result = await scalekit.authenticateWithCode(code, redirectUri);
- // ... store session
-});
-```
-
-**Correct:**
-```typescript
-app.get('/auth/callback', async (req, res) => {
- const { code, state } = req.query;
-
- const storedState = req.session.oauthState; // or from cookie
- if (!state || state !== storedState) {
- return res.status(403).send('CSRF validation failed');
- }
-
- const result = await scalekit.authenticateWithCode(code, redirectUri);
- // ... store session
-});
-```
-
-### Incomplete logout — only clearing local session
-
-**Wrong:**
-```typescript
-app.post('/logout', (req, res) => {
- req.session.destroy();
- res.redirect('/');
-});
-```
-
-**Correct:**
-```typescript
-app.post('/logout', (req, res) => {
- const logoutUrl = scalekit.getLogoutUrl({
- idTokenHint: req.session.idToken,
- postLogoutRedirectUri: 'https://yourapp.com',
- });
- req.session.destroy();
- res.redirect(logoutUrl); // Ends IdP session too
-});
-```
-
-Without calling `getLogoutUrl()`, the user's IdP session persists and they get silently re-authenticated on next login.
-
-### Missing IdP-initiated login handling
-
-If the callback route doesn't check for `idp_initiated_login` query parameter, IdP-initiated SSO won't work:
-
-```typescript
-app.get('/auth/callback', async (req, res) => {
- const { idp_initiated_login, code, state } = req.query;
-
- if (idp_initiated_login) {
- const claims = await scalekit.getIdpInitiatedLoginClaims(idp_initiated_login);
- const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
- connectionId: claims.connection_id,
- organizationId: claims.organization_id,
- loginHint: claims.login_hint,
- ...(claims.relay_state && { state: claims.relay_state }),
- });
- return res.redirect(authUrl);
- }
-
- // Normal SP-initiated flow continues...
-});
-```
-
----
-
-## 6. Security Anti-Patterns
-
-### `sameSite: 'strict'` on session cookies
-
-**Wrong:**
-```typescript
-res.cookie('session', data, { sameSite: 'strict', httpOnly: true, secure: true });
-```
-
-**Correct:**
-```typescript
-res.cookie('session', data, { sameSite: 'lax', httpOnly: true, secure: true });
-```
-
-OAuth callbacks are cross-site redirects from Scalekit back to your app. `strict` drops the cookie on that redirect, causing CSRF state mismatch errors on every login.
-
-### Missing `httpOnly` flag
-
-**Wrong:**
-```typescript
-res.cookie('session', data, { secure: true });
-```
-
-**Correct:**
-```typescript
-res.cookie('session', data, { httpOnly: true, secure: true, sameSite: 'lax' });
-```
-
-Without `httpOnly`, JavaScript can read the session cookie — XSS becomes session hijacking.
-
-### Open redirect via unvalidated `next` parameter
-
-**Wrong:**
-```typescript
-const next = req.query.next;
-res.redirect(next); // Attacker can set next=https://evil.com
-```
-
-**Correct:**
-```typescript
-const next = req.query.next;
-// Only allow relative paths
-if (!next || !next.startsWith('/') || next.startsWith('//')) {
- return res.redirect('/dashboard');
-}
-res.redirect(next);
-```
-
-### Hardcoded client secret
-
-**Wrong:**
-```typescript
-const scalekit = new ScalekitClient(
- 'https://myapp.scalekit.com',
- 'skc_12345',
- 'sks_secret_abc123' // NEVER hardcode secrets
-);
-```
-
-**Correct:**
-```typescript
-const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
- process.env.SCALEKIT_CLIENT_ID!,
- process.env.SCALEKIT_CLIENT_SECRET!
-);
-```
-
-### Webhook handler without signature verification
-
-**Wrong:**
-```typescript
-app.post('/webhooks', express.json(), (req, res) => {
- const event = req.body; // Trusting unverified payload
- handleEvent(event);
- res.sendStatus(200);
-});
-```
-
-**Correct:**
-```typescript
-app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
- const isValid = scalekit.verifyWebhookPayload(
- process.env.SCALEKIT_WEBHOOK_SECRET!,
- req.headers,
- req.body.toString()
- );
-
- if (!isValid) {
- return res.sendStatus(401);
- }
-
- const event = JSON.parse(req.body.toString());
- handleEvent(event);
- res.sendStatus(200);
-});
-```
-
-Note: The webhook body must be raw (not JSON-parsed) for signature verification to work.
-
-### Client-side navigation for OAuth redirect
-
-**Wrong:**
-```typescript
-// React / Next.js
-router.push(authUrl); // Client-side route change
-```
-
-**Correct:**
-```typescript
-window.location.href = authUrl; // Full page navigation required for OAuth
-```
-
-OAuth redirects are full HTTP redirects to an external domain (Scalekit/IdP). Client-side routing doesn't work.
-
----
-
-## 7. Environment Variable Mistakes
-
-| Wrong | Correct | Issue |
-|-------|---------|-------|
-| `SCALEKIT_URL` | `SCALEKIT_ENV_URL` | Missing `ENV_` |
-| `SCALEKIT_SECRET` | `SCALEKIT_CLIENT_SECRET` | Missing `CLIENT_` |
-| `SCALEKIT_ID` | `SCALEKIT_CLIENT_ID` | Missing `CLIENT_` |
-| `SCALEKIT_CALLBACK_URL` | `SCALEKIT_REDIRECT_URI` | Wrong name entirely |
-| `http://myapp.scalekit.com` | `https://myapp.scalekit.com` | Must be HTTPS |
-| `https://myapp.scalekit.com/` | `https://myapp.scalekit.com` | No trailing slash |
-
----
-
-## 8. Client Instantiation Mistakes
-
-### Creating a new client per request
-
-**Wrong:**
-```typescript
-app.get('/api/data', async (req, res) => {
- const scalekit = new ScalekitClient(envUrl, clientId, clientSecret); // per-request!
- // ...
-});
-```
-
-**Correct:**
-```typescript
-// Module-level singleton
-const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
- process.env.SCALEKIT_CLIENT_ID!,
- process.env.SCALEKIT_CLIENT_SECRET!
-);
-
-app.get('/api/data', async (req, res) => {
- // Use the singleton
- const result = await scalekit.validateAccessToken(token);
-});
-```
-
-The client manages its own token lifecycle and connection pooling. Creating it per request wastes resources and can hit rate limits.
-
----
-
-## 9. Token Refresh Race Conditions
-
-When multiple browser tabs trigger token refresh simultaneously, the second request often fails because the first one already consumed the refresh token.
-
-**Mitigation pattern:**
-```typescript
-// Before refreshing, set a short-lived flag
-const REFRESH_LOCK_KEY = 'refresh_in_progress';
-
-async function refreshToken(session) {
- if (session[REFRESH_LOCK_KEY]) return; // Another tab is refreshing
-
- session[REFRESH_LOCK_KEY] = true;
- try {
- const result = await scalekit.refreshAccessToken(session.refreshToken);
- session.accessToken = result.accessToken;
- session.refreshToken = result.refreshToken;
- } finally {
- delete session[REFRESH_LOCK_KEY];
- }
-}
-```
-
----
-
-## 10. Missing Scopes
-
-### Refresh tokens require `offline_access` scope
-
-**Wrong:**
-```typescript
-const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
- scopes: ['openid', 'profile', 'email'],
-});
-// Later: scalekit.refreshAccessToken(refreshToken) → fails because no refresh token was issued
-```
-
-**Correct:**
-```typescript
-const authUrl = scalekit.getAuthorizationUrl(redirectUri, {
- scopes: ['openid', 'profile', 'email', 'offline_access'],
-});
-```
-
-Without `offline_access`, the authorization server won't issue a refresh token.
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md b/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
deleted file mode 100644
index a66718b..0000000
--- a/plugins/agentkit/skills/scalekit-code-doctor/references/EXAMPLE-REPOS.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Example Repos
-
-Working examples by framework. Fetch the matching repo for real, tested patterns when generating or reviewing code.
-
-## SaaSKit — Auth examples
-
-| Framework | Repo | What it shows |
-|-----------|------|---------------|
-| Next.js (App Router) | [scalekit-nextjs-auth-example](https://github.com/scalekit-inc/scalekit-nextjs-auth-example) | SSO, sessions, protected routes |
-| Next.js (Pages) | [nextjs-example-apps](https://github.com/scalekit-inc/nextjs-example-apps) | React SSO flows |
-| Next.js + Auth.js | [scalekit-authjs-example](https://github.com/scalekit-developers/scalekit-authjs-example) | Enterprise SSO with next-auth v5 |
-| Express.js | [scalekit-express-auth-example](https://github.com/scalekit-inc/scalekit-express-auth-example) | Node SDK, sessions |
-| Express.js | [scalekit-express-example](https://github.com/scalekit-developers/scalekit-express-example) | SSO, middleware |
-| FastAPI | [scalekit-fastapi-auth-example](https://github.com/scalekit-inc/scalekit-fastapi-auth-example) | Python SDK, OAuth 2.0 |
-| FastAPI | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Async auth, Pydantic |
-| Django | [scalekit-django-auth-example](https://github.com/scalekit-inc/scalekit-django-auth-example) | Django auth integration |
-| Flask | [scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example) | Flask sessions |
-| Spring Boot | [scalekit-springboot-auth-example](https://github.com/scalekit-inc/scalekit-springboot-auth-example) | Spring Security, OIDC |
-| Go (Gin) | [scalekit-go-example](https://github.com/scalekit-developers/scalekit-go-example) | Go SDK, SSO |
-| Laravel | [scalekit-laravel-auth-example](https://github.com/scalekit-inc/scalekit-laravel-auth-example) | REST API, Laravel |
-| Astro | [astro-scalekit-auth-example](https://github.com/scalekit-developers/astro-scalekit-auth-example) | Auth, SSO, social login |
-| .NET | [dotnet-example-apps](https://github.com/scalekit-inc/dotnet-example-apps) | ASP.NET Core, SAML/OIDC |
-| Expo (mobile) | [expo-scalekit-sample](https://github.com/scalekit-inc/expo-scalekit-sample) | OAuth 2.0 + PKCE |
-
-## SaaSKit — Integration examples
-
-| Integration | Repo |
-|-------------|------|
-| AWS Cognito | [scalekit-cognito-sso](https://github.com/scalekit-inc/scalekit-cognito-sso) |
-| Firebase | [scalekit-firebase-sso](https://github.com/scalekit-inc/scalekit-firebase-sso) |
-| Supabase | [scalekit-supabase-example](https://github.com/scalekit-inc/scalekit-supabase-example) |
-| Multi-app SSO | [multiapp-demo](https://github.com/scalekit-inc/multiapp-demo) |
-| OIDC/SAML/SCIM | [oidc-saml-scim-examples](https://github.com/scalekit-developers/oidc-saml-scim-examples) |
-| Full demo app | [coffee-desk-demo](https://github.com/scalekit-inc/coffee-desk-demo) |
-
-## AgentKit — Agent and MCP examples
-
-| Framework | Repo |
-|-----------|------|
-| LangChain | [sample-langchain-agent](https://github.com/scalekit-inc/sample-langchain-agent) |
-| Google ADK | [google-adk-agent-example](https://github.com/scalekit-inc/google-adk-agent-example) |
-| Vercel AI SDK | [vercel-ai-agent-toolkit](https://github.com/scalekit-developers/vercel-ai-agent-toolkit) |
-| MCP Auth | [mcp-auth-demos](https://github.com/scalekit-inc/mcp-auth-demos) |
-| FastMCP | [fastmcp-scalekit-example](https://github.com/scalekit-inc/fastmcp-scalekit-example) |
-| Agent auth | [agent-auth-examples](https://github.com/scalekit-developers/agent-auth-examples) |
-
-## Developer tools
-
-| Tool | Repo |
-|------|------|
-| Dryrun CLI | [scalekit-dryrun](https://github.com/scalekit-inc/scalekit-dryrun) |
-| MCP server | [scalekit-mcp-server](https://github.com/scalekit-inc/scalekit-mcp-server) |
-| API collections | [api-collections](https://github.com/scalekit-inc/api-collections) |
-
-## Frontend SDKs
-
-| SDK | Repo |
-|-----|------|
-| React | [scalekit-react-sdk](https://github.com/scalekit-inc/scalekit-react-sdk) |
-| Vue | [scalekit-vue-sdk](https://github.com/scalekit-inc/scalekit-vue-sdk) |
-| Expo | [scalekit-expo-sdk](https://github.com/scalekit-inc/scalekit-expo-sdk) |
\ No newline at end of file
diff --git a/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md b/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md
deleted file mode 100644
index 5ecab18..0000000
--- a/plugins/agentkit/skills/scalekit-code-doctor/references/REFERENCE.md
+++ /dev/null
@@ -1,503 +0,0 @@
-# Scalekit API Reference — Compact Lookup
-
-This file contains every correct SDK method signature and REST endpoint. Use it as ground truth when generating or reviewing Scalekit code. If a method isn't listed here, do NOT assume it exists — verify against the live SDK source or `https://docs.scalekit.com/apis.md`.
-
----
-
-## Client Initialization
-
-### Node.js (`@scalekit-sdk/node`)
-
-```typescript
-import { ScalekitClient } from '@scalekit-sdk/node';
-
-const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!, // string — environment URL
- process.env.SCALEKIT_CLIENT_ID!, // string — client ID
- process.env.SCALEKIT_CLIENT_SECRET! // string — client secret
-);
-```
-
-### Python (`scalekit-sdk-python`)
-
-```python
-from scalekit import ScalekitClient
-
-scalekit_client = ScalekitClient(
- os.environ.get('SCALEKIT_ENV_URL'), # str — environment URL
- os.environ.get('SCALEKIT_CLIENT_ID'), # str — client ID
- os.environ.get('SCALEKIT_CLIENT_SECRET') # str — client secret
-)
-```
-
-### Go (`github.com/scalekit-inc/scalekit-sdk-go`)
-
-```go
-import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
-
-client := scalekit.NewScalekitClient(
- os.Getenv("SCALEKIT_ENV_URL"), // string — environment URL
- os.Getenv("SCALEKIT_CLIENT_ID"), // string — client ID
- os.Getenv("SCALEKIT_CLIENT_SECRET"), // string — client secret
-)
-```
-
-### Java (`com.scalekit:scalekit-sdk-java`)
-
-```java
-import com.scalekit.ScalekitClient;
-
-ScalekitClient client = new ScalekitClient(
- System.getenv("SCALEKIT_ENV_URL"), // String — environment URL
- System.getenv("SCALEKIT_CLIENT_ID"), // String — client ID
- System.getenv("SCALEKIT_CLIENT_SECRET") // String — client secret
-);
-```
-
----
-
-## Environment Variables
-
-| Variable | Purpose | Format |
-|----------|---------|--------|
-| `SCALEKIT_ENV_URL` | Environment URL | `https://.scalekit.com` (prod) or `https://.scalekit.dev` (dev) |
-| `SCALEKIT_CLIENT_ID` | Client ID | String from dashboard |
-| `SCALEKIT_CLIENT_SECRET` | Client secret | String from dashboard |
-| `SCALEKIT_REDIRECT_URI` | OAuth callback URL | Must exactly match dashboard config |
-| `SCALEKIT_WEBHOOK_SECRET` | Webhook signing secret | Format: `whsec_...` |
-
-Note: The REST API docs use `SCALEKIT_ENVIRONMENT_URL` in some examples. Both `SCALEKIT_ENV_URL` and `SCALEKIT_ENVIRONMENT_URL` are acceptable — just be consistent within a project.
-
----
-
-## Auth Methods (called directly on the client)
-
-### Node.js
-
-| Method | Signature | Returns |
-|--------|-----------|---------|
-| `getAuthorizationUrl` | `(redirectUri: string, options?: AuthorizationUrlOptions) → string` | Authorization URL string |
-| `authenticateWithCode` | `(code: string, redirectUri: string, options?: AuthenticationOptions) → Promise` | Tokens + user info |
-| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: string, options?: TokenValidationOptions) → Promise` | IDP login claims |
-| `validateAccessToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Boolean |
-| `validateToken` | `(token: string, options?: TokenValidationOptions) → Promise` | Decoded JWT payload |
-| `verifyScopes` | `(token: string, requiredScopes: string[]) → boolean` | Boolean |
-| `getLogoutUrl` | `(options?: LogoutUrlOptions) → string` | Logout URL string |
-| `refreshAccessToken` | `(refreshToken: string) → Promise` | New tokens |
-| `verifyWebhookPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
-| `verifyInterceptorPayload` | `(secret: string, headers: Record, payload: string) → boolean` | Boolean |
-| `generateClientToken` | `(clientId: string, clientSecret: string) → Promise` | M2M access token |
-| `getClientAccessToken` | `() → Promise` | M2M access token (uses stored credentials) |
-
-**AuthorizationUrlOptions**: `scopes?: string[]`, `state?: string`, `nonce?: string`, `loginHint?: string`, `domainHint?: string`, `connectionId?: string`, `organizationId?: string`, `provider?: string`, `codeChallenge?: string`, `codeChallengeMethod?: string`, `prompt?: string`
-
-**LogoutUrlOptions**: `idTokenHint?: string`, `postLogoutRedirectUri?: string`, `state?: string`
-
-**AuthenticationOptions**: `codeVerifier?: string`
-
-### Python
-
-| Method | Signature | Returns |
-|--------|-----------|---------|
-| `get_authorization_url` | `(redirect_uri: str, options?: AuthorizationUrlOptions) → str` | Authorization URL string |
-| `authenticate_with_code` | `(code: str, redirect_uri: str, options?: CodeAuthenticationOptions) → dict` | Tokens + user info |
-| `get_idp_initiated_login_claims` | `(idp_initiated_login_token: str, options?: TokenValidationOptions) → IdpInitiatedLoginClaims` | IDP login claims |
-| `validate_access_token` | `(token: str, options?: TokenValidationOptions) → bool` | Boolean |
-| `get_logout_url` | `(options?: LogoutUrlOptions) → str` | Logout URL string |
-| `refresh_access_token` | `(refresh_token: str) → dict` | New tokens |
-| `verify_webhook_payload` | `(secret: str, headers: Dict[str, str], payload: str\|bytes) → bool` | Boolean |
-
-**AuthorizationUrlOptions** (Python): `scopes`, `state`, `nonce`, `login_hint`, `domain_hint`, `connection_id`, `organization_id`, `provider`, `prompt` — all `Optional[str]` (scopes is `Optional[list[str]]`)
-
-**LogoutUrlOptions** (Python): `id_token_hint`, `post_logout_redirect_uri`, `state` — all `Optional[str]`
-
-### Go
-
-| Method | Signature | Returns |
-|--------|-----------|---------|
-| `GetAuthorizationUrl` | `(redirectUri string, options AuthorizationUrlOptions) → (*url.URL, error)` | URL + error |
-| `AuthenticateWithCode` | `(ctx context.Context, code string, redirectUri string, options AuthenticationOptions) → (*AuthenticationResponse, error)` | Response + error |
-| `GetIdpInitiatedLoginClaims` | `(ctx context.Context, idpInitiatedLoginToken string) → (*IdpInitiatedLoginClaims, error)` | Claims + error |
-| `GetAccessTokenClaims` | `(ctx context.Context, accessToken string) → (*AccessTokenClaims, error)` | Claims + error |
-| `ValidateAccessToken` | `(ctx context.Context, accessToken string) → (bool, error)` | Boolean + error |
-| `RefreshAccessToken` | `(ctx context.Context, refreshToken string) → (*TokenResponse, error)` | Tokens + error |
-| `GetLogoutUrl` | `(options LogoutUrlOptions) → string` | Logout URL string |
-| `VerifyWebhookPayload` | `(secret string, headers map[string][]string, payload []byte) → bool` | Boolean |
-
-**Go AuthorizationUrlOptions fields**: `Scopes []string`, `State string`, `Nonce string`, `LoginHint string`, `DomainHint string`, `ConnectionId string`, `OrganizationId string`, `Provider string`, `CodeChallenge string`, `CodeChallengeMethod string`, `Prompt string`
-
-Note: Go methods take `context.Context` as the first parameter for network calls. `GetAuthorizationUrl` and `GetLogoutUrl` do NOT take context (they're local-only operations).
-
-### Java
-
-| Method | Signature | Returns |
-|--------|-----------|---------|
-| `getAuthorizationUrl` | `(redirectUri: String, options: AuthorizationUrlOptions) → String` | Authorization URL string |
-| `authenticateWithCode` | `(code: String, redirectUri: String, options: AuthenticationOptions) → AuthenticationResponse` | Tokens + user info |
-| `getIdpInitiatedLoginClaims` | `(idpInitiatedLoginToken: String) → IdpInitiatedLoginClaims` | Claims |
-| `validateToken` | `(token: String) → Claims` | JWT Claims |
-| `getLogoutUrl` | `(options: LogoutUrlOptions) → String` | Logout URL string |
-
----
-
-## Sub-client Methods
-
-### Node.js sub-clients (accessed via `client..`)
-
-**client.organization**
-| Method | Signature |
-|--------|-----------|
-| `createOrganization` | `(name: string, options?) → Promise` |
-| `getOrganization` | `(id: string) → Promise` |
-| `getOrganizationByExternalId` | `(externalId: string) → Promise` |
-| `listOrganizations` | `(options?) → Promise` |
-| `updateOrganization` | `(id: string, organization) → Promise` |
-| `deleteOrganization` | `(id: string) → Promise` |
-| `generatePortalLink` | `(organizationId: string, features?) → Promise` |
-| `updateOrganizationSettings` | `(id: string, settings) → Promise` |
-
-**client.connection**
-| Method | Signature |
-|--------|-----------|
-| `getConnection` | `(id: string) → Promise` |
-| `listConnections` | `(options?) → Promise` |
-| `listConnectionsByDomain` | `(domain: string, options?) → Promise` |
-| `enableConnection` | `(connectionId: string) → Promise` |
-| `disableConnection` | `(connectionId: string) → Promise` |
-
-**client.domain**
-| Method | Signature |
-|--------|-----------|
-| `createDomain` | `(domain: string) → Promise` |
-| `getDomain` | `(domain: string) → Promise` |
-| `listDomains` | `(options?) → Promise` |
-| `deleteDomain` | `(domain: string) → Promise` |
-
-**client.user**
-| Method | Signature |
-|--------|-----------|
-| `createUser` | `(organizationId: string, user) → Promise` |
-| `createUserAndMembership` | `(organizationId: string, request) → Promise` |
-| `getUser` | `(id: string) → Promise` |
-| `listUsers` | `(options?) → Promise` |
-| `listOrganizationUsers` | `(organizationId: string, options?) → Promise` |
-| `updateUser` | `(id: string, user) → Promise` |
-| `deleteUser` | `(id: string) → Promise` |
-| `searchUsers` | `(options) → Promise` |
-| `searchOrganizationUsers` | `(organizationId: string, options) → Promise` |
-
-**client.directory**
-| Method | Signature |
-|--------|-----------|
-| `listDirectories` | `(organizationId: string) → Promise` |
-| `getDirectory` | `(organizationId: string, directoryId: string) → Promise` |
-| `listDirectoryUsers` | `(organizationId: string, directoryId: string, options?) → Promise` |
-| `listDirectoryGroups` | `(organizationId: string, directoryId: string, options?) → Promise` |
-| `enableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
-| `disableDirectory` | `(organizationId: string, directoryId: string) → Promise` |
-
-**client.role**
-| Method | Signature |
-|--------|-----------|
-| `createRole` | `(role) → Promise` |
-| `getRole` | `(roleId: string) → Promise` |
-| `listRoles` | `(options?) → Promise` |
-| `updateRole` | `(roleId: string, role) → Promise` |
-| `deleteRole` | `(roleId: string) → Promise` |
-
-**client.permission**
-| Method | Signature |
-|--------|-----------|
-| `createPermission` | `(permission) → Promise` |
-| `listPermissions` | `(options?) → Promise` |
-| `updatePermission` | `(permissionId: string, permission) → Promise` |
-| `deletePermission` | `(permissionId: string) → Promise` |
-
-**client.session**
-| Method | Signature |
-|--------|-----------|
-| `getSession` | `(sessionId: string) → Promise` |
-| `getUserSessions` | `(userId: string, options?) → Promise` |
-| `revokeSession` | `(sessionId: string) → Promise` |
-| `revokeAllUserSessions` | `(userId: string) → Promise` |
-
-**client.connectedAccounts**
-| Method | Signature |
-|--------|-----------|
-| `listConnectedAccounts` | `(options?) → Promise` |
-| `getConnectedAccountAuth` | `(options) → Promise` |
-| `createConnectedAccount` | `(request) → Promise` |
-| `updateConnectedAccount` | `(request) → Promise` |
-| `deleteConnectedAccount` | `(request) → Promise` |
-
-**client.tools**
-| Method | Signature |
-|--------|-----------|
-| `executeTool` | `(request) → Promise` |
-
-### Python sub-clients (accessed via `client..`)
-
-Python uses `snake_case` method names. **Important**: Some Python sub-client names are **plural** while Node uses singular. This is a common source of bugs.
-
-| Node.js | Python | Difference |
-|---------|--------|------------|
-| `client.user` | `client.users` | Plural in Python |
-| `client.role` | `client.roles` | Plural in Python |
-| `client.permission` | `client.permissions` | Plural in Python |
-| `client.session` | `client.sessions` | Plural in Python |
-| `client.organization` | `client.organization` | Same |
-| `client.connection` | `client.connection` | Same |
-| `client.domain` | `client.domain` | Same |
-| `client.directory` | `client.directory` | Same |
-| `client.connectedAccounts` | `client.connected_accounts` | snake_case in Python |
-
-Methods:
-- `client.organization.create_organization(organization)`
-- `client.organization.get_organization(organization_id)`
-- `client.organization.list_organizations(page_size, page_token?)`
-- `client.organization.update_organization(organization_id, organization)`
-- `client.organization.delete_organization(organization_id)`
-- `client.organization.generate_portal_link(organization_id, features?)`
-- `client.connection.list_connections(organization_id, include?)`
-- `client.connection.get_connection(organization_id, connection_id)`
-- `client.connection.enable_connection(organization_id, connection_id)`
-- `client.connection.disable_connection(organization_id, connection_id)`
-- `client.domain.create_domain(organization_id, domain_name)`
-- `client.domain.list_domains(organization_id)`
-- `client.domain.delete_domain(organization_id, domain_id)`
-- `client.directory.list_directories(organization_id)`
-- `client.directory.get_directory(organization_id, directory_id)`
-- `client.directory.list_directory_users(organization_id, directory_id, options?)`
-- `client.directory.list_directory_groups(organization_id, directory_id, options?)`
-- `client.users.create_user(organization_id, user)`
-- `client.users.get_user(user_id)`
-- `client.users.list_users(options?)`
-- `client.users.update_user(user_id, user)`
-- `client.users.delete_user(user_id)`
-- `client.roles.create_role(role)`
-- `client.roles.list_roles(options?)`
-- `client.roles.update_role(role_id, role)`
-- `client.roles.delete_role(role_id)`
-- `client.permissions.create_permission(permission)`
-- `client.permissions.list_permissions(options?)`
-- `client.sessions.get_session(session_id)`
-- `client.sessions.get_user_sessions(user_id, options?)`
-- `client.sessions.revoke_session(session_id)`
-- `client.sessions.revoke_all_user_sessions(user_id)`
-
-Additional Python-only methods on client:
-- `client.validate_access_token_and_get_claims(token, options?) → dict` — validates and returns decoded claims
-- `client.verify_scopes(token, required_scopes) → bool` — checks scopes, raises on missing
-- `client.generate_client_token(client_id, client_secret, scopes?) → str` — M2M token generation
-- `client.get_client_access_token() → str` — M2M token using stored credentials
-- `client.verify_interceptor_payload(secret, headers, payload) → bool` — interceptor signature verification
-
-Note: Python connection/domain/directory methods often require `organization_id` as the first parameter, unlike Node which uses option objects.
-
-### Go sub-clients
-
-Go uses `PascalCase` and typed request/response objects:
-- `client.Organization().CreateOrganization(ctx, request)`
-- `client.Organization().GetOrganization(ctx, organizationId)`
-- `client.Organization().ListOrganizations(ctx, pageSize, pageToken)`
-- `client.Organization().UpdateOrganization(ctx, organizationId, request)`
-- `client.Organization().DeleteOrganization(ctx, organizationId)`
-- `client.Organization().GeneratePortalLink(ctx, organizationId, features)`
-- `client.Connection().GetConnection(ctx, organizationId, connectionId)`
-- `client.Connection().ListConnections(ctx, organizationId)`
-- `client.Connection().EnableConnection(ctx, organizationId, connectionId)`
-- `client.Connection().DisableConnection(ctx, organizationId, connectionId)`
-- `client.Domain().CreateDomain(ctx, organizationId, domainName)`
-- `client.Domain().ListDomains(ctx, organizationId)`
-- `client.Domain().DeleteDomain(ctx, organizationId, domainId)`
-- `client.Directory().ListDirectories(ctx, organizationId)`
-- `client.Directory().GetDirectory(ctx, organizationId, directoryId)`
-- `client.Directory().ListDirectoryUsers(ctx, organizationId, directoryId, options)`
-- `client.Directory().ListDirectoryGroups(ctx, organizationId, directoryId, options)`
-- `client.User().CreateUser(ctx, organizationId, request)`
-- `client.User().GetUser(ctx, userId)`
-- `client.User().ListUsers(ctx, options)`
-- `client.User().UpdateUser(ctx, userId, request)`
-- `client.User().DeleteUser(ctx, userId)`
-- `client.Role().ListRoles(ctx)`
-- `client.Role().CreateRole(ctx, request)`
-- `client.Session().GetSession(ctx, sessionId)`
-- `client.Session().RevokeSession(ctx, sessionId)`
-- `client.Session().RevokeAllUserSessions(ctx, userId)`
-
-### Java sub-clients
-
-Java uses accessor methods that return typed clients:
-- `client.organizations().create(request) → CreateOrganizationResponse`
-- `client.organizations().getById(organizationId) → Organization`
-- `client.organizations().getByExternalId(externalId) → Organization`
-- `client.organizations().list(pageSize, pageToken) → ListOrganizationsResponse`
-- `client.organizations().update(organizationId, request) → Organization`
-- `client.organizations().delete(organizationId)`
-- `client.organizations().generatePortalLink(organizationId, features) → Link`
-- `client.connections().listConnectionsByOrganization(organizationId) → ListConnectionsResponse`
-- `client.connections().getConnection(organizationId, connectionId) → GetConnectionResponse`
-- `client.connections().enableConnection(organizationId, connectionId)`
-- `client.connections().disableConnection(organizationId, connectionId)`
-- `client.domains().listDomainsByOrganizationId(organizationId) → ListDomainsResponse`
-- `client.domains().createDomain(organizationId, domainName) → CreateDomainResponse`
-- `client.domains().deleteDomain(organizationId, domainId)`
-- `client.directories().listDirectories(organizationId) → ListDirectoriesResponse`
-- `client.directories().getDirectory(organizationId, directoryId) → GetDirectoryResponse`
-- `client.directories().listDirectoryUsers(organizationId, directoryId) → ListDirectoryUsersResponse`
-- `client.directories().listDirectoryGroups(organizationId, directoryId) → ListDirectoryGroupsResponse`
-- `client.users().getUser(userId) → GetUserResponse`
-- `client.users().listUsers(options) → ListUsersResponse`
-- `client.users().createUser(organizationId, request) → CreateUserResponse`
-- `client.users().createUserAndMembership(organizationId, request) → CreateUserAndMembershipResponse`
-- `client.users().updateUser(userId, request) → UpdateUserResponse`
-- `client.users().deleteUser(userId)`
-- `client.roles().listRoles() → ListRolesResponse`
-- `client.roles().createRole(request) → CreateRoleResponse`
-- `client.roles().updateRole(roleId, request) → UpdateRoleResponse`
-- `client.roles().deleteRole(roleId)`
-- `client.permissions().listPermissions() → ListPermissionsResponse`
-- `client.permissions().createPermission(request) → CreatePermissionResponse`
-- `client.sessions().getSession(sessionId) → SessionDetails`
-- `client.sessions().getUserSessions(userId, filter) → UserSessionDetails`
-- `client.sessions().revokeSession(sessionId)`
-- `client.sessions().revokeAllUserSessions(userId)`
-
-Note: Java does NOT yet support Connected Accounts, Tools, or Actions in the public API.
-
----
-
-## REST API Endpoints
-
-Base URL: `https://.scalekit.com` (production) or `https://.scalekit.dev` (development)
-
-Authentication: Bearer token from `POST /oauth/token` with `client_credentials` grant.
-
-Endpoints are grouped by product suite: **SaaSKit** (authentication, SSO, SCIM, RBAC, sessions) and **AgentKit** (connections, tool calling, MCP auth).
-
-### Token endpoint
-```
-POST /oauth/token
-Content-Type: application/x-www-form-urlencoded
-
-client_id={client_id}&client_secret={client_secret}&grant_type=client_credentials
-```
-
-### AgentKit — Connected Accounts
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/connected_accounts` | List connected accounts |
-| POST | `/api/v1/connected_accounts` | Create a connected account |
-| PUT | `/api/v1/connected_accounts` | Update connected account credentials |
-| POST | `/api/v1/connected_accounts:delete` | Delete a connected account |
-| GET | `/api/v1/connected_accounts/auth` | Get connected account auth details |
-| GET | `/api/v1/connected_accounts:search` | Search connected accounts |
-| POST | `/api/v1/connected_accounts/magic_link` | Generate authentication magic link |
-| POST | `/api/v1/connected_accounts/user/verify` | Verify connected account user |
-
-### SaaSKit — Connections (SSO)
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/connections` | List connections |
-
-### SaaSKit — Organizations
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/organizations` | List organizations |
-| POST | `/api/v1/organizations` | Create an organization |
-| GET | `/api/v1/organizations/{id}` | Get organization details |
-| PATCH | `/api/v1/organizations/{id}` | Update organization |
-| DELETE | `/api/v1/organizations/{id}` | Delete an organization |
-| PUT | `/api/v1/organizations/{id}/portal_links` | Generate admin portal link |
-| PATCH | `/api/v1/organizations/{id}/settings` | Toggle organization settings |
-
-### SaaSKit — Roles
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/organizations/{org_id}/roles` | List organization roles |
-| POST | `/api/v1/organizations/{org_id}/roles` | Create organization role |
-| GET | `/api/v1/organizations/{org_id}/roles/{role_name}` | Get role details |
-| PUT | `/api/v1/organizations/{org_id}/roles/{role_name}` | Update role |
-| DELETE | `/api/v1/organizations/{org_id}/roles/{role_name}` | Delete role |
-| PATCH | `/api/v1/organizations/{org_id}/roles:set_defaults` | Set default roles |
-
-### SaaSKit — Users & Memberships
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/users` | List users |
-| POST | `/api/v1/users` | Create a user |
-| GET | `/api/v1/users/{id}` | Get user details |
-| PATCH | `/api/v1/users/{id}` | Update user |
-| DELETE | `/api/v1/users/{id}` | Delete user |
-| GET | `/api/v1/users:search` | Search users |
-| GET | `/api/v1/organizations/{org_id}/users` | List organization users |
-| GET | `/api/v1/organizations/{org_id}/users:search` | Search organization users |
-| POST | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Add user to organization |
-| DELETE | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Remove user from organization |
-| PATCH | `/api/v1/memberships/organizations/{organization_id}/users/{id}` | Update membership |
-| PATCH | `/api/v1/invites/organizations/{organization_id}/users/{id}/resend` | Resend invitation |
-
-### SaaSKit — Sessions
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/users/{user_id}/sessions` | Get user sessions |
-| POST | `/api/v1/users/{user_id}/sessions:revoke_all` | Revoke all user sessions |
-| POST | `/api/v1/sessions/{session_id}:revoke` | Revoke a session |
-
-### AgentKit — Tools
-| Method | Path | Description |
-|--------|------|-------------|
-| POST | `/api/v1/execute_tool` | Execute a tool using a connected account |
-
-### SaaSKit — Organization API Clients (M2M)
-| Method | Path | Description |
-|--------|------|-------------|
-| GET | `/api/v1/organizations/{organization_id}/clients` | List org API clients |
-| POST | `/api/v1/organizations/{organization_id}/clients` | Create org API client |
-| GET | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Get org API client |
-| DELETE | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Delete org API client |
-| PATCH | `/api/v1/organizations/{organization_id}/clients/{client_id}` | Update org API client |
-
----
-
-## Error Handling
-
-### Node.js exception hierarchy
-```
-ScalekitException (base)
-├── ScalekitValidateTokenFailureException
-├── ScalekitServerException (HTTP 400-599)
-│ ├── properties: httpStatus, errorCode, message, errDetails
-│ └── Specific subclasses for 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504
-└── WebhookVerificationError
-```
-
-Import: `import { ScalekitServerException } from '@scalekit-sdk/node'`
-
-### Python exceptions
-```
-ScalekitException (base)
-```
-
-### Go errors
-All methods return `(result, error)`. Check `err != nil` for all network calls.
-
-### Java exceptions
-All methods may throw checked exceptions. Wrap in try-catch.
-
----
-
-## Common Token Claims
-
-Access tokens from Scalekit contain these standard claims:
-- `sub` — User ID
-- `email` — User email
-- `name` — Display name
-- `org_id` — Organization ID
-- `roles` — Array of role names
-- `permissions` — Array of permission strings (also available at `https://scalekit.com/permissions` or `scalekit:permissions` claim paths)
-
-Permission claims should be checked in this priority order:
-1. `permissions` claim
-2. `https://scalekit.com/permissions` claim
-3. `scalekit:permissions` claim
\ No newline at end of file
diff --git a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index aa9d09e..0624059 100644
--- a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -552,7 +552,7 @@ app.post('/logout', (req, res) => {
**Connection Selector Precedence**: connectionId > organizationId > loginHint
-**Token Expiration**: ID tokens expire in 15 minutes, access tokens in 24 hours
+**Token Expiration**: ID tokens expire in 15 minutes, access tokens in 5 minutes (configurable in dashboard)
**Admin Portal Events**: Listen for `sso.enabled`, `sso.disabled`, `session.expired`
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
new file mode 100644
index 0000000..2096a0c
--- /dev/null
+++ b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
@@ -0,0 +1,247 @@
+# Scalekit Auth — Django
+
+## Dependencies
+
+```bash
+pip install scalekit-sdk-python python-dotenv django
+```
+
+## Environment variables
+
+```env
+SCALEKIT_ENV_URL=https://your-env.scalekit.dev
+SCALEKIT_CLIENT_ID=your_client_id
+SCALEKIT_CLIENT_SECRET=your_client_secret
+SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
+```
+
+Load with `python-dotenv` or Django's built-in settings from env.
+
+## Client initialization — initialize once
+
+In `yourapp/auth_client.py`:
+
+```python
+import os
+from scalekit import ScalekitClient
+
+_sc = None
+
+def get_scalekit_client() -> ScalekitClient:
+ global _sc
+ if _sc is None:
+ _sc = ScalekitClient(
+ env_url=os.getenv("SCALEKIT_ENV_URL"),
+ client_id=os.getenv("SCALEKIT_CLIENT_ID"),
+ client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
+ )
+ return _sc
+```
+
+## Auth flow at a glance
+
+```
+GET /auth/login
+ → get_authorization_url() → 302 to Scalekit
+
+GET /auth/callback?code=...
+ → authenticate_with_code() → set session → redirect to /dashboard
+
+Middleware: ScalekitAuthMiddleware
+ → validate_access_token() → refresh if expired → pass or redirect /auth/login
+
+GET /auth/logout
+ → get_logout_url() → clear session → 302 to Scalekit end-session
+```
+
+## Views
+
+```python
+# yourapp/views.py
+import os, secrets
+from django.shortcuts import redirect
+from django.http import HttpRequest, HttpResponse
+from .auth_client import get_scalekit_client
+
+REDIRECT_URI = os.getenv("SCALEKIT_REDIRECT_URI", "http://localhost:8000/auth/callback")
+
+def login(request: HttpRequest):
+ state = secrets.token_urlsafe(32)
+ request.session["oauth_state"] = state
+ sc = get_scalekit_client()
+ auth_url = sc.get_authorization_url(REDIRECT_URI, options={"state": state})
+ return redirect(auth_url)
+
+def callback(request: HttpRequest):
+ stored_state = request.session.pop("oauth_state", None)
+ if not stored_state or stored_state != request.GET.get("state"):
+ return HttpResponse("CSRF mismatch", status=403)
+ if error := request.GET.get("error"):
+ return HttpResponse(f"Auth error: {error}", status=400)
+
+ sc = get_scalekit_client()
+ result = sc.authenticate_with_code(request.GET["code"], REDIRECT_URI)
+
+ request.session["access_token"] = result.access_token
+ request.session["refresh_token"] = result.refresh_token
+ request.session["id_token"] = result.id_token
+ request.session.cycle_key() # session fixation protection
+
+ return redirect("/dashboard")
+
+def logout(request: HttpRequest):
+ id_token = request.session.get("id_token", "")
+ sc = get_scalekit_client()
+ logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:8000"})
+ request.session.flush()
+ return redirect(logout_url)
+```
+
+## Middleware
+
+```python
+# yourapp/middleware.py
+from django.shortcuts import redirect
+from .auth_client import get_scalekit_client
+
+SKIP_PATHS = {"/auth/login", "/auth/callback", "/auth/logout"}
+
+class ScalekitAuthMiddleware:
+ def __init__(self, get_response):
+ self.get_response = get_response
+
+ def __call__(self, request):
+ if request.path in SKIP_PATHS:
+ return self.get_response(request)
+
+ access_token = request.session.get("access_token")
+ refresh_token = request.session.get("refresh_token")
+
+ if not access_token:
+ return redirect(f"/auth/login?next={request.path}")
+
+ sc = get_scalekit_client()
+ try:
+ sc.validate_access_token(access_token)
+ except Exception:
+ # Token expired — attempt silent refresh
+ if not refresh_token:
+ request.session.flush()
+ return redirect("/auth/login")
+ try:
+ refreshed = sc.refresh_access_token(refresh_token)
+ request.session["access_token"] = refreshed.access_token
+ request.session["refresh_token"] = refreshed.refresh_token
+ except Exception:
+ request.session.flush()
+ return redirect("/auth/login")
+
+ return self.get_response(request)
+```
+
+Register in `settings.py`:
+
+```python
+MIDDLEWARE = [
+ # ... Django default middleware ...
+ "yourapp.middleware.ScalekitAuthMiddleware",
+]
+```
+
+## URL configuration
+
+```python
+# yourapp/urls.py
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ path("auth/login", views.login, name="auth_login"),
+ path("auth/callback", views.callback, name="auth_callback"),
+ path("auth/logout", views.logout, name="auth_logout"),
+ path("dashboard/", views.dashboard, name="dashboard"),
+]
+```
+
+## Session storage
+
+Use database-backed sessions for production:
+
+```python
+# settings.py
+SESSION_ENGINE = "django.contrib.sessions.backends.db"
+SESSION_COOKIE_HTTPONLY = True
+SESSION_COOKIE_SECURE = True # HTTPS only
+SESSION_COOKIE_SAMESITE = "Lax"
+SESSION_COOKIE_AGE = 86400 # 24 hours
+```
+
+## Implementation checklist
+
+```
+- [ ] Step 1: pip install scalekit-sdk-python python-dotenv django
+- [ ] Step 2: Set SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET in .env
+- [ ] Step 3: Create auth_client.py with singleton ScalekitClient
+- [ ] Step 4: Implement login, callback, logout views
+- [ ] Step 5: Add ScalekitAuthMiddleware to MIDDLEWARE in settings.py
+- [ ] Step 6: Register /auth/login, /auth/callback, /auth/logout routes
+- [ ] Step 7: Configure SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SECURE=True
+- [ ] Step 8: Register callback URI in Scalekit dashboard
+- [ ] Step 9: Call session.cycle_key() after login (session fixation protection)
+- [ ] Step 10: Test: login → /dashboard → token refresh → logout
+```
+
+## Troubleshooting
+
+**`authenticate_with_code` raises exception**: The `redirect_uri` must exactly match the URI in the Scalekit dashboard — including scheme, host, and path.
+
+**Session not persisting across requests**: Ensure `django.contrib.sessions` is in `INSTALLED_APPS` and `python manage.py migrate` has been run.
+
+**CSRF errors on callback**: The `/auth/callback` GET route is not subject to Django's CSRF middleware (CSRF applies to POST). Add it to `CSRF_EXEMPT_URLS` if you hit issues.
+
+**Redirect loop in middleware**: Verify `SKIP_PATHS` includes `/auth/login`, `/auth/callback`, and `/auth/logout`. Also ensure static file paths are excluded.
+
+## Tactics
+
+### Deep link preservation
+
+```python
+# In login view
+next_url = request.GET.get("next", "/dashboard")
+if not next_url.startswith("/"):
+ next_url = "/dashboard"
+request.session["next"] = next_url
+
+# In callback view
+next_url = request.session.pop("next", "/dashboard")
+return redirect(next_url)
+```
+
+### Cache-Control: no-store on protected views
+
+```python
+from django.views.decorators.cache import never_cache
+
+@never_cache
+def dashboard(request):
+ ...
+```
+
+### IDP-initiated SSO
+
+```python
+def idp_login(request):
+ sc = get_scalekit_client()
+ claims = sc.get_idp_initiated_login_claims(request.GET.get("idp_initiated_login", ""))
+ options = {}
+ if claims.organization_id: options["organization_id"] = claims.organization_id
+ if claims.connection_id: options["connection_id"] = claims.connection_id
+ if claims.login_hint: options["login_hint"] = claims.login_hint
+ auth_url = sc.get_authorization_url(REDIRECT_URI, options=options)
+ return redirect(auth_url)
+```
+
+## Reference
+
+- Scalekit Python SDK: [docs.scalekit.com/apis](https://docs.scalekit.com/apis)
+- Django sessions: [docs.djangoproject.com/topics/http/sessions](https://docs.djangoproject.com/en/stable/topics/http/sessions/)
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
index 38b4452..bf79540 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
@@ -1,585 +1,221 @@
----
-name: implementing-scalekit-flask-auth
-description: Guides implementation of Scalekit OIDC/OAuth2 authentication and authorization in an existing Flask project. Use when the user wants to add Scalekit login, SSO, token management, session handling, or permission-based route protection to a Flask app. Triggers on: "add scalekit", "scalekit auth", "scalekit login", "scalekit SSO", "scalekit flask", "protect flask routes with scalekit".
----
+# Scalekit Auth — Flask
-# Scalekit Auth for Flask
-
-Reference implementation: [scalekit-inc/scalekit-flask-auth-example](https://github.com/scalekit-inc/scalekit-flask-auth-example)
-
-## Step 1 — Install dependencies
+## Dependencies
```bash
-pip install scalekit-sdk-python python-dotenv flask
-```
-
-Add to `requirements.txt`:
+pip install scalekit-sdk-python python-dotenv flask flask-session
```
-scalekit-sdk>=0.1.0
-python-dotenv
-flask
-```
-
----
-
-## Step 2 — Environment variables
-Create `.env` (never commit this):
+## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.com
+SCALEKIT_ENV_URL=https://your-env.scalekit.dev
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:5000/auth/callback
-FLASK_SECRET_KEY=change-me-in-production
-DEBUG=True
+SECRET_KEY=your-flask-secret-key
```
-> `offline_access` scope is included by default in the config below. It is required to receive a `refresh_token`.
-
----
-
-## Step 3 — App factory (`app.py`)
-
-Use Flask's application factory pattern. All Scalekit config goes into `app.config` so that `current_app` is available inside request contexts.
+## App setup
```python
-import os
-from flask import Flask
+# app.py
+import os, secrets
from dotenv import load_dotenv
+from flask import Flask, redirect, request, session, url_for, jsonify
+from flask_session import Session
+from scalekit import ScalekitClient
load_dotenv()
-def create_app():
- app = Flask(__name__)
-
- # Flask session config
- app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'change-me')
- app.config['SESSION_COOKIE_HTTPONLY'] = True
- app.config['SESSION_COOKIE_SECURE'] = False # Set True in production (HTTPS)
- app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
- app.config['PERMANENT_SESSION_LIFETIME'] = 3600
-
- # Scalekit config
- app.config['SCALEKIT_ENV_URL'] = os.getenv('SCALEKIT_ENV_URL', '')
- app.config['SCALEKIT_CLIENT_ID'] = os.getenv('SCALEKIT_CLIENT_ID', '')
- app.config['SCALEKIT_CLIENT_SECRET'] = os.getenv('SCALEKIT_CLIENT_SECRET', '')
- app.config['SCALEKIT_REDIRECT_URI'] = os.getenv('SCALEKIT_REDIRECT_URI', 'http://localhost:5000/auth/callback')
- app.config['SCALEKIT_SCOPES'] = 'openid profile email offline_access'
-
- # Register blueprint
- from auth_app.views import auth_bp
- app.register_blueprint(auth_bp)
+app = Flask(__name__)
+app.secret_key = os.getenv("SECRET_KEY")
+app.config["SESSION_TYPE"] = "filesystem" # or "redis", "sqlalchemy"
+app.config["SESSION_COOKIE_HTTPONLY"] = True
+app.config["SESSION_COOKIE_SECURE"] = True
+app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
+Session(app)
- # Register token refresh middleware as a before_request hook
- from auth_app.middleware import TokenRefreshMiddleware
- app.before_request(TokenRefreshMiddleware.process_request)
+REDIRECT_URI = os.getenv("SCALEKIT_REDIRECT_URI", "http://localhost:5000/auth/callback")
- return app
-
-if __name__ == '__main__':
- app = create_app()
- app.run(host='0.0.0.0', port=5000, debug=app.config['DEBUG'])
+sc = ScalekitClient(
+ env_url=os.getenv("SCALEKIT_ENV_URL"),
+ client_id=os.getenv("SCALEKIT_CLIENT_ID"),
+ client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
+)
```
----
+## Auth flow at a glance
-## Step 4 — Scalekit client wrapper (`auth_app/scalekit_client.py`)
+```
+GET /auth/login
+ → get_authorization_url() → 302 to Scalekit
-**Important**: `ScalekitClient` reads from `current_app.config`, so it must always be instantiated inside an active Flask request context (i.e., inside a view or `before_request` hook).
+GET /auth/callback?code=...
+ → authenticate_with_code() → set session → redirect to /dashboard
-```python
-import logging
-from datetime import datetime, timedelta
-from flask import current_app
-from scalekit import ScalekitClient as SDKClient
-from scalekit.common.scalekit import (
- AuthorizationUrlOptions,
- CodeAuthenticationOptions,
- TokenValidationOptions,
- LogoutUrlOptions,
-)
+@require_auth decorator
+ → validate_access_token() → refresh if expired → pass or redirect /auth/login
-logger = logging.getLogger(__name__)
-
-
-class ScalekitClient:
- def __init__(self):
- self.domain = current_app.config['SCALEKIT_ENV_URL']
- self.client_id = current_app.config['SCALEKIT_CLIENT_ID']
- self.client_secret = current_app.config['SCALEKIT_CLIENT_SECRET']
- self.redirect_uri = current_app.config['SCALEKIT_REDIRECT_URI']
- scopes = current_app.config.get('SCALEKIT_SCOPES', '')
- self.scopes = scopes.split() if scopes else ['openid', 'profile', 'email', 'offline_access']
-
- self.sdk_client = SDKClient(
- env_url=self.domain,
- client_id=self.client_id,
- client_secret=self.client_secret,
- )
-
- def get_authorization_url(self, state=None) -> str:
- options = AuthorizationUrlOptions()
- options.state = state
- options.scopes = self.scopes
- return self.sdk_client.get_authorization_url(redirect_uri=self.redirect_uri, options=options)
-
- def exchange_code_for_tokens(self, code: str) -> dict:
- options = CodeAuthenticationOptions()
- token_response = self.sdk_client.authenticate_with_code(
- code=code, redirect_uri=self.redirect_uri, options=options
- )
- token_response.setdefault('expires_in', 3600)
- return token_response
-
- def refresh_access_token(self, refresh_token: str) -> dict:
- token_response = self.sdk_client.refresh_access_token(refresh_token)
- token_response.setdefault('expires_in', 3600)
- if not token_response.get('refresh_token'):
- token_response['refresh_token'] = refresh_token
- return token_response
-
- def get_user_info(self, access_token: str) -> dict:
- options = TokenValidationOptions()
- claims = self.sdk_client.validate_access_token_and_get_claims(token=access_token, options=options)
- return claims if isinstance(claims, dict) else dict(claims)
-
- def validate_token_and_get_claims(self, access_token: str) -> dict:
- return self.get_user_info(access_token)
-
- def has_permission(self, access_token: str, permission: str) -> bool:
- try:
- claims = self.validate_token_and_get_claims(access_token)
- permissions = (
- claims.get('permissions', []) or
- claims.get('https://scalekit.com/permissions', []) or
- claims.get('scalekit:permissions', []) or
- []
- )
- return permission in permissions
- except Exception:
- return False
-
- def logout(self, access_token: str) -> str:
- try:
- options = LogoutUrlOptions()
- options.post_logout_redirect_uri = self.redirect_uri.split('/auth/callback')[0]
- return self.sdk_client.get_logout_url(options)
- except Exception:
- return f"{self.domain}/oidc/logout"
+GET /auth/logout
+ → get_logout_url() → clear session → 302 to Scalekit end-session
```
----
-
-## Step 5 — Decorators (`auth_app/decorators.py`)
-
-Flask uses decorators (not dependency injection) to protect routes.
+## Routes
```python
-from functools import wraps
-from flask import session, redirect, url_for, request, render_template
-from auth_app.scalekit_client import ScalekitClient
+@app.get("/auth/login")
+def login():
+ state = secrets.token_urlsafe(32)
+ session["oauth_state"] = state
+ auth_url = sc.get_authorization_url(REDIRECT_URI, options={"state": state})
+ return redirect(auth_url)
+@app.get("/auth/callback")
+def callback():
+ stored = session.pop("oauth_state", None)
+ if not stored or stored != request.args.get("state"):
+ return "CSRF mismatch", 403
+ if error := request.args.get("error"):
+ return f"Auth error: {error}", 400
-def login_required(f):
- """Redirect to /login if user is not authenticated."""
- @wraps(f)
- def decorated(*args, **kwargs):
- if not session.get('scalekit_user'):
- return redirect(url_for('auth.login', next=request.path))
- return f(*args, **kwargs)
- return decorated
+ result = sc.authenticate_with_code(request.args["code"], REDIRECT_URI)
+ session["access_token"] = result.access_token
+ session["refresh_token"] = result.refresh_token
+ session["id_token"] = result.id_token
+ session.modified = True
+ return redirect(session.pop("next", "/dashboard"))
-def permission_required(permission):
- """Return 403 if authenticated user lacks the specified permission."""
- def decorator(f):
- @wraps(f)
- def decorated(*args, **kwargs):
- if not session.get('scalekit_user'):
- return redirect(url_for('auth.login', next=request.path))
- token_data = session.get('scalekit_tokens', {})
- access_token = token_data.get('access_token')
- if not access_token:
- return "No access token. Please log in again.", 403
- client = ScalekitClient()
- if not client.has_permission(access_token, permission):
- return render_template('permission_denied.html',
- user=session.get('scalekit_user', {})), 403
- return f(*args, **kwargs)
- return decorated
- return decorator
+@app.get("/auth/logout")
+def logout():
+ id_token = session.get("id_token", "")
+ logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:5000"})
+ session.clear()
+ return redirect(logout_url)
```
----
-
-## Step 6 — Token refresh middleware (`auth_app/middleware.py`)
-
-Registered as a `before_request` hook. Auto-refreshes access tokens within 5 minutes of expiry. On `invalid_grant`, clears the session to force re-login.
+## Auth decorator
```python
-import logging
-from datetime import datetime, timedelta
-from flask import session, request
-from auth_app.scalekit_client import ScalekitClient
-
-logger = logging.getLogger(__name__)
-
-REFRESH_BUFFER_MINUTES = 5
-SKIP_PATHS = ['/login', '/auth/callback', '/logout', '/static/', '/sessions/refresh-token']
-
-
-class TokenRefreshMiddleware:
- @staticmethod
- def process_request():
- if not session.get('scalekit_user'):
- return None
- if any(request.path.startswith(p) for p in SKIP_PATHS):
- return None
+from functools import wraps
+from flask import g
- token_data = session.get('scalekit_tokens', {})
- expires_at_str = token_data.get('expires_at')
- refresh_token = token_data.get('refresh_token')
+def require_auth(f):
+ @wraps(f)
+ def decorated(*args, **kwargs):
+ access_token = session.get("access_token")
+ refresh_token = session.get("refresh_token")
- if not expires_at_str or not refresh_token:
- return None
+ if not access_token:
+ session["next"] = request.path
+ return redirect(url_for("login"))
try:
- expires_at = datetime.fromisoformat(expires_at_str.replace('Z', '+00:00'))
- if expires_at.tzinfo:
- expires_at = expires_at.replace(tzinfo=None)
-
- if datetime.utcnow() + timedelta(minutes=REFRESH_BUFFER_MINUTES) >= expires_at:
- client = ScalekitClient()
- token_response = client.refresh_access_token(refresh_token)
- expires_in = token_response.get('expires_in', 3600)
- session['scalekit_tokens'] = {
- 'access_token': token_response.get('access_token'),
- 'refresh_token': token_response.get('refresh_token', refresh_token),
- 'id_token': token_response.get('id_token', token_data.get('id_token')),
- 'expires_at': (datetime.utcnow() + timedelta(seconds=expires_in)).isoformat(),
- 'expires_in': expires_in,
- }
- except Exception as e:
- logger.error(f"Token refresh failed: {e}")
- if 'invalid_grant' in str(e):
- logger.warning("Refresh token revoked — clearing session")
+ sc.validate_access_token(access_token)
+ except Exception:
+ if not refresh_token:
session.clear()
-
- return None
-```
-
----
-
-## Step 7 — Auth views (`auth_app/views.py`)
-
-```python
-import secrets
-import base64
-import json
-import logging
-from datetime import datetime, timedelta
-from flask import Blueprint, render_template, redirect, url_for, request, session, jsonify
-from auth_app.scalekit_client import ScalekitClient
-from auth_app.decorators import login_required, permission_required
-
-logger = logging.getLogger(__name__)
-auth_bp = Blueprint('auth', __name__)
-
-
-@auth_bp.route('/login')
-def login():
- if session.get('scalekit_user'):
- return redirect(url_for('auth.dashboard'))
- state = secrets.token_urlsafe(32)
- session['oauth_state'] = state
- client = ScalekitClient()
- auth_url = client.get_authorization_url(state=state)
- # Render a login template that links to auth_url, or redirect directly:
- return redirect(auth_url)
-
-
-@auth_bp.route('/auth/callback')
-def callback():
- # CSRF check
- state = request.args.get('state')
- if not state or state != session.pop('oauth_state', None):
- return render_template('error.html', error='Invalid state. Enable cookies and try again.'), 400
-
- code = request.args.get('code')
- error = request.args.get('error')
- if error or not code:
- return render_template('error.html', error=f'Auth error: {error or "no code"}'), 400
-
- try:
- client = ScalekitClient()
- token_response = client.exchange_code_for_tokens(code)
-
- access_token = token_response.get('access_token')
- refresh_token = token_response.get('refresh_token')
- id_token = token_response.get('id_token')
- expires_in = token_response.get('expires_in', 3600)
-
- # Decode ID token for user profile (primary source)
- id_token_claims = {}
- if id_token:
+ return redirect(url_for("login"))
try:
- payload = id_token.split('.')[1]
- payload += '=' * (4 - len(payload) % 4)
- id_token_claims = json.loads(base64.urlsafe_b64decode(payload))
+ refreshed = sc.refresh_access_token(refresh_token)
+ session["access_token"] = refreshed.access_token
+ session["refresh_token"] = refreshed.refresh_token
except Exception:
- pass
+ session.clear()
+ return redirect(url_for("login"))
- # Get user info from access token (for roles/permissions)
- user_info = {}
- try:
- user_info = client.get_user_info(access_token)
- except Exception as e:
- logger.warning(f"Could not get user info: {e}")
-
- # Merge: access token claims first, then ID token claims override profile fields
- merged = {**user_info, **id_token_claims}
-
- session['scalekit_user'] = {
- 'sub': merged.get('sub'),
- 'email': merged.get('email'),
- 'name': merged.get('name'),
- 'given_name': merged.get('given_name'),
- 'family_name': merged.get('family_name'),
- 'preferred_username': merged.get('preferred_username'),
- 'claims': merged,
- }
- session['scalekit_tokens'] = {
- 'access_token': access_token,
- 'refresh_token': refresh_token,
- 'id_token': id_token,
- 'expires_at': (datetime.utcnow() + timedelta(seconds=expires_in)).isoformat(),
- 'expires_in': expires_in,
- }
- session['scalekit_roles'] = user_info.get('roles', []) or user_info.get('https://scalekit.com/roles', [])
- session['scalekit_permissions'] = (
- user_info.get('permissions', []) or user_info.get('https://scalekit.com/permissions', [])
- )
- session.permanent = True
-
- return redirect(url_for('auth.dashboard'))
-
- except Exception as e:
- logger.error(f"Auth error: {e}")
- return render_template('error.html', error=str(e)), 500
-
-
-@auth_bp.route('/logout', methods=['GET', 'POST'])
-@login_required
-def logout():
- token_data = session.get('scalekit_tokens', {})
- access_token = token_data.get('access_token')
- session.clear()
- if access_token:
- try:
- logout_url = ScalekitClient().logout(access_token)
- return redirect(logout_url)
- except Exception:
- pass
- return redirect(url_for('auth.home'))
+ return f(*args, **kwargs)
+ return decorated
+```
+## Protected routes
-# --- Example: protected route ---
-@auth_bp.route('/dashboard')
-@login_required
+```python
+@app.get("/dashboard")
+@require_auth
def dashboard():
- return render_template('dashboard.html', user=session.get('scalekit_user', {}))
-
-
-# --- Example: permission-gated route ---
-@auth_bp.route('/organization/settings')
-@permission_required('organization:settings')
-def organization_settings():
- return render_template('organization_settings.html', user=session.get('scalekit_user', {}))
-
-
-# --- API: manual token refresh ---
-@auth_bp.route('/sessions/refresh-token', methods=['POST'])
-@login_required
-def refresh_token():
- token_data = session.get('scalekit_tokens', {})
- rt = token_data.get('refresh_token')
- if not rt:
- return jsonify({'success': False, 'error': 'No refresh token. Request offline_access scope.'}), 400
- try:
- client = ScalekitClient()
- resp = client.refresh_access_token(rt)
- expires_in = resp.get('expires_in', 3600)
- session['scalekit_tokens'] = {
- 'access_token': resp.get('access_token'),
- 'refresh_token': resp.get('refresh_token', rt),
- 'id_token': resp.get('id_token', token_data.get('id_token')),
- 'expires_at': (datetime.utcnow() + timedelta(seconds=expires_in)).isoformat(),
- 'expires_in': expires_in,
- }
- return jsonify({'success': True, 'newAccessToken': resp.get('access_token')})
- except Exception as e:
- if 'invalid_grant' in str(e):
- session.clear()
- return jsonify({'success': False, 'error': 'Refresh token expired. Re-login required.', 'requiresReauth': True}), 401
- return jsonify({'success': False, 'error': str(e)})
+ return jsonify({"status": "authenticated"})
```
----
-
-## Key differences from FastAPI
-
-| | Flask | FastAPI |
-|---|---|---|
-| Route protection | `@login_required` decorator | `Depends(require_login)` |
-| Permission check | `@permission_required('x')` decorator | `Depends(require_permission('x'))` |
-| Middleware hook | `app.before_request(...)` | `app.add_middleware(...)` |
-| Config access | `current_app.config` (request context) | `settings` singleton (module level) |
-| Session import | `from flask import session` | `request.session` attribute |
-| Claims source | ID token + access token merged | Access token / `user` object from SDK |
-| Refresh token error | Clears session on `invalid_grant` | Logs error, lets next request retry |
-
----
-
-## Session data structure
-
-| Key | Contents |
-|---|---|
-| `scalekit_user` | `sub`, `email`, `name`, `given_name`, `family_name`, `preferred_username`, `claims` |
-| `scalekit_tokens` | `access_token`, `refresh_token`, `id_token`, `expires_at`, `expires_in` |
-| `scalekit_roles` | `["admin", ...]` |
-| `scalekit_permissions` | `["organization:settings", ...]` |
-
----
-
-## Common patterns
+## Implementation checklist
-**Read current user in any view:**
-```python
-from flask import session
-user = session.get('scalekit_user', {})
```
-
-**Check permission ad-hoc:**
-```python
-client = ScalekitClient()
-if client.has_permission(session['scalekit_tokens']['access_token'], 'reports:read'):
- ...
+- [ ] Step 1: pip install scalekit-sdk-python python-dotenv flask flask-session
+- [ ] Step 2: Set SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET, SECRET_KEY in .env
+- [ ] Step 3: Initialize ScalekitClient at module level (single instance per process)
+- [ ] Step 4: Configure Flask-Session with filesystem or Redis backend
+- [ ] Step 5: Implement /auth/login, /auth/callback, /auth/logout routes
+- [ ] Step 6: Create require_auth decorator; apply to protected routes
+- [ ] Step 7: Set SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SECURE=True, SESSION_COOKIE_SAMESITE=Lax
+- [ ] Step 8: Register callback URI in Scalekit dashboard
+- [ ] Step 9: Test: login → /dashboard → token refresh → logout
```
-**Decode JWT claims without verification:**
-```python
-import base64, json
-payload = access_token.split('.')[1]
-payload += '=' * (4 - len(payload) % 4)
-claims = json.loads(base64.urlsafe_b64decode(payload))
-```
+## Troubleshooting
+
+**`authenticate_with_code` raises exception**: The `redirect_uri` must exactly match the URI in the Scalekit dashboard — including scheme, host, path, and no trailing slash.
----
+**Session data lost between requests**: Ensure `SECRET_KEY` is set and consistent. With `SESSION_TYPE="filesystem"`, verify the session directory is writable.
-## Checklist
+**`SameSite=Lax` breaking SSO callback**: Some IdPs POST the callback. If you use POST-based SSO, set `SESSION_COOKIE_SAMESITE = "None"` with `SESSION_COOKIE_SECURE = True`.
-- [ ] `.env` populated with all 5 Scalekit env vars
-- [ ] `SCALEKIT_REDIRECT_URI` matches the URI registered in Scalekit dashboard
-- [ ] `offline_access` in `SCALEKIT_SCOPES` (required for `refresh_token`)
-- [ ] `before_request` hook registered in `create_app()` — not on the module level
-- [ ] `ScalekitClient()` instantiated only inside request contexts (views, hooks)
-- [ ] `SESSION_COOKIE_SECURE = True` in production (HTTPS only)
-- [ ] `FLASK_SECRET_KEY` is a strong random string in production
-- [ ] CSRF `state` check present in `/auth/callback`
-- [ ] `invalid_grant` handling in token refresh clears session
+**Token refresh race condition**: Multiple concurrent requests with the same refresh token can exhaust it. Use a per-user lock or treat `invalid_grant` as session expiry.
## Tactics
-### SameSite=Lax — never Strict
-`SESSION_COOKIE_SAMESITE = 'Lax'` is correct. Do not change to `'Strict'` — the OAuth callback is a cross-origin redirect from Scalekit back to `/auth/callback`. `'Strict'` drops the session cookie on that redirect, making `oauth_state` unavailable and causing the CSRF check to fail on every login.
+### Blueprint structure for larger apps
-### CORS for JavaScript clients
-If a JavaScript frontend calls the Flask backend:
+```python
+# auth/routes.py
+from flask import Blueprint
+auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
-```bash
-pip install flask-cors
-```
+@auth_bp.get("/login")
+def login(): ...
-```python
-from flask_cors import CORS
-
-def create_app():
- app = Flask(__name__)
- CORS(app,
- origins=["http://localhost:3000"], # explicit origin required
- supports_credentials=True) # required for session cookies
- ...
+# app.py
+from auth.routes import auth_bp
+app.register_blueprint(auth_bp)
```
-> ⚠️ `origins="*"` does not work with `supports_credentials=True`. Always specify explicit origins.
-
-### Deep link preservation
+### IDP-initiated SSO
```python
-@auth_bp.route('/login')
-def login():
- next_url = request.args.get('next', url_for('auth.dashboard'))
- state = secrets.token_urlsafe(32)
- session['oauth_state'] = state
- session['next'] = next_url # preserve intended URL
- ...
-
-@auth_bp.route('/auth/callback')
-def callback():
- ...
- next_url = session.pop('next', url_for('auth.dashboard'))
- if not next_url.startswith('/'): # prevent open redirect
- next_url = url_for('auth.dashboard')
- return redirect(next_url)
+@app.get("/auth/idp-login")
+def idp_login():
+ claims = sc.get_idp_initiated_login_claims(request.args.get("idp_initiated_login", ""))
+ options = {}
+ if claims.organization_id: options["organization_id"] = claims.organization_id
+ if claims.connection_id: options["connection_id"] = claims.connection_id
+ if claims.login_hint: options["login_hint"] = claims.login_hint
+ return redirect(sc.get_authorization_url(REDIRECT_URI, options=options))
```
-The `@login_required` decorator passes `?next=` automatically — read it in `login()`.
-
### Cache-Control: no-store on protected responses
```python
from flask import make_response
-@auth_bp.route('/dashboard')
-@login_required
+@app.get("/dashboard")
+@require_auth
def dashboard():
- resp = make_response(render_template('dashboard.html', user=session.get('scalekit_user', {})))
- resp.headers['Cache-Control'] = 'no-store'
+ resp = make_response(jsonify({"status": "authenticated"}))
+ resp.headers["Cache-Control"] = "no-store"
return resp
```
-Prevents the browser from serving a cached authenticated page after logout via the back button.
-
-### AJAX: 401 instead of redirect
-Update `@login_required` to return `401` for JSON requests:
+### Redis session backend (production)
```python
-def login_required(f):
- @wraps(f)
- def decorated(*args, **kwargs):
- if not session.get('scalekit_user'):
- if request.headers.get('Accept') == 'application/json':
- return jsonify({'error': 'Authentication required'}), 401
- return redirect(url_for('auth.login', next=request.path))
- return f(*args, **kwargs)
- return decorated
+app.config["SESSION_TYPE"] = "redis"
+app.config["SESSION_REDIS"] = redis.from_url(os.getenv("REDIS_URL"))
+app.config["SESSION_USE_SIGNER"] = True
+app.config["SESSION_KEY_PREFIX"] = "sk_session:"
+app.config["PERMANENT_SESSION_LIFETIME"] = 86400
```
-### Session fixation after login
-Flask does not regenerate the session ID automatically. Call `session.modified = True` and use `flask.session` with a new session cookie after login. For a stronger fix, clear and re-create the session immediately after writing user data in `callback()`:
-
-```python
-# After storing user/token data, regenerate session to prevent fixation:
-user_data = session.get('scalekit_user')
-token_data = session.get('scalekit_tokens')
-session.clear()
-session['scalekit_user'] = user_data
-session['scalekit_tokens'] = token_data
-session.permanent = True
-```
+## Reference
-### Production: Secure cookie flag
-```python
-app.config['SESSION_COOKIE_SECURE'] = not app.debug # True in production (HTTPS)
-```
+- Scalekit Python SDK: [docs.scalekit.com/apis](https://docs.scalekit.com/apis)
+- Flask-Session: [flask-session.readthedocs.io](https://flask-session.readthedocs.io/)
From 23570af1f34917b5d6111553bd2d18f647d2943f Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Thu, 21 May 2026 22:34:36 +0530
Subject: [PATCH 31/39] feat: add setup/onboarding skill to agentkit and
saaskit
Co-Authored-By: Claude Sonnet 4.6
---
plugins/agentkit/README.md | 2 +
plugins/agentkit/skills/setup/SKILL.md | 73 +++++++++++++++++++++++++
plugins/saaskit/README.md | 2 +
plugins/saaskit/skills/setup/SKILL.md | 74 ++++++++++++++++++++++++++
4 files changed, 151 insertions(+)
create mode 100644 plugins/agentkit/skills/setup/SKILL.md
create mode 100644 plugins/saaskit/skills/setup/SKILL.md
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
index e8a8e63..70558c5 100644
--- a/plugins/agentkit/README.md
+++ b/plugins/agentkit/README.md
@@ -6,6 +6,8 @@ AgentKit handles the full OAuth lifecycle — authorization, token vault, and au
## Skills
+- `/agentkit:setup`
+ New to AgentKit? Start here — answers 2 questions and routes you to the right skill.
- `integrating-agentkit` — Core integration: SDK setup, connected accounts, OAuth flows, token fetching, downstream API calls, and agent framework examples.
- `discovering-connector-tools` — Uses live AgentKit metadata to find tools, inspect schemas, and narrow the tool set.
- `exposing-agentkit-via-mcp` — Exposes AgentKit tools through MCP for MCP-compatible runtimes.
diff --git a/plugins/agentkit/skills/setup/SKILL.md b/plugins/agentkit/skills/setup/SKILL.md
new file mode 100644
index 0000000..3e8ec1f
--- /dev/null
+++ b/plugins/agentkit/skills/setup/SKILL.md
@@ -0,0 +1,73 @@
+---
+name: setup
+description: Starting point for any Scalekit AgentKit integration. Use when the user says "I want to add agent auth", "set up AgentKit", "where do I start", or is new to AgentKit and doesn't know which skill to use. Routes to the right skill based on what they're building.
+---
+
+# AgentKit — Where to Start
+
+Answer 2 questions, then follow the link for your exact skill.
+
+---
+
+## Step 1: Ask the user these questions
+
+If answers aren't already clear from context, ask:
+
+1. **What are you building?**
+ - New agent that needs to call third-party tools on behalf of users (Gmail, Slack, Salesforce, etc.)
+ - Existing agent — adding connector access or fixing auth
+ - MCP server that exposes AgentKit tools
+
+2. **What's your current state?**
+ - Starting from scratch
+ - Have a Scalekit account and environment already
+ - Have AgentKit set up, stuck on a specific step
+
+---
+
+## Step 2: Route to the right skill
+
+| What you're building | Skill |
+|---|---|
+| Connect users to third-party apps, execute tools on their behalf | `/agentkit:integrating-agentkit` |
+| Discover available tools for a connector, inspect schemas | `/agentkit:discovering-connector-tools` |
+| Expose AgentKit tools over MCP for Claude Desktop, Cursor, VS Code | `/agentkit:exposing-agentkit-via-mcp` |
+| Pre-launch checklist for production | `/agentkit:production-readiness-agentkit` |
+| SDK errors, wrong imports, broken auth calls | `/saaskit:scalekit-code-doctor` |
+
+---
+
+## Step 3: Environment setup (if new project)
+
+Before starting any skill, verify credentials exist:
+
+```bash
+SCALEKIT_ENV_URL=https://your-env.scalekit.dev
+SCALEKIT_CLIENT_ID=
+SCALEKIT_CLIENT_SECRET=
+```
+
+Get these from [app.scalekit.com](https://app.scalekit.com) → Developers → Settings → API Credentials.
+
+The Scalekit MCP server (`https://mcp.scalekit.com`) is pre-configured in `.mcp.json`. Claude Code handles OAuth 2.1 auth automatically — no additional setup needed.
+
+---
+
+## Core AgentKit concepts (30-second orientation)
+
+| Concept | What it is |
+|---|---|
+| **Connector** | A third-party app (Gmail, Slack, Salesforce, GitHub, etc.) |
+| **Connection** | Your app's agreement with a connector (configured in dashboard) |
+| **Connected account** | A specific user's authorization to use a connection |
+| **Tool** | An action the agent can take (send email, create issue, etc.) |
+
+Flow: User authorizes → connected account created → agent discovers tools → agent executes tool calls using that account.
+
+---
+
+## When to switch skills
+
+- **Already know what you need?** Skip this skill and invoke the target directly.
+- **SDK errors?** Use `/saaskit:scalekit-code-doctor`.
+- **Want to add B2B auth (login, SSO, SCIM) to your app?** Switch to the `saaskit` plugin: `/saaskit:setup`.
diff --git a/plugins/saaskit/README.md b/plugins/saaskit/README.md
index c4d20ef..8aaf2dd 100644
--- a/plugins/saaskit/README.md
+++ b/plugins/saaskit/README.md
@@ -4,6 +4,8 @@ Production-ready auth for B2B SaaS apps. This plugin brings Scalekit SaaSKit int
## Skills
+- `/saaskit:setup`
+ New to SaaSKit? Start here — answers 3 questions and routes you to the right skill.
- `implementing-saaskit` — Core auth flow: login, signup, callback, token exchange, session management, logout. Framework references for Go, Spring Boot, Laravel.
- `implementing-saaskit-nextjs` — Auth for Next.js App Router.
- `implementing-saaskit-python` — Auth for Django, FastAPI, or Flask. Framework references included.
diff --git a/plugins/saaskit/skills/setup/SKILL.md b/plugins/saaskit/skills/setup/SKILL.md
new file mode 100644
index 0000000..a8af32f
--- /dev/null
+++ b/plugins/saaskit/skills/setup/SKILL.md
@@ -0,0 +1,74 @@
+---
+name: setup
+description: Starting point for any Scalekit SaaSKit integration. Use when the user says "I want to add auth", "set up Scalekit", "where do I start", or is new to SaaSKit and doesn't know which skill to use. Routes to the right skill based on framework and what they're building.
+---
+
+# SaaSKit — Where to Start
+
+Answer 3 questions, then follow the link for your exact skill.
+
+---
+
+## Step 1: Ask the user these questions
+
+If answers aren't already clear from context, ask:
+
+1. **New or existing codebase?**
+ - New project
+ - Adding auth to an existing app
+
+2. **Framework?**
+ - Next.js (App Router or Pages Router)
+ - Python (Django / FastAPI / Flask)
+ - Go
+ - Other / not sure
+
+3. **What are you adding?**
+ - Login, sessions, and user management (most common starting point)
+ - Enterprise SSO (Okta, Azure AD, Google Workspace, etc.)
+ - SCIM / user provisioning (sync users from a directory)
+ - Secure an MCP server with OAuth 2.1
+ - API keys for developers
+ - Not sure / full auth stack
+
+---
+
+## Step 2: Route to the right skill
+
+| Framework | What you're adding | Skill |
+|---|---|---|
+| Next.js | Login + sessions | `/saaskit:implementing-saaskit-nextjs` |
+| Python | Login + sessions | `/saaskit:implementing-saaskit-python` |
+| Go / other | Login + sessions | `/saaskit:implementing-saaskit` |
+| Any | Enterprise SSO | `/saaskit:implementing-modular-sso` |
+| Any | SCIM provisioning | `/saaskit:implementing-scim-provisioning` |
+| Any | MCP server auth | `/saaskit:adding-mcp-oauth` |
+| Any | API keys | `/saaskit:adding-api-auth` |
+| Any | RBAC / permissions | `/saaskit:implementing-access-control` |
+| Any | Migrating from Auth0 / Firebase / custom auth | `/saaskit:migrating-to-saaskit` |
+
+If the user wants **login + SSO + SCIM** (full B2B auth stack), start with `/saaskit:implementing-saaskit` or the framework-specific variant, then chain to `/saaskit:implementing-modular-sso` once login is working.
+
+---
+
+## Step 3: Environment setup (if new project)
+
+Before starting any skill, verify credentials exist:
+
+```bash
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
+SCALEKIT_CLIENT_ID=
+SCALEKIT_CLIENT_SECRET=
+```
+
+Get these from [app.scalekit.com](https://app.scalekit.com) → Developers → Settings → API Credentials.
+
+Use `/saaskit:testing-auth-setup` to validate credentials and connection end-to-end before writing any auth code.
+
+---
+
+## When to switch skills
+
+- **Already know what you need?** Skip this skill and invoke the target directly.
+- **SDK errors or wrong imports?** Use `/saaskit:scalekit-code-doctor`.
+- **Production checklist?** Use `/saaskit:production-readiness-saaskit`.
From 5ebf8a416e4d547829b3d37ee704b3dd9e1f8955 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Thu, 21 May 2026 22:45:34 +0530
Subject: [PATCH 32/39] fix: wrong Python SDK methods and stale .io domain
Co-Authored-By: Claude Sonnet 4.6
---
plugins/saaskit/skills/adding-mcp-oauth/SKILL.md | 2 +-
plugins/saaskit/skills/implementing-access-control/SKILL.md | 6 +++---
plugins/saaskit/skills/implementing-modular-sso/SKILL.md | 4 ++--
plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md | 2 +-
.../skills/implementing-saaskit/laravel-reference.md | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
index af7f029..8236bcf 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
@@ -204,7 +204,7 @@ async def auth_middleware(request: Request, call_next):
issuer=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
audience=[RESOURCE_ID]
)
- scalekit_client.validate_token(token, options=options)
+ scalekit_client.validate_access_token_and_get_claims(token, options=options)
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
diff --git a/plugins/saaskit/skills/implementing-access-control/SKILL.md b/plugins/saaskit/skills/implementing-access-control/SKILL.md
index 3b0c835..14fdc2b 100644
--- a/plugins/saaskit/skills/implementing-access-control/SKILL.md
+++ b/plugins/saaskit/skills/implementing-access-control/SKILL.md
@@ -68,10 +68,10 @@ def validate_and_extract_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
access_token = decrypt(request.cookies.get("accessToken"))
- if not scalekit_client.validate_access_token(access_token):
+ try:
+ token_data = scalekit_client.validate_access_token_and_get_claims(access_token)
+ except Exception:
return jsonify({"error": "Invalid or expired token"}), 401
-
- token_data = scalekit_client.decode_access_token(access_token)
request.user = {
"id": token_data.get("sub"),
"organization_id": token_data.get("oid"),
diff --git a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index 0624059..6f1b49a 100644
--- a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -306,8 +306,8 @@ const accessTokenClaims = await scalekit.validateToken(result.accessToken);
**Python:**
```python
-id_token_claims = scalekit.validate_token(result['id_token'])
-access_token_claims = scalekit.validate_token(result['access_token'])
+id_token_claims = scalekit.validate_access_token_and_get_claims(result['id_token'])
+access_token_claims = scalekit.validate_access_token_and_get_claims(result['access_token'])
```
### Token Structure
diff --git a/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
index de49b3e..e231806 100644
--- a/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
@@ -26,7 +26,7 @@ lib/
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.io
+SCALEKIT_ENV_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your-client-id
SCALEKIT_CLIENT_SECRET=your-client-secret
SCALEKIT_REDIRECT_URI=http://localhost:3000/auth/callback
diff --git a/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md b/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
index 05bb2fe..dc74b53 100644
--- a/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
@@ -31,7 +31,7 @@ routes/
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.io
+SCALEKIT_ENV_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your-client-id
SCALEKIT_CLIENT_SECRET=your-client-secret
SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
From e67b845de6cb21d9acfd6923082b5357ab5931ba Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 11:28:41 +0530
Subject: [PATCH 33/39] fix: native HTTP MCP, wrong SDK methods, and
platform-specific refs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- .mcp.json: replace mcp-remote with native HTTP MCP (type: http)
- session-management: scalekit.auth.* → scalekit.validateAccessToken/refreshAccessToken
- fastapi-reference: scalekit-sdk → scalekit-sdk-python, validate_access_token → validate_access_token_and_get_claims
- Setup skill: Claude Code → Codex platform reference
- Env var: SCALEKIT_ENV_URL → SCALEKIT_ENVIRONMENT_URL
---
plugins/agentkit/.mcp.json | 4 ++--
plugins/agentkit/skills/setup/SKILL.md | 4 ++--
plugins/saaskit/.mcp.json | 4 ++--
plugins/saaskit/references/session-management-patterns.md | 6 +++---
.../skills/implementing-saaskit-python/fastapi-reference.md | 4 ++--
5 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/plugins/agentkit/.mcp.json b/plugins/agentkit/.mcp.json
index 36dbbf4..97dc405 100644
--- a/plugins/agentkit/.mcp.json
+++ b/plugins/agentkit/.mcp.json
@@ -1,8 +1,8 @@
{
"mcpServers": {
"scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
+ "type": "http",
+ "url": "https://mcp.scalekit.com/"
}
}
}
diff --git a/plugins/agentkit/skills/setup/SKILL.md b/plugins/agentkit/skills/setup/SKILL.md
index 3e8ec1f..546afe2 100644
--- a/plugins/agentkit/skills/setup/SKILL.md
+++ b/plugins/agentkit/skills/setup/SKILL.md
@@ -42,14 +42,14 @@ If answers aren't already clear from context, ask:
Before starting any skill, verify credentials exist:
```bash
-SCALEKIT_ENV_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=
SCALEKIT_CLIENT_SECRET=
```
Get these from [app.scalekit.com](https://app.scalekit.com) → Developers → Settings → API Credentials.
-The Scalekit MCP server (`https://mcp.scalekit.com`) is pre-configured in `.mcp.json`. Claude Code handles OAuth 2.1 auth automatically — no additional setup needed.
+The Scalekit MCP server (`https://mcp.scalekit.com`) is pre-configured in `.mcp.json`. Codex handles OAuth 2.1 auth automatically — sign in with `codex mcp login scalekit` if prompted.
---
diff --git a/plugins/saaskit/.mcp.json b/plugins/saaskit/.mcp.json
index 36dbbf4..97dc405 100644
--- a/plugins/saaskit/.mcp.json
+++ b/plugins/saaskit/.mcp.json
@@ -1,8 +1,8 @@
{
"mcpServers": {
"scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com"]
+ "type": "http",
+ "url": "https://mcp.scalekit.com/"
}
}
}
diff --git a/plugins/saaskit/references/session-management-patterns.md b/plugins/saaskit/references/session-management-patterns.md
index 6421c8a..3c8d03d 100644
--- a/plugins/saaskit/references/session-management-patterns.md
+++ b/plugins/saaskit/references/session-management-patterns.md
@@ -123,7 +123,7 @@ async function scalekitSessionMiddleware(req, res, next) {
if (!accessToken) return res.redirect('/login');
try {
- const payload = await scalekit.auth.validateAccessToken(accessToken);
+ const payload = await scalekit.validateAccessToken(accessToken);
req.user = payload;
return next();
} catch (err) {
@@ -139,10 +139,10 @@ async function handleTokenRefresh(req, res, next) {
if (!refreshToken) return res.redirect('/login');
try {
- const newTokens = await scalekit.auth.refreshTokens(refreshToken);
+ const newTokens = await scalekit.refreshAccessToken(refreshToken);
res.cookie('access_token', newTokens.access_token, { /* same options */ });
res.cookie('refresh_token', newTokens.refresh_token, { /* same options */ });
- req.user = await scalekit.auth.validateAccessToken(newTokens.access_token);
+ req.user = await scalekit.validateAccessToken(newTokens.access_token);
return next();
} catch (err) {
res.clearCookie('access_token');
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
index c317faf..e78194c 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
@@ -15,7 +15,7 @@ pip install scalekit-sdk-python python-dotenv pydantic-settings starlette
Add to `requirements.txt`:
```
-scalekit-sdk>=0.1.0
+scalekit-sdk-python>=2.4.0
python-dotenv
pydantic-settings
starlette
@@ -101,7 +101,7 @@ class ScalekitClientWrapper:
return self._client.get_user_info(access_token)
def validate_token_and_get_claims(self, access_token: str) -> dict:
- return self._client.validate_access_token(access_token)
+ return self._client.validate_access_token_and_get_claims(access_token)
def refresh_access_token(self, refresh_token: str) -> dict:
return self._client.refresh_token(refresh_token)
From b4900faee15e621b4129e941fd84c4c24d9305a4 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 11:36:21 +0530
Subject: [PATCH 34/39] fix: .md URL suffixes, env var canonicalization, module
shadowing, Go/Java SDK refs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Strip .md suffix from docs.scalekit.com URLs
- SCALEKIT_ENV_URL → SCALEKIT_ENVIRONMENT_URL (50 remaining instances)
- Fix Python module shadowing in agentkit skills
- Fix Go SDK path to scalekit-inc/scalekit-sdk-go/v2
- Fix Java artifact to com.scalekit:scalekit-sdk-java
- Fix plugin.json homepage and websiteURL
---
plugins/agentkit/.codex-plugin/plugin.json | 4 ++--
plugins/agentkit/README.md | 6 +++---
plugins/agentkit/references/code-samples.md | 20 +++++++++----------
.../discovering-connector-tools/SKILL.md | 4 ++--
.../skills/exposing-agentkit-via-mcp/SKILL.md | 8 ++++----
.../skills/integrating-agentkit/SKILL.md | 13 ++++++------
.../production-readiness-agentkit/SKILL.md | 4 ++--
.../saaskit/references/scalekit-mcp-server.md | 4 ++--
plugins/saaskit/references/setup-scalekit.md | 5 +++--
.../implementing-saaskit-nextjs/SKILL.md | 2 +-
.../implementing-saaskit-python/SKILL.md | 4 ++--
.../django-reference.md | 6 +++---
.../fastapi-reference.md | 4 ++--
.../flask-reference.md | 6 +++---
.../implementing-saaskit/laravel-reference.md | 2 +-
.../springboot-reference.md | 2 +-
.../implementing-scim-provisioning/SKILL.md | 4 ++--
.../skills/migrating-to-saaskit/SKILL.md | 4 ++--
.../production-readiness-saaskit/SKILL.md | 6 +++---
.../skills/scalekit-code-doctor/SKILL.md | 8 ++++----
.../references/COMMON-MISTAKES.md | 12 +++++------
.../references/REFERENCE.md | 14 ++++++-------
.../skills/testing-auth-setup/SKILL.md | 6 +++---
23 files changed, 74 insertions(+), 74 deletions(-)
diff --git a/plugins/agentkit/.codex-plugin/plugin.json b/plugins/agentkit/.codex-plugin/plugin.json
index 5c612f7..ee3fc1d 100644
--- a/plugins/agentkit/.codex-plugin/plugin.json
+++ b/plugins/agentkit/.codex-plugin/plugin.json
@@ -7,7 +7,7 @@
"email": "support@scalekit.com",
"url": "https://scalekit.com"
},
- "homepage": "https://docs.scalekit.com/agentkit/overview.md",
+ "homepage": "https://docs.scalekit.com/agentkit/overview",
"repository": "https://github.com/scalekit-inc/codex-authstack",
"license": "MIT",
"keywords": ["scalekit", "agentkit", "agent-auth", "oauth", "connectors", "tool-calling"],
@@ -21,7 +21,7 @@
"developerName": "Scalekit Inc.",
"category": "Agent Auth",
"capabilities": ["Interactive", "Write"],
- "websiteURL": "https://docs.scalekit.com/agentkit/overview.md",
+ "websiteURL": "https://docs.scalekit.com/agentkit/overview",
"privacyPolicyURL": "https://www.scalekit.com/privacy",
"termsOfServiceURL": "https://www.scalekit.com/terms",
"defaultPrompt": [
diff --git a/plugins/agentkit/README.md b/plugins/agentkit/README.md
index 70558c5..620bcb4 100644
--- a/plugins/agentkit/README.md
+++ b/plugins/agentkit/README.md
@@ -19,12 +19,12 @@ AgentKit handles the full OAuth lifecycle — authorization, token vault, and au
Required environment variables:
-- `SCALEKIT_ENV_URL`
+- `SCALEKIT_ENVIRONMENT_URL`
- `SCALEKIT_CLIENT_ID`
- `SCALEKIT_CLIENT_SECRET`
## Links
-- [AgentKit overview](https://docs.scalekit.com/agentkit/overview.md)
-- [AgentKit quickstart](https://docs.scalekit.com/agentkit/quickstart.md)
+- [AgentKit overview](https://docs.scalekit.com/agentkit/overview)
+- [AgentKit quickstart](https://docs.scalekit.com/agentkit/quickstart)
- [LLM docs map](https://docs.scalekit.com/llms.txt)
diff --git a/plugins/agentkit/references/code-samples.md b/plugins/agentkit/references/code-samples.md
index 81361aa..db692c7 100644
--- a/plugins/agentkit/references/code-samples.md
+++ b/plugins/agentkit/references/code-samples.md
@@ -36,7 +36,7 @@ Choose the right sample based on your needs:
OPENAI_API_KEY=your_openai_api_key_here
SCALEKIT_CLIENT_ID=your_scalekit_client_id
SCALEKIT_CLIENT_SECRET=your_scalekit_client_secret
-SCALEKIT_ENV_URL=your_scalekit_environment_url
+SCALEKIT_ENVIRONMENT_URL=your_scalekit_environment_url
```
**Installation:**
@@ -50,17 +50,17 @@ python main.py
**1. SDK Initialization**
```python
import os
-import scalekit.client
+from scalekit import ScalekitClient
from dotenv import load_dotenv
load_dotenv()
-scalekit = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
-actions = scalekit.actions
+actions = sk_client.actions
```
**2. OAuth Authorization Flow**
@@ -143,7 +143,7 @@ GOOGLE_GENAI_USE_VERTEXAI=FALSE
GOOGLE_API_KEY=your_google_api_key_here
SCALEKIT_CLIENT_ID=your_scalekit_client_id
SCALEKIT_CLIENT_SECRET=your_scalekit_client_secret
-SCALEKIT_ENV_URL=your_scalekit_environment_url
+SCALEKIT_ENVIRONMENT_URL=your_scalekit_environment_url
```
**Installation:**
@@ -167,7 +167,7 @@ connection_name = "gmail"
client = scalekit.client.ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL")
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL")
)
# Generate OAuth authorization link
@@ -498,10 +498,10 @@ from dotenv import load_dotenv
load_dotenv()
-scalekit = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
```
@@ -532,6 +532,6 @@ scalekit = scalekit.client.ScalekitClient(
### Troubleshooting
1. **Connection not ACTIVE:** Check OAuth flow completed in browser
2. **Token expired:** Scalekit auto-refreshes tokens; call `get_connected_account` before tool calls
-3. **Invalid credentials:** Verify `SCALEKIT_ENV_URL`, `SCALEKIT_CLIENT_ID`, and `SCALEKIT_CLIENT_SECRET`
+3. **Invalid credentials:** Verify `SCALEKIT_ENVIRONMENT_URL`, `SCALEKIT_CLIENT_ID`, and `SCALEKIT_CLIENT_SECRET`
4. **Tool not found:** Verify connection name matches Scalekit Dashboard exactly
5. **Scope errors:** Check connection configuration has required scopes in Scalekit Dashboard
diff --git a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
index bbba82c..5523882 100644
--- a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
+++ b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
@@ -32,7 +32,7 @@ load_dotenv()
client = scalekit.client.ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
# List all tools for a provider
@@ -54,7 +54,7 @@ import { ScalekitClient } from '@scalekit-sdk/node';
import 'dotenv/config';
const client = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
);
diff --git a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
index 36e0a20..59f7c46 100644
--- a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
+++ b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
@@ -18,7 +18,7 @@ Scalekit lets you configure MCP endpoints that manage authentication, create per
## Prerequisites
-- [ ] **Scalekit credentials**: [app.scalekit.com](https://app.scalekit.com) → Settings → Copy `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`, `SCALEKIT_ENV_URL`
+- [ ] **Scalekit credentials**: [app.scalekit.com](https://app.scalekit.com) → Settings → Copy `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`, `SCALEKIT_ENVIRONMENT_URL`
- [ ] **OpenAI API key**: `OPENAI_API_KEY`
> **Gmail is the only connector that does not require dashboard setup.** All other connectors (including Google Calendar) must be created in the Scalekit Dashboard before use:
@@ -62,12 +62,12 @@ Initialize the Scalekit client:
```python
load_dotenv()
-scalekit = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
-my_mcp = scalekit.actions.mcp
+my_mcp = sk_client.actions.mcp
```
## Step 2 — Create an MCP config and server instance
diff --git a/plugins/agentkit/skills/integrating-agentkit/SKILL.md b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
index a7c907f..bc44ca8 100644
--- a/plugins/agentkit/skills/integrating-agentkit/SKILL.md
+++ b/plugins/agentkit/skills/integrating-agentkit/SKILL.md
@@ -7,7 +7,7 @@ description: Integrates Scalekit AgentKit into a project so an agent can create
Scalekit handles the full OAuth lifecycle — authorization, token storage, and refresh — so agents can act on behalf of users in Gmail, Slack, Notion, Calendar, and other connectors.
-**Required env vars**: `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`, `SCALEKIT_ENV_URL`
+**Required env vars**: `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`, `SCALEKIT_ENVIRONMENT_URL`
→ Get from [app.scalekit.com](https://app.scalekit.com): Developers → Settings → API Credentials
## Setup
@@ -25,16 +25,17 @@ Install the SDK and initialize the client:
pip install scalekit-sdk-python
```
```python
-import scalekit.client, os
+from scalekit import ScalekitClient
+import os
from dotenv import load_dotenv
load_dotenv()
-scalekit = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
-actions = scalekit.actions
+actions = sk_client.actions
```
**Node.js**
@@ -46,7 +47,7 @@ import { ScalekitClient } from '@scalekit-sdk/node';
import 'dotenv/config';
const scalekitClient = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
);
diff --git a/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
index fd3625f..d28d40d 100644
--- a/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
+++ b/plugins/agentkit/skills/production-readiness-agentkit/SKILL.md
@@ -13,12 +13,12 @@ Work through each section in order — earlier sections are blockers for later o
```bash
# Confirm production credentials are set (not dev/staging)
-echo $SCALEKIT_ENV_URL # should be https://.scalekit.com (not .scalekit.dev)
+echo $SCALEKIT_ENVIRONMENT_URL # should be https://.scalekit.com (not .scalekit.dev)
echo $SCALEKIT_CLIENT_ID # should be set
echo $SCALEKIT_CLIENT_SECRET # should be set
# Verify token endpoint works
-curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
-d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
# Expected: 200
```
diff --git a/plugins/saaskit/references/scalekit-mcp-server.md b/plugins/saaskit/references/scalekit-mcp-server.md
index e950b57..4ee78c9 100644
--- a/plugins/saaskit/references/scalekit-mcp-server.md
+++ b/plugins/saaskit/references/scalekit-mcp-server.md
@@ -257,7 +257,7 @@ server.tool(
```bash
# Scalekit Configuration
-SCALEKIT_ENV_URL=https://your-env.scalekit.com
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
@@ -276,7 +276,7 @@ NODE_ENV=production
```typescript
const config = {
port: parseInt(process.env.PORT || '3002', 10),
- environmentUrl: process.env.SCALEKIT_ENV_URL,
+ environmentUrl: process.env.SCALEKIT_ENVIRONMENT_URL,
clientId: process.env.SCALEKIT_CLIENT_ID,
clientSecret: process.env.SCALEKIT_CLIENT_SECRET,
expectedAudience: process.env.EXPECTED_AUDIENCE,
diff --git a/plugins/saaskit/references/setup-scalekit.md b/plugins/saaskit/references/setup-scalekit.md
index a81f2db..1712744 100644
--- a/plugins/saaskit/references/setup-scalekit.md
+++ b/plugins/saaskit/references/setup-scalekit.md
@@ -49,11 +49,12 @@ npm i -g @scalekit-inc/cli
**Python**
```python
-import scalekit.client, os
+from scalekit import ScalekitClient
+import os
from dotenv import load_dotenv
load_dotenv()
-scalekit = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
diff --git a/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
index e231806..5a3b241 100644
--- a/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-nextjs/SKILL.md
@@ -26,7 +26,7 @@ lib/
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.com
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your-client-id
SCALEKIT_CLIENT_SECRET=your-client-secret
SCALEKIT_REDIRECT_URI=http://localhost:3000/auth/callback
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index f071ce2..c5589ef 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -30,7 +30,7 @@ from scalekit import ScalekitClient
load_dotenv()
sc = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
@@ -61,7 +61,7 @@ app = FastAPI()
REDIRECT_URI = os.getenv("SCALEKIT_REDIRECT_URI", "http://localhost:8000/auth/callback")
sc = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
index 2096a0c..b3e11cb 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
@@ -9,7 +9,7 @@ pip install scalekit-sdk-python python-dotenv django
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
@@ -31,7 +31,7 @@ def get_scalekit_client() -> ScalekitClient:
global _sc
if _sc is None:
_sc = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
@@ -180,7 +180,7 @@ SESSION_COOKIE_AGE = 86400 # 24 hours
```
- [ ] Step 1: pip install scalekit-sdk-python python-dotenv django
-- [ ] Step 2: Set SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET in .env
+- [ ] Step 2: Set SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET in .env
- [ ] Step 3: Create auth_client.py with singleton ScalekitClient
- [ ] Step 4: Implement login, callback, logout views
- [ ] Step 5: Add ScalekitAuthMiddleware to MIDDLEWARE in settings.py
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
index e78194c..3f80b28 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
@@ -28,7 +28,7 @@ starlette
Create `.env` (never commit this):
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.com
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
@@ -52,7 +52,7 @@ from dotenv import load_dotenv
load_dotenv()
class Settings(BaseSettings):
- scalekit_env_url: str = os.getenv('SCALEKIT_ENV_URL', '')
+ scalekit_env_url: str = os.getenv('SCALEKIT_ENVIRONMENT_URL', '')
scalekit_client_id: str = os.getenv('SCALEKIT_CLIENT_ID', '')
scalekit_client_secret: str = os.getenv('SCALEKIT_CLIENT_SECRET', '')
scalekit_redirect_uri: str = os.getenv('SCALEKIT_REDIRECT_URI', 'http://localhost:8000/auth/callback')
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
index bf79540..1b1ed73 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
@@ -9,7 +9,7 @@ pip install scalekit-sdk-python python-dotenv flask flask-session
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:5000/auth/callback
@@ -39,7 +39,7 @@ Session(app)
REDIRECT_URI = os.getenv("SCALEKIT_REDIRECT_URI", "http://localhost:5000/auth/callback")
sc = ScalekitClient(
- env_url=os.getenv("SCALEKIT_ENV_URL"),
+ env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
)
@@ -142,7 +142,7 @@ def dashboard():
```
- [ ] Step 1: pip install scalekit-sdk-python python-dotenv flask flask-session
-- [ ] Step 2: Set SCALEKIT_ENV_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET, SECRET_KEY in .env
+- [ ] Step 2: Set SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET, SECRET_KEY in .env
- [ ] Step 3: Initialize ScalekitClient at module level (single instance per process)
- [ ] Step 4: Configure Flask-Session with filesystem or Redis backend
- [ ] Step 5: Implement /auth/login, /auth/callback, /auth/logout routes
diff --git a/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md b/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
index dc74b53..cfec2e9 100644
--- a/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit/laravel-reference.md
@@ -31,7 +31,7 @@ routes/
## Environment variables
```env
-SCALEKIT_ENV_URL=https://your-env.scalekit.com
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your-client-id
SCALEKIT_CLIENT_SECRET=your-client-secret
SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
diff --git a/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md b/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
index fb6b34a..07110e9 100644
--- a/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
@@ -35,7 +35,7 @@ Add to `pom.xml` (Spring Boot 3.2+, Java 17+):
```yaml
scalekit:
- env-url: ${SCALEKIT_ENV_URL}
+ env-url: ${SCALEKIT_ENVIRONMENT_URL}
client-id: ${SCALEKIT_CLIENT_ID}
client-secret: ${SCALEKIT_CLIENT_SECRET}
redirect-uri: ${SCALEKIT_REDIRECT_URI:http://localhost:8080/login/oauth2/code/scalekit}
diff --git a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
index 53f6550..24bf1b4 100644
--- a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
+++ b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
@@ -33,8 +33,8 @@ Detect the project's language/framework from existing files (`package.json`, `re
|-------|----------------|
| Node.js | `npm install @scalekit-sdk/node` |
| Python | `pip install scalekit-sdk-python` |
-| Go | `go get github.com/scalekit/scalekit-go` |
-| Java | Add `com.scalekit:scalekit-sdk` to `pom.xml` or `build.gradle` |
+| Go | `go get github.com/scalekit-inc/scalekit-sdk-go/v2` |
+| Java | Add `com.scalekit:scalekit-sdk-java` to `pom.xml` or `build.gradle` |
---
diff --git a/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
index b579143..445003b 100644
--- a/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/migrating-to-saaskit/SKILL.md
@@ -133,12 +133,12 @@ Verify:
```bash
# Verify token endpoint works with Scalekit credentials
-curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
-d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
# Expected: 200
# Verify a migrated user can be looked up
-curl -s -H "Authorization: Bearer $TOKEN" "$SCALEKIT_ENV_URL/api/v1/organizations//users?email=migrated-user@example.com" | jq .
+curl -s -H "Authorization: Bearer $TOKEN" "$SCALEKIT_ENVIRONMENT_URL/api/v1/organizations//users?email=migrated-user@example.com" | jq .
# Should return the user with correct external_id
```
diff --git a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
index b3e9d56..11e094e 100644
--- a/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/production-readiness-saaskit/SKILL.md
@@ -11,7 +11,7 @@ Work through in order — skip sections that don't apply. Earlier sections are b
```bash
# Confirm production credentials are set (not dev/staging)
-echo $SCALEKIT_ENV_URL # should be https://.scalekit.com (not .scalekit.dev)
+echo $SCALEKIT_ENVIRONMENT_URL # should be https://.scalekit.com (not .scalekit.dev)
echo $SCALEKIT_CLIENT_ID # should be set
echo $SCALEKIT_CLIENT_SECRET # should be set
```
@@ -31,7 +31,7 @@ echo $SCALEKIT_CLIENT_SECRET # should be set
```bash
# Test token endpoint reachability
-curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
+curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \
-d "client_id=$SCALEKIT_CLIENT_ID&client_secret=$SCALEKIT_CLIENT_SECRET&grant_type=client_credentials"
# Expected: 200
```
@@ -53,7 +53,7 @@ curl -s -o /dev/null -w "%{http_code}" -X POST "$SCALEKIT_ENV_URL/oauth/token" \
# Generate an auth URL with organization_id to trigger SSO
node -e "
const { ScalekitClient } = require('@scalekit-sdk/node');
-const sc = new ScalekitClient(process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET);
+const sc = new ScalekitClient(process.env.SCALEKIT_ENVIRONMENT_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET);
console.log(sc.getAuthorizationUrl(process.env.SCALEKIT_REDIRECT_URI, { organizationId: '' }));
"
# Open the URL — should redirect to the IdP login page
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
index e15de81..8a42e5a 100644
--- a/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
+++ b/plugins/saaskit/skills/scalekit-code-doctor/SKILL.md
@@ -41,7 +41,7 @@ import { ScalekitClient } from '@scalekit-sdk/node';
import crypto from 'crypto';
const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
);
@@ -93,7 +93,7 @@ Check these categories in order:
**3. Security** — Cookies: `httpOnly`, `secure`, `sameSite: 'lax'`. State: cryptographically random. Redirects: only relative paths. Secrets: from env vars. Webhooks: signature verified before processing.
-**4. Environment** — `SCALEKIT_ENV_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`. Redirect URI matches dashboard. Domain format: `https://.scalekit.com`.
+**4. Environment** — `SCALEKIT_ENVIRONMENT_URL`, `SCALEKIT_CLIENT_ID`, `SCALEKIT_CLIENT_SECRET`. Redirect URI matches dashboard. Domain format: `https://.scalekit.com`.
**5. Best practices** — Client is singleton. Error handling uses typed exceptions. `window.location.href` for OAuth redirects (not `router.push`).
@@ -107,7 +107,7 @@ Resolution order when a method isn't in `references/REFERENCE.md`:
|----------|--------|
| 1 | Embedded `references/REFERENCE.md` |
| 2 | Live SDK reference: `https://raw.githubusercontent.com/scalekit-inc/scalekit-sdk-{node,python,go,java}/main/REFERENCE.md` |
-| 3 | REST API: `https://docs.scalekit.com/apis.md` |
+| 3 | REST API: `https://docs.scalekit.com/apis` |
| 4 | State explicitly: "This method could not be verified." |
Never output code containing an unverified method call.
@@ -116,7 +116,7 @@ Never output code containing an unverified method call.
| Resource | URL |
|----------|-----|
-| REST API reference | `https://docs.scalekit.com/apis.md` |
+| REST API reference | `https://docs.scalekit.com/apis` |
| LLM doc index | `https://docs.scalekit.com/llms.txt` |
| SaaSKit docs | `https://docs.scalekit.com/_llms-txt/saaskit-complete.txt` |
| AgentKit docs | `https://docs.scalekit.com/_llms-txt/agentkit.txt` |
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md b/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
index 5343181..45ea547 100644
--- a/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
+++ b/plugins/saaskit/skills/scalekit-code-doctor/references/COMMON-MISTAKES.md
@@ -15,14 +15,12 @@ import { ScalekitClient } from 'scalekit'; // wrong package name
import { ScalekitClient } from 'scalekit-sdk-node'; // wrong package name
```
-**Correct (either works):**
+**Correct:**
```typescript
import { ScalekitClient } from '@scalekit-sdk/node';
-// OR
-import { Scalekit } from '@scalekit-sdk/node'; // official alias, also valid
```
-Both `ScalekitClient` and `Scalekit` are valid named exports from `@scalekit-sdk/node`. The SDK source exports both. Use whichever is consistent with your codebase.
+Only `ScalekitClient` is the canonical named export from `@scalekit-sdk/node`. Older docs sometimes show `Scalekit` as an alias — treat that as deprecated/wrong; the runtime export is `ScalekitClient`. Always use `ScalekitClient`.
### Python
@@ -335,7 +333,7 @@ const scalekit = new ScalekitClient(
**Correct:**
```typescript
const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
);
@@ -394,7 +392,7 @@ OAuth redirects are full HTTP redirects to an external domain (Scalekit/IdP). Cl
| Wrong | Correct | Issue |
|-------|---------|-------|
-| `SCALEKIT_URL` | `SCALEKIT_ENV_URL` | Missing `ENV_` |
+| `SCALEKIT_URL` | `SCALEKIT_ENVIRONMENT_URL` | Missing `ENV_` |
| `SCALEKIT_SECRET` | `SCALEKIT_CLIENT_SECRET` | Missing `CLIENT_` |
| `SCALEKIT_ID` | `SCALEKIT_CLIENT_ID` | Missing `CLIENT_` |
| `SCALEKIT_CALLBACK_URL` | `SCALEKIT_REDIRECT_URI` | Wrong name entirely |
@@ -419,7 +417,7 @@ app.get('/api/data', async (req, res) => {
```typescript
// Module-level singleton
const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!,
+ process.env.SCALEKIT_ENVIRONMENT_URL!,
process.env.SCALEKIT_CLIENT_ID!,
process.env.SCALEKIT_CLIENT_SECRET!
);
diff --git a/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md b/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md
index 5ecab18..43fb013 100644
--- a/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md
+++ b/plugins/saaskit/skills/scalekit-code-doctor/references/REFERENCE.md
@@ -1,6 +1,6 @@
# Scalekit API Reference — Compact Lookup
-This file contains every correct SDK method signature and REST endpoint. Use it as ground truth when generating or reviewing Scalekit code. If a method isn't listed here, do NOT assume it exists — verify against the live SDK source or `https://docs.scalekit.com/apis.md`.
+This file contains every correct SDK method signature and REST endpoint. Use it as ground truth when generating or reviewing Scalekit code. If a method isn't listed here, do NOT assume it exists — verify against the live SDK source or `https://docs.scalekit.com/apis`.
---
@@ -12,7 +12,7 @@ This file contains every correct SDK method signature and REST endpoint. Use it
import { ScalekitClient } from '@scalekit-sdk/node';
const scalekit = new ScalekitClient(
- process.env.SCALEKIT_ENV_URL!, // string — environment URL
+ process.env.SCALEKIT_ENVIRONMENT_URL!, // string — environment URL
process.env.SCALEKIT_CLIENT_ID!, // string — client ID
process.env.SCALEKIT_CLIENT_SECRET! // string — client secret
);
@@ -24,7 +24,7 @@ const scalekit = new ScalekitClient(
from scalekit import ScalekitClient
scalekit_client = ScalekitClient(
- os.environ.get('SCALEKIT_ENV_URL'), # str — environment URL
+ os.environ.get('SCALEKIT_ENVIRONMENT_URL'), # str — environment URL
os.environ.get('SCALEKIT_CLIENT_ID'), # str — client ID
os.environ.get('SCALEKIT_CLIENT_SECRET') # str — client secret
)
@@ -36,7 +36,7 @@ scalekit_client = ScalekitClient(
import scalekit "github.com/scalekit-inc/scalekit-sdk-go/v2"
client := scalekit.NewScalekitClient(
- os.Getenv("SCALEKIT_ENV_URL"), // string — environment URL
+ os.Getenv("SCALEKIT_ENVIRONMENT_URL"), // string — environment URL
os.Getenv("SCALEKIT_CLIENT_ID"), // string — client ID
os.Getenv("SCALEKIT_CLIENT_SECRET"), // string — client secret
)
@@ -48,7 +48,7 @@ client := scalekit.NewScalekitClient(
import com.scalekit.ScalekitClient;
ScalekitClient client = new ScalekitClient(
- System.getenv("SCALEKIT_ENV_URL"), // String — environment URL
+ System.getenv("SCALEKIT_ENVIRONMENT_URL"), // String — environment URL
System.getenv("SCALEKIT_CLIENT_ID"), // String — client ID
System.getenv("SCALEKIT_CLIENT_SECRET") // String — client secret
);
@@ -60,13 +60,13 @@ ScalekitClient client = new ScalekitClient(
| Variable | Purpose | Format |
|----------|---------|--------|
-| `SCALEKIT_ENV_URL` | Environment URL | `https://.scalekit.com` (prod) or `https://.scalekit.dev` (dev) |
+| `SCALEKIT_ENVIRONMENT_URL` | Environment URL | `https://.scalekit.com` (prod) or `https://.scalekit.dev` (dev) |
| `SCALEKIT_CLIENT_ID` | Client ID | String from dashboard |
| `SCALEKIT_CLIENT_SECRET` | Client secret | String from dashboard |
| `SCALEKIT_REDIRECT_URI` | OAuth callback URL | Must exactly match dashboard config |
| `SCALEKIT_WEBHOOK_SECRET` | Webhook signing secret | Format: `whsec_...` |
-Note: The REST API docs use `SCALEKIT_ENVIRONMENT_URL` in some examples. Both `SCALEKIT_ENV_URL` and `SCALEKIT_ENVIRONMENT_URL` are acceptable — just be consistent within a project.
+Note: The REST API docs use `SCALEKIT_ENVIRONMENT_URL` in some examples. Both `SCALEKIT_ENVIRONMENT_URL` and `SCALEKIT_ENVIRONMENT_URL` are acceptable — just be consistent within a project.
---
diff --git a/plugins/saaskit/skills/testing-auth-setup/SKILL.md b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
index 45f3f96..1517a40 100644
--- a/plugins/saaskit/skills/testing-auth-setup/SKILL.md
+++ b/plugins/saaskit/skills/testing-auth-setup/SKILL.md
@@ -24,7 +24,7 @@ npm i -g @scalekit-inc/cli
Confirm these environment variables are available:
-- `SCALEKIT_ENV_URL` — your Scalekit environment URL
+- `SCALEKIT_ENVIRONMENT_URL` — your Scalekit environment URL
- `SCALEKIT_CLIENT_ID` — your client ID from app.scalekit.com > Settings
## Running the test
@@ -32,7 +32,7 @@ Confirm these environment variables are available:
### Full-stack auth (fsa)
```bash
-npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENV_URL --client_id=$SCALEKIT_CLIENT_ID --mode=fsa
+npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENVIRONMENT_URL --client_id=$SCALEKIT_CLIENT_ID --mode=fsa
```
### Enterprise SSO
@@ -40,7 +40,7 @@ npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENV_URL --client_id=$SCALEKIT_CLIEN
Requires an `organization_id` — ask for it if not provided.
```bash
-npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENV_URL --client_id=$SCALEKIT_CLIENT_ID --mode=sso --organization_id=
+npx @scalekit-sdk/dryrun --env_url=$SCALEKIT_ENVIRONMENT_URL --client_id=$SCALEKIT_CLIENT_ID --mode=sso --organization_id=
```
## Choosing the mode
From 9e2d9d701bd8de9dec45a6d6d387b9ac3ff4cb5d Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 12:24:51 +0530
Subject: [PATCH 35/39] fix: scalekit.auth sub-client, SCIM methods, webhook,
getLogoutUrl, sameSite, mcp-remote, internal imports
---
README.md | 2 +-
plugins/agentkit/references/code-samples.md | 8 ++---
.../discovering-connector-tools/SKILL.md | 9 ++---
.../skills/exposing-agentkit-via-mcp/SKILL.md | 2 +-
.../saaskit/references/bring-your-own-auth.md | 10 +++---
.../saaskit/references/scalekit-mcp-server.md | 6 ++--
.../references/session-management-patterns.md | 6 ++--
.../skills/implementing-modular-sso/SKILL.md | 2 +-
.../implementing-saaskit-python/SKILL.md | 10 +++---
.../skills/implementing-saaskit/SKILL.md | 6 ++--
.../implementing-scim-provisioning/SKILL.md | 34 ++++++++++---------
11 files changed, 49 insertions(+), 46 deletions(-)
diff --git a/README.md b/README.md
index bd8b74a..317fffd 100644
--- a/README.md
+++ b/README.md
@@ -120,7 +120,7 @@ This checks:
- [Scalekit Documentation](https://docs.scalekit.com) — Complete guides and API reference
- [Modular SSO guide](https://docs.scalekit.com/authenticate/sso/add-modular-sso/) — Implement enterprise SSO
- [MCP Auth guide](https://docs.scalekit.com/authenticate/mcp/quickstart/) — Secure MCP servers
-- [AgentKit overview](https://docs.scalekit.com/agentkit/overview.md) — Connect agents to authenticated tools
+- [AgentKit overview](https://docs.scalekit.com/agentkit/overview/) — Connect agents to authenticated tools
#### Resources
diff --git a/plugins/agentkit/references/code-samples.md b/plugins/agentkit/references/code-samples.md
index db692c7..314152e 100644
--- a/plugins/agentkit/references/code-samples.md
+++ b/plugins/agentkit/references/code-samples.md
@@ -157,21 +157,21 @@ adk run scalekit_tool_agent
**1. Complete Agent Implementation**
```python
from google.adk.agents import Agent
-import scalekit.client
+from scalekit import ScalekitClient
import os
identifier = "user-1234"
connection_name = "gmail"
# Initialize Scalekit client
-client = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL")
)
# Generate OAuth authorization link
-auth = client.actions.get_authorization_link(
+auth = sk_client.actions.get_authorization_link(
identifier=identifier,
connection_name=connection_name
)
@@ -181,7 +181,7 @@ print(f"🔗 Visit this URL to authorize the gmail connection:\n\n {auth.link}
input("✅ Press Enter after authorization...")
# Generate Gmail tools with authenticated access
-gmail_tools = client.actions.google.get_tools(
+gmail_tools = sk_client.actions.google.get_tools(
providers=["GMAIL"],
identifier=identifier,
page_size=100
diff --git a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
index 5523882..01e84aa 100644
--- a/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
+++ b/plugins/agentkit/skills/discovering-connector-tools/SKILL.md
@@ -25,18 +25,19 @@ Do not rely on static connector notes as a complete catalog. Those may lag the l
## Live tool discovery (Python)
```python
-import scalekit.client, os
+import os
from dotenv import load_dotenv
+from scalekit import ScalekitClient
load_dotenv()
-client = scalekit.client.ScalekitClient(
+sk_client = ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
# List all tools for a provider
-tools = client.actions.get_tools(providers=["GMAIL"], page_size=100)
+tools = sk_client.actions.get_tools(providers=["GMAIL"], page_size=100)
for tool in tools.tools:
print(f"Tool: {tool.name}")
print(f" Description: {tool.description}")
@@ -44,7 +45,7 @@ for tool in tools.tools:
print(f" Output schema: {tool.output_schema}")
# Get a specific tool by name
-tool = client.actions.get_tools(tool_name="gmail_fetch_mails")
+tool = sk_client.actions.get_tools(tool_name="gmail_fetch_mails")
```
## Live tool discovery (Node.js)
diff --git a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
index 59f7c46..0f04789 100644
--- a/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
+++ b/plugins/agentkit/skills/exposing-agentkit-via-mcp/SKILL.md
@@ -44,7 +44,7 @@ Add these imports to `main.py`:
import os
import asyncio
from dotenv import load_dotenv
-import scalekit.client
+from scalekit import ScalekitClient
from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping
from scalekit.actions.types import GetMcpInstanceAuthStateResponse
from langgraph.prebuilt import create_react_agent
diff --git a/plugins/saaskit/references/bring-your-own-auth.md b/plugins/saaskit/references/bring-your-own-auth.md
index f268b1a..eee3eaa 100644
--- a/plugins/saaskit/references/bring-your-own-auth.md
+++ b/plugins/saaskit/references/bring-your-own-auth.md
@@ -64,13 +64,13 @@ from scalekit import ScalekitClient
import os
scalekit = ScalekitClient(
- os.environ.get('SCALEKIT_ENVIRONMENT_URL'),
- os.environ.get('SCALEKIT_CLIENT_ID'),
- os.environ.get('SCALEKIT_CLIENT_SECRET')
+ env_url=os.environ.get('SCALEKIT_ENVIRONMENT_URL'),
+ client_id=os.environ.get('SCALEKIT_CLIENT_ID'),
+ client_secret=os.environ.get('SCALEKIT_CLIENT_SECRET')
)
# Update login user details
-scalekit.auth.update_login_user_details(
+scalekit.update_login_user_details(
connection_id="{{connection_id}}",
login_request_id="{{login_request_id}}",
user={
@@ -95,7 +95,7 @@ const scalekit = new ScalekitClient(
process.env.SCALEKIT_CLIENT_SECRET
);
-await scalekit.auth.updateLoginUserDetails(
+await scalekit.updateLoginUserDetails(
'{{connection_id}}',
'{{login_request_id}}',
{
diff --git a/plugins/saaskit/references/scalekit-mcp-server.md b/plugins/saaskit/references/scalekit-mcp-server.md
index 4ee78c9..ed5d4e9 100644
--- a/plugins/saaskit/references/scalekit-mcp-server.md
+++ b/plugins/saaskit/references/scalekit-mcp-server.md
@@ -73,7 +73,7 @@ server.tool(
},
async ({ environmentId, name }, { token }) => {
// Token already validated by middleware
- const organization = await scalekit.createOrganization({
+ const organization = await scalekit.organization.createOrganization({
environmentId,
name,
});
@@ -441,8 +441,8 @@ The Scalekit MCP server is already hosted and ready to use:
{
"mcpServers": {
"scalekit": {
- "command": "npx",
- "args": ["-y", "mcp-remote", "https://mcp.scalekit.com/"]
+ "type": "http",
+ "url": "https://mcp.scalekit.com/"
}
}
}
diff --git a/plugins/saaskit/references/session-management-patterns.md b/plugins/saaskit/references/session-management-patterns.md
index 3c8d03d..ac97557 100644
--- a/plugins/saaskit/references/session-management-patterns.md
+++ b/plugins/saaskit/references/session-management-patterns.md
@@ -103,7 +103,7 @@ res.cookie('access_token', tokens.access_token, {
res.cookie('refresh_token', tokens.refresh_token, {
httpOnly: true,
secure: true,
- sameSite: 'strict',
+ sameSite: 'lax',
path: '/auth/refresh', // scope to refresh endpoint only
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
@@ -170,9 +170,7 @@ lucia) that want enterprise SSO without rebuilding auth.
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
- const { user, idTokenClaims } = await scalekit.auth.authenticateWithCode(code, {
- redirectUri: process.env.REDIRECT_URI
- });
+ const { user, idTokenClaims } = await scalekit.authenticateWithCode(code, process.env.REDIRECT_URI);
// Create session using YOUR existing mechanism
req.session.userId = user.id;
diff --git a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
index 6f1b49a..ea3e367 100644
--- a/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
+++ b/plugins/saaskit/skills/implementing-modular-sso/SKILL.md
@@ -55,7 +55,7 @@ pip install scalekit-sdk-python
**Go:**
```bash
-go get github.com/scalekit-inc/scalekit-sdk-go
+go get github.com/scalekit-inc/scalekit-sdk-go/v2
```
**Java:**
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index c5589ef..3122049 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -25,7 +25,7 @@ pip install scalekit-sdk-python python-dotenv
```python
import os
from dotenv import load_dotenv
-from scalekit import ScalekitClient
+from scalekit import ScalekitClient, AuthorizationUrlOptions, LogoutUrlOptions
load_dotenv()
@@ -53,7 +53,7 @@ import os, secrets
from fastapi import FastAPI, Request, Response
from fastapi.responses import RedirectResponse
from dotenv import load_dotenv
-from scalekit import ScalekitClient
+from scalekit import ScalekitClient, AuthorizationUrlOptions, LogoutUrlOptions
load_dotenv()
@@ -69,7 +69,8 @@ sc = ScalekitClient(
@app.get("/auth/login")
def login(response: Response):
state = secrets.token_urlsafe(32)
- response = RedirectResponse(sc.get_authorization_url(REDIRECT_URI, {"state": state}))
+ options = AuthorizationUrlOptions(state=state)
+ response = RedirectResponse(sc.get_authorization_url(REDIRECT_URI, options))
response.set_cookie("oauth_state", state, httponly=True, samesite="lax", secure=True)
return response
@@ -86,7 +87,8 @@ def callback(request: Request, code: str, state: str):
@app.get("/auth/logout")
def logout(request: Request):
- logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:8000"})
+ options = LogoutUrlOptions(post_logout_redirect_uri="http://localhost:8000")
+ logout_url = sc.get_logout_url(options)
# Clear your session here
return RedirectResponse(logout_url)
```
diff --git a/plugins/saaskit/skills/implementing-saaskit/SKILL.md b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
index f36bb4d..20c900f 100644
--- a/plugins/saaskit/skills/implementing-saaskit/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit/SKILL.md
@@ -55,10 +55,10 @@ Store tokens in HttpOnly cookies:
// Node.js
res.cookie('accessToken', authResult.accessToken, {
maxAge: (authResult.expiresIn - 60) * 1000,
- httpOnly: true, secure: true, path: '/api', sameSite: 'strict'
+ httpOnly: true, secure: true, path: '/api', sameSite: 'lax'
});
res.cookie('refreshToken', authResult.refreshToken, {
- httpOnly: true, secure: true, path: '/auth/refresh', sameSite: 'strict'
+ httpOnly: true, secure: true, path: '/auth/refresh', sameSite: 'lax'
});
```
@@ -74,7 +74,7 @@ Clear session data, then redirect to Scalekit's logout endpoint:
```js
// Node.js
clearSessionData();
-const logoutUrl = scalekit.getLogoutUrl(idTokenHint, postLogoutRedirectUri);
+const logoutUrl = scalekit.getLogoutUrl({ idTokenHint, postLogoutRedirectUri });
res.redirect(logoutUrl); // One-time use URL; expires after logout
```
diff --git a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
index 24bf1b4..ec7ba25 100644
--- a/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
+++ b/plugins/saaskit/skills/implementing-scim-provisioning/SKILL.md
@@ -90,7 +90,8 @@ Use for scheduled jobs, onboarding flows, or bulk imports. Integrate into existi
```javascript
// Node.js
-const { directory } = await scalekit.directory.getPrimaryDirectoryByOrganizationId(orgId);
+const { directories } = await scalekit.directory.listDirectories(orgId);
+const directory = directories[0];
const { users } = await scalekit.directory.listDirectoryUsers(orgId, directory.id);
for (const user of users) {
@@ -100,7 +101,8 @@ for (const user of users) {
```python
# Python
-directory = scalekit_client.directory.get_primary_directory_by_organization_id(org_id)
+response = scalekit_client.directory.list_directories(org_id)
+directory = response.directories[0]
users = scalekit_client.directory.list_directory_users(org_id, directory.id)
for user in users:
@@ -128,18 +130,17 @@ Add a new route to the existing HTTP server/router. Match the framework pattern
**Node.js (Express):**
```javascript
-app.post('/webhooks/scalekit', async (req, res) => {
- try {
- await scalekit.verifyWebhookPayload(
- process.env.SCALEKIT_WEBHOOK_SECRET,
- req.headers,
- req.body
- );
- } catch {
+app.post('/webhooks/scalekit', express.raw({ type: 'application/json' }), async (req, res) => {
+ const isValid = scalekit.verifyWebhookPayload(
+ process.env.SCALEKIT_WEBHOOK_SECRET,
+ req.headers,
+ req.body
+ );
+ if (!isValid) {
return res.status(400).json({ error: 'Invalid signature' });
}
- const { type, data } = req.body;
+ const { type, data } = JSON.parse(req.body);
try {
await handleDirectoryEvent(type, data);
res.status(201).json({ status: 'processed' });
@@ -153,15 +154,16 @@ app.post('/webhooks/scalekit', async (req, res) => {
```python
@app.post("/webhooks/scalekit")
async def scalekit_webhook(request: Request):
- body = await request.json()
- valid = scalekit_client.verify_webhook_payload(
+ raw_body = await request.body()
+ is_valid = scalekit_client.verify_webhook_payload(
secret=os.getenv("SCALEKIT_WEBHOOK_SECRET"),
- headers=request.headers,
- payload=json.dumps(body).encode()
+ headers=dict(request.headers),
+ payload=raw_body
)
- if not valid:
+ if not is_valid:
raise HTTPException(status_code=400, detail="Invalid signature")
+ body = json.loads(raw_body)
await handle_directory_event(body.get("type"), body.get("data", {}))
return JSONResponse(status_code=201, content={"status": "processed"})
```
From 2901e6110d6c03e5807d0cc5c714a55fe77899c6 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 12:41:24 +0530
Subject: [PATCH 36/39] fix: SK_ENV_URL, .scalekit.dev, decodeToken,
refresh_token, Go SDK /v2, add Codex to client lists
---
plugins/agentkit/skills/setup/SKILL.md | 2 +-
plugins/saaskit/references/setup-scalekit.md | 2 +-
plugins/saaskit/skills/adding-mcp-oauth/SKILL.md | 2 +-
.../skills/adding-mcp-oauth/express-reference.md | 12 ++++++------
.../skills/adding-mcp-oauth/fastapi-reference.md | 8 ++++----
.../skills/implementing-access-control/SKILL.md | 6 ++----
.../implementing-saaskit-python/django-reference.md | 2 +-
.../implementing-saaskit-python/fastapi-reference.md | 2 +-
.../implementing-saaskit-python/flask-reference.md | 2 +-
.../skills/implementing-saaskit/go-reference.md | 2 +-
.../implementing-saaskit/springboot-reference.md | 2 +-
plugins/saaskit/skills/setup/SKILL.md | 2 +-
12 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/plugins/agentkit/skills/setup/SKILL.md b/plugins/agentkit/skills/setup/SKILL.md
index 546afe2..4717da5 100644
--- a/plugins/agentkit/skills/setup/SKILL.md
+++ b/plugins/agentkit/skills/setup/SKILL.md
@@ -31,7 +31,7 @@ If answers aren't already clear from context, ask:
|---|---|
| Connect users to third-party apps, execute tools on their behalf | `/agentkit:integrating-agentkit` |
| Discover available tools for a connector, inspect schemas | `/agentkit:discovering-connector-tools` |
-| Expose AgentKit tools over MCP for Claude Desktop, Cursor, VS Code | `/agentkit:exposing-agentkit-via-mcp` |
+| Expose AgentKit tools over MCP for Claude Desktop, Codex, Cursor, VS Code | `/agentkit:exposing-agentkit-via-mcp` |
| Pre-launch checklist for production | `/agentkit:production-readiness-agentkit` |
| SDK errors, wrong imports, broken auth calls | `/saaskit:scalekit-code-doctor` |
diff --git a/plugins/saaskit/references/setup-scalekit.md b/plugins/saaskit/references/setup-scalekit.md
index 1712744..6afec80 100644
--- a/plugins/saaskit/references/setup-scalekit.md
+++ b/plugins/saaskit/references/setup-scalekit.md
@@ -42,7 +42,7 @@ npm i -g @scalekit-inc/cli
|----------|---------|
| Node.js | `npm install @scalekit-sdk/node` |
| Python | `pip install scalekit-sdk-python` |
-| Go | `go get github.com/scalekit-inc/scalekit-sdk-go` |
+| Go | `go get github.com/scalekit-inc/scalekit-sdk-go/v2` |
| Java | Add `scalekit-sdk-java` to Maven/Gradle |
### 5. Initialize the client
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
index 8236bcf..a32e0de 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/SKILL.md
@@ -1,6 +1,6 @@
---
name: adding-mcp-oauth
-description: Guides users through adding OAuth 2.1 authorization to MCP servers using Scalekit — configures discovery endpoints, sets up token validation middleware, and enables scope-based tool authorization. Use when setting up MCP servers, implementing authentication for AI hosts like Claude Desktop, Cursor, or VS Code, or when users mention MCP security, OAuth, or Scalekit integration.
+description: Guides users through adding OAuth 2.1 authorization to MCP servers using Scalekit — configures discovery endpoints, sets up token validation middleware, and enables scope-based tool authorization. Use when setting up MCP servers, implementing authentication for AI hosts like Claude Desktop, Codex, Cursor, or VS Code, or when users mention MCP security, OAuth, or Scalekit integration.
---
# Adding OAuth 2.1 Authorization to MCP Servers
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
index d25874d..87f839c 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/express-reference.md
@@ -43,8 +43,8 @@ McpServer → Tool Handler → Response
### 1. Environment Configuration
**Required variables:**
-- `SK_ENV_URL`: Scalekit environment URL (issuer)
-- `SK_CLIENT_ID` + `SK_CLIENT_SECRET`: SDK authentication credentials
+- `SCALEKIT_ENVIRONMENT_URL`: Scalekit environment URL (issuer)
+- `SCALEKIT_CLIENT_ID` + `SCALEKIT_CLIENT_SECRET`: SDK authentication credentials
- `EXPECTED_AUDIENCE`: The resource identifier that tokens must target
- `PROTECTED_RESOURCE_METADATA`: Complete OAuth discovery metadata JSON
- `PORT`: Server listening port (must match registered server URL)
@@ -53,7 +53,7 @@ McpServer → Tool Handler → Response
- Never commit `.env` files to version control
- Add `.env` to `.gitignore` immediately
- Use secret managers in production (AWS Secrets Manager, Doppler, HashiCorp Vault)
-- Rotate `SK_CLIENT_SECRET` regularly
+- Rotate `SCALEKIT_CLIENT_SECRET` regularly
- Validate `EXPECTED_AUDIENCE` matches your server's public URL exactly (including trailing slash)
### 2. Scalekit Client Initialization
@@ -62,9 +62,9 @@ McpServer → Tool Handler → Response
import { ScalekitClient } from '@scalekit-sdk/node';
const scalekit = new ScalekitClient(
- SK_ENV_URL,
- SK_CLIENT_ID,
- SK_CLIENT_SECRET
+ SCALEKIT_ENVIRONMENT_URL,
+ SCALEKIT_CLIENT_ID,
+ SCALEKIT_CLIENT_SECRET
);
```
diff --git a/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md b/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
index 1538e1e..51b3ffe 100644
--- a/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
+++ b/plugins/saaskit/skills/adding-mcp-oauth/fastapi-reference.md
@@ -42,8 +42,8 @@ FastAPI → MCP Tool Handler → Response
### 1. Environment Configuration
**Required variables:**
-- `SK_ENV_URL`: Scalekit environment URL (issuer)
-- `SK_CLIENT_ID` + `SK_CLIENT_SECRET`: SDK authentication credentials
+- `SCALEKIT_ENVIRONMENT_URL`: Scalekit environment URL (issuer)
+- `SCALEKIT_CLIENT_ID` + `SCALEKIT_CLIENT_SECRET`: SDK authentication credentials
- `EXPECTED_AUDIENCE`: The resource identifier that tokens must target
- `PROTECTED_RESOURCE_METADATA`: Complete OAuth discovery metadata JSON
- `PORT`: Server listening port (must match registered server URL)
@@ -51,7 +51,7 @@ FastAPI → MCP Tool Handler → Response
**Security:**
- Never commit `.env` files to version control
- Use secret managers in production (AWS Secrets Manager, HashiCorp Vault)
-- Rotate `SK_CLIENT_SECRET` regularly
+- Rotate `SCALEKIT_CLIENT_SECRET` regularly
- Validate `EXPECTED_AUDIENCE` matches your server's public URL exactly
### 2. Middleware Authentication Pattern
@@ -77,7 +77,7 @@ async def auth_middleware(request: Request, call_next):
# Validate with Scalekit SDK
options = TokenValidationOptions(
- issuer=SK_ENV_URL,
+ issuer=SCALEKIT_ENVIRONMENT_URL,
audience=[EXPECTED_AUDIENCE]
)
diff --git a/plugins/saaskit/skills/implementing-access-control/SKILL.md b/plugins/saaskit/skills/implementing-access-control/SKILL.md
index 14fdc2b..3c67799 100644
--- a/plugins/saaskit/skills/implementing-access-control/SKILL.md
+++ b/plugins/saaskit/skills/implementing-access-control/SKILL.md
@@ -26,10 +26,8 @@ Validate+extract, then RBAC/PBAC guards.
const validateAndExtractAuth = async (req, res, next) => {
try {
const accessToken = decrypt(req.cookies.accessToken); // if encrypted
- const isValid = await scalekit.validateAccessToken(accessToken);
- if (!isValid) return res.status(401).json({ error: "Invalid or expired token" });
-
- const tokenData = await decodeToken(accessToken); // JWT decode library
+ const tokenData = await scalekit.validateAccessTokenAndGetClaims(accessToken);
+ if (!tokenData) return res.status(401).json({ error: "Invalid or expired token" });
req.user = {
id: tokenData.sub,
organizationId: tokenData.oid,
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
index b3e11cb..931b058 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
@@ -9,7 +9,7 @@ pip install scalekit-sdk-python python-dotenv django
## Environment variables
```env
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:8000/auth/callback
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
index 3f80b28..b4f0ce3 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
@@ -104,7 +104,7 @@ class ScalekitClientWrapper:
return self._client.validate_access_token_and_get_claims(access_token)
def refresh_access_token(self, refresh_token: str) -> dict:
- return self._client.refresh_token(refresh_token)
+ return self._client.refresh_access_token(refresh_token)
def has_permission(self, access_token: str, permission: str) -> bool:
try:
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
index 1b1ed73..a87747a 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
@@ -9,7 +9,7 @@ pip install scalekit-sdk-python python-dotenv flask flask-session
## Environment variables
```env
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
SCALEKIT_REDIRECT_URI=http://localhost:5000/auth/callback
diff --git a/plugins/saaskit/skills/implementing-saaskit/go-reference.md b/plugins/saaskit/skills/implementing-saaskit/go-reference.md
index 8364c1c..97cdd22 100644
--- a/plugins/saaskit/skills/implementing-saaskit/go-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit/go-reference.md
@@ -20,7 +20,7 @@ go get github.com/golang-jwt/jwt/v5
## Environment variables
```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=your_client_id
SCALEKIT_CLIENT_SECRET=your_client_secret
PORT=8080
diff --git a/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md b/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
index 07110e9..29a6621 100644
--- a/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit/springboot-reference.md
@@ -153,7 +153,7 @@ Key `OidcUser` accessors: `getFullName()`, `getEmail()`, `getSubject()`, `getCla
## Scalekit Dashboard setup checklist
```
-- [ ] Get Environment URL (e.g., https://your-env.scalekit.dev)
+- [ ] Get Environment URL (e.g., https://your-env.scalekit.com)
- [ ] Get Client ID and Client Secret from Settings > API Credentials
- [ ] Add allowed redirect URI: http://localhost:8080/login/oauth2/code/scalekit
- [ ] Optionally add post-logout redirect: http://localhost:8080
diff --git a/plugins/saaskit/skills/setup/SKILL.md b/plugins/saaskit/skills/setup/SKILL.md
index a8af32f..2c929af 100644
--- a/plugins/saaskit/skills/setup/SKILL.md
+++ b/plugins/saaskit/skills/setup/SKILL.md
@@ -56,7 +56,7 @@ If the user wants **login + SSO + SCIM** (full B2B auth stack), start with `/saa
Before starting any skill, verify credentials exist:
```bash
-SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.dev
+SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
SCALEKIT_CLIENT_ID=
SCALEKIT_CLIENT_SECRET=
```
From 48ee3753d20a20058ecbf8db6acf690fa88b8d97 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 16:57:02 +0530
Subject: [PATCH 37/39] fix: correct Python SDK call patterns for
get_authorization_url and get_logout_url
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- get_authorization_url: AuthorizationUrlOptions takes no constructor args
- get_logout_url: pass LogoutUrlOptions object, not dicts or bare kwargs
- fastapi-reference: fix wrong param name (access_token → id_token_hint)
---
.../saaskit/skills/implementing-saaskit-python/SKILL.md | 3 ++-
.../implementing-saaskit-python/django-reference.md | 3 ++-
.../implementing-saaskit-python/fastapi-reference.md | 9 +++++----
.../implementing-saaskit-python/flask-reference.md | 3 ++-
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
index 3122049..286c629 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/SKILL.md
@@ -69,7 +69,8 @@ sc = ScalekitClient(
@app.get("/auth/login")
def login(response: Response):
state = secrets.token_urlsafe(32)
- options = AuthorizationUrlOptions(state=state)
+ options = AuthorizationUrlOptions()
+ options.state = state
response = RedirectResponse(sc.get_authorization_url(REDIRECT_URI, options))
response.set_cookie("oauth_state", state, httponly=True, samesite="lax", secure=True)
return response
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
index 931b058..fbc82b2 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
@@ -92,7 +92,8 @@ def callback(request: HttpRequest):
def logout(request: HttpRequest):
id_token = request.session.get("id_token", "")
sc = get_scalekit_client()
- logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:8000"})
+ from scalekit.common.scalekit import LogoutUrlOptions
+ logout_url = sc.get_logout_url(LogoutUrlOptions(post_logout_redirect_uri="http://localhost:8000"))
request.session.flush()
return redirect(logout_url)
```
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
index b4f0ce3..e99a51e 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
@@ -117,11 +117,12 @@ class ScalekitClientWrapper:
except Exception:
return False
- def logout(self, access_token: str) -> str:
- return self._client.get_logout_url(
- access_token=access_token,
+ def logout(self, id_token: str) -> str:
+ from scalekit.common.scalekit import LogoutUrlOptions
+ return self._client.get_logout_url(LogoutUrlOptions(
+ id_token_hint=id_token,
post_logout_redirect_uri=settings.scalekit_redirect_uri.replace('/auth/callback', '/'),
- )
+ ))
@lru_cache(maxsize=1)
def scalekit_client() -> ScalekitClientWrapper:
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
index a87747a..d507a4b 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
@@ -90,7 +90,8 @@ def callback():
@app.get("/auth/logout")
def logout():
id_token = session.get("id_token", "")
- logout_url = sc.get_logout_url({"post_logout_redirect_uri": "http://localhost:5000"})
+ from scalekit.common.scalekit import LogoutUrlOptions
+ logout_url = sc.get_logout_url(LogoutUrlOptions(post_logout_redirect_uri="http://localhost:5000"))
session.clear()
return redirect(logout_url)
```
From 063c45e7590cb3c5dc67e4331a4d9bf243223828 Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 17:00:47 +0530
Subject: [PATCH 38/39] fix: get_authorization_url options must be typed
object, not dict, in django/flask refs
---
.../skills/implementing-saaskit-python/django-reference.md | 5 ++++-
.../skills/implementing-saaskit-python/flask-reference.md | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
index fbc82b2..f7743a7 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/django-reference.md
@@ -69,7 +69,10 @@ def login(request: HttpRequest):
state = secrets.token_urlsafe(32)
request.session["oauth_state"] = state
sc = get_scalekit_client()
- auth_url = sc.get_authorization_url(REDIRECT_URI, options={"state": state})
+ from scalekit.common.scalekit import AuthorizationUrlOptions
+ options = AuthorizationUrlOptions()
+ options.state = state
+ auth_url = sc.get_authorization_url(REDIRECT_URI, options)
return redirect(auth_url)
def callback(request: HttpRequest):
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
index d507a4b..8e66fb2 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/flask-reference.md
@@ -68,7 +68,10 @@ GET /auth/logout
def login():
state = secrets.token_urlsafe(32)
session["oauth_state"] = state
- auth_url = sc.get_authorization_url(REDIRECT_URI, options={"state": state})
+ from scalekit.common.scalekit import AuthorizationUrlOptions
+ options = AuthorizationUrlOptions()
+ options.state = state
+ auth_url = sc.get_authorization_url(REDIRECT_URI, options)
return redirect(auth_url)
@app.get("/auth/callback")
From 56df030ac3d11630a4ad3445c362b6fbab408a4c Mon Sep 17 00:00:00 2001
From: Saif Shines
Date: Fri, 22 May 2026 17:33:23 +0530
Subject: [PATCH 39/39] fix: replace phantom get_user_info with
validate_access_token_and_get_claims in fastapi-reference
---
.../skills/implementing-saaskit-python/fastapi-reference.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
index e99a51e..653467c 100644
--- a/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
+++ b/plugins/saaskit/skills/implementing-saaskit-python/fastapi-reference.md
@@ -98,7 +98,7 @@ class ScalekitClientWrapper:
)
def get_user_info(self, access_token: str) -> dict:
- return self._client.get_user_info(access_token)
+ return self._client.validate_access_token_and_get_claims(access_token)
def validate_token_and_get_claims(self, access_token: str) -> dict:
return self._client.validate_access_token_and_get_claims(access_token)