Supercheck Security Auth
supercheck-io/supercheck
Work on Supercheck authentication, RBAC, tenant isolation, sessions, API and trigger keys, invitations, project membership, project variables, OAuth, super-admin behavior, SSRF, or…
SaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling.
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install vibeeval/vibecosystem saas-auth-patterns --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/saas-auth-patterns .claude/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .claude/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patternsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install vibeeval/vibecosystem saas-auth-patterns --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/saas-auth-patterns .agents/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .agents/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install vibeeval/vibecosystem saas-auth-patterns --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/saas-auth-patterns .cursor/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .cursor/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/vibeeval/vibecosystem.git --path skills/saas-auth-patterns--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install vibeeval/vibecosystem saas-auth-patterns --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/saas-auth-patterns .gemini/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .gemini/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install vibeeval/vibecosystem saas-auth-patternsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/saas-auth-patterns .github/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .github/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install vibeeval/vibecosystem saas-auth-patterns --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/vibeeval/vibecosystem.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/saas-auth-patterns .opencode/skills/saas-auth-patterns && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "saas-auth-patterns" agent skill from https://github.com/vibeeval/vibecosystem/tree/main/skills/saas-auth-patterns into .opencode/skills/saas-auth-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "saas-auth-patterns", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
saas-auth-patternsSaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling.
SaaS Auth Patterns is an agent skill from vibeeval/vibecosystem. SaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling.
Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering Authentication, Authorization and RBAC and Multi-tenancy. The repository describes itself as: AI software team for Claude Code - 138 agents, 295 skills, 73 hooks. Self-learning, multi-agent swarm, autonomous skill evolution. The licence is MIT.
Read from SKILL.md and the folder at commit 3b763b1. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
SaaS Auth Patterns loads about 3.2k tokens when it runs. Until then it costs about 52 tokens; SKILL.md has 160 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from vibeeval/vibecosystem at commit 3b763b1, republished under its MIT licence (© vibeeval). 160 words, ~3,193 tokens.
.claude/skills/saas-auth-patterns/SKILL.md (or your agent's skills folder).Authentication and authorization patterns for multi-tenant SaaS applications.
| Strategy | Stateless | Scalable | Revocable | Best For |
|---|---|---|---|---|
| JWT + Refresh | Yes | High | Hard (needs blocklist) | API-first, mobile clients |
| Session (server) | No | Medium (sticky/shared store) | Instant | Traditional web apps |
| OAuth 2.0 + PKCE | Yes | High | Via provider | Third-party login, SSO |
Pick JWT when you control both client and server and need horizontal scaling. Pick sessions when you need instant revocation and serve server-rendered pages. Pick OAuth when users expect "Sign in with Google/GitHub" or you federate identity.
interface TenantContext {
tenantId: string
userId: string
role: string
}
// Extract tenant from JWT claims or subdomain
function resolveTenant(req: Request): TenantContext {
const token = req.headers.get('authorization')?.replace('Bearer ', '')
if (!token) throw new AuthError('Missing token')
const payload = verifyJwt(token)
return {
tenantId: payload.tenantId,
userId: payload.sub,
role: payload.role,
}
}
// Every DB query scoped to tenant - no cross-tenant leakage
async function getTenantUsers(ctx: TenantContext): Promise<User[]> {
return db.users.findMany({
where: { tenantId: ctx.tenantId },
})
}// Shared DB (row-level isolation) - simpler ops, lower cost
// Every table has tenant_id column + RLS policy
// SQL: CREATE POLICY tenant_isolation ON users
// USING (tenant_id = current_setting('app.tenant_id'))
async function withTenantScope<T>(tenantId: string, fn: () => Promise<T>): Promise<T> {
await db.$executeRaw`SELECT set_config('app.tenant_id', ${tenantId}, true)`
return fn()
}
// Isolated DB (schema-per-tenant) - stronger isolation, harder ops
// Use when: compliance requires it, tenants have wildly different data volumes
function getTenantConnection(tenantId: string): PrismaClient {
// SECURITY: Validate tenantId to prevent schema injection
if (!/^[a-zA-Z0-9_-]+$/.test(tenantId)) {
throw new Error('Invalid tenant ID format')
}
const schema = `tenant_${tenantId}`
// Note: Cache PrismaClient instances per tenant to avoid connection leaks
return new PrismaClient({ datasources: { db: { url: `${DB_URL}?schema=${schema}` } } })
}async function linkOrCreateAccount(provider: string, profile: OAuthProfile): Promise<User> {
// Step 1: Check if social account already linked
const existing = await db.socialAccounts.findUnique({
where: { provider_providerAccountId: { provider, providerAccountId: profile.id } },
include: { user: true },
})
if (existing) return existing.user
// Step 2: Check if email matches an existing user
// SECURITY: Only auto-link if provider verified the email
if (!profile.email_verified) {
return db.users.create({
data: {
email: null, name: profile.name,
socialAccounts: { create: { provider, providerAccountId: profile.id } },
},
})
}
const emailUser = await db.users.findUnique({
where: { email: profile.email },
})
if (emailUser) {
// Link social account to existing user (merge)
await db.socialAccounts.create({
data: { userId: emailUser.id, provider, providerAccountId: profile.id },
})
return emailUser
}
// Step 3: Brand new user - create both records
return db.users.create({
data: {
email: profile.email,
name: profile.name,
socialAccounts: {
create: { provider, providerAccountId: profile.id },
},
},
})
}type Permission = 'read' | 'write' | 'delete' | 'manage_users' | 'billing'
const ROLE_PERMISSIONS: Record<string, Permission[]> = {
owner: ['read', 'write', 'delete', 'manage_users', 'billing'],
admin: ['read', 'write', 'delete', 'manage_users'],
member: ['read', 'write'],
viewer: ['read'],
}
function authorize(role: string, required: Permission): boolean {
const permissions = ROLE_PERMISSIONS[role]
if (!permissions) return false
return permissions.includes(required)
}
// Middleware factory - attach to any route
function requirePermission(permission: Permission) {
return async (req: Request): Promise<void> => {
const ctx = resolveTenant(req)
if (!authorize(ctx.role, permission)) {
throw new AuthError('Insufficient permissions')
}
}
}
// Usage
// await requirePermission('manage_users')(req)
// await requirePermission('billing')(req)import { randomBytes, createHash } from 'crypto'
// Generate: show full key once, store only the hash
function generateApiKey(): { fullKey: string; hashedKey: string; prefix: string } {
const raw = randomBytes(32).toString('base64url')
const prefix = raw.slice(0, 8)
const fullKey = `sk_live_${raw}`
const hashedKey = createHash('sha256').update(fullKey).digest('hex')
return { fullKey, hashedKey, prefix }
}
// Store key with scopes and expiry
async function createApiKey(tenantId: string, name: string, scopes: string[]): Promise<string> {
const { fullKey, hashedKey, prefix } = generateApiKey()
await db.apiKeys.create({
data: { tenantId, name, hashedKey, prefix, scopes, expiresAt: addDays(new Date(), 90) },
})
return fullKey // Return ONCE - never stored in plaintext
}
// Validate incoming API key
async function validateApiKey(key: string): Promise<{ tenantId: string; scopes: string[] }> {
const hashedKey = createHash('sha256').update(key).digest('hex')
const record = await db.apiKeys.findUnique({ where: { hashedKey } })
if (!record) throw new AuthError('Invalid API key')
if (record.expiresAt < new Date()) throw new AuthError('API key expired')
if (record.revokedAt) throw new AuthError('API key revoked')
await db.apiKeys.update({ where: { id: record.id }, data: { lastUsedAt: new Date() } })
return { tenantId: record.tenantId, scopes: record.scopes }
}
// Rotation: create new key, mark old as deprecated, revoke after grace period
async function rotateApiKey(oldKeyId: string, tenantId: string): Promise<string> {
const oldKey = await db.apiKeys.findUnique({ where: { id: oldKeyId } })
if (!oldKey) throw new Error('Key not found')
const newFullKey = await createApiKey(tenantId, `${oldKey.name} (rotated)`, oldKey.scopes)
await db.apiKeys.update({ where: { id: oldKeyId }, data: { revokedAt: addDays(new Date(), 7) } })
return newFullKey
}async function sendMagicLink(email: string): Promise<void> {
const token = randomBytes(32).toString('base64url')
const hashedToken = createHash('sha256').update(token).digest('hex')
await db.magicLinks.create({
data: { email, hashedToken, expiresAt: new Date(Date.now() + 15 * 60 * 1000) }, // 15 min
})
const link = `${process.env.APP_URL}/auth/verify?token=${token}`
await sendEmail(email, 'Sign in', `Click to sign in: ${link}`)
}
async function verifyMagicLink(token: string): Promise<{ userId: string; sessionToken: string }> {
const hashedToken = createHash('sha256').update(token).digest('hex')
// Atomic: mark as used only if not already used (prevents TOCTOU race)
const result = await db.magicLinks.updateMany({
where: { hashedToken, usedAt: null, expiresAt: { gt: new Date() } },
data: { usedAt: new Date() },
})
if (result.count === 0) throw new AuthError('Invalid, expired, or already used link')
const record = await db.magicLinks.findUnique({ where: { hashedToken } })
const user = await findOrCreateUser(record.email)
const sessionToken = await createSession(user.id)
return { userId: user.id, sessionToken }
}import { authenticator } from 'otplib'
// Enrollment: generate secret, user scans QR code
async function enrollMfa(userId: string): Promise<{ secret: string; qrUri: string }> {
const secret = authenticator.generateSecret()
// SECURITY: Encrypt secret at rest in production (AES-256-GCM)
await db.mfaSecrets.create({ data: { userId, secret, verified: false } })
const qrUri = authenticator.keyuri(userId, process.env.APP_NAME ?? 'My App', secret)
return { secret, qrUri }
}
// Verify first code to activate MFA
async function activateMfa(userId: string, code: string): Promise<void> {
const record = await db.mfaSecrets.findUnique({ where: { userId } })
if (!record) throw new AuthError('MFA not enrolled')
if (!authenticator.check(code, record.secret)) {
throw new AuthError('Invalid MFA code')
}
await db.mfaSecrets.update({ where: { userId }, data: { verified: true } })
}
// Login: after password check, require MFA if enabled
async function loginWithMfa(email: string, password: string, mfaCode?: string): Promise<string> {
const user = await verifyPassword(email, password)
const mfa = await db.mfaSecrets.findUnique({ where: { userId: user.id, verified: true } })
if (mfa) {
if (!mfaCode) throw new MfaRequiredError('MFA code required')
if (!authenticator.check(mfaCode, mfa.secret)) throw new AuthError('Invalid MFA code')
}
return createSession(user.id)
}// Session with refresh token rotation
async function createSession(userId: string): Promise<{ accessToken: string; refreshToken: string }> {
const accessToken = signJwt({ sub: userId }, { expiresIn: '15m' })
const refreshToken = randomBytes(32).toString('base64url')
const hashedRefresh = createHash('sha256').update(refreshToken).digest('hex')
await db.sessions.create({
data: { userId, hashedRefreshToken: hashedRefresh, expiresAt: addDays(new Date(), 30) },
})
return { accessToken, refreshToken }
}
// Refresh: issue new pair, invalidate old refresh token (rotation)
async function refreshSession(oldRefreshToken: string): Promise<{ accessToken: string; refreshToken: string }> {
const hashed = createHash('sha256').update(oldRefreshToken).digest('hex')
const session = await db.sessions.findUnique({ where: { hashedRefreshToken: hashed } })
if (!session || session.expiresAt < new Date()) throw new AuthError('Session expired')
if (session.revokedAt) {
// Refresh token reuse detected - revoke ALL sessions for this user
await db.sessions.updateMany({ where: { userId: session.userId }, data: { revokedAt: new Date() } })
throw new AuthError('Token reuse detected, all sessions revoked')
}
// Revoke old, issue new
await db.sessions.update({ where: { id: session.id }, data: { revokedAt: new Date() } })
return createSession(session.userId)
}
// Concurrent session limit
async function enforceSessionLimit(userId: string, maxSessions: number): Promise<void> {
const activeSessions = await db.sessions.findMany({
where: { userId, revokedAt: null, expiresAt: { gt: new Date() } },
orderBy: { createdAt: 'asc' },
})
if (activeSessions.length >= maxSessions) {
const oldest = activeSessions[0]
await db.sessions.update({ where: { id: oldest.id }, data: { revokedAt: new Date() } })
}
}// BAD: localStorage is accessible to any JS on the page (XSS = full account takeover)
localStorage.setItem('token', accessToken)
fetch('/api/data', { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } })
// GOOD: httpOnly cookie - JS cannot read it, browser sends it automatically
// Server sets the cookie on login response:
function setAuthCookie(res: Response, accessToken: string): void {
res.headers.set('Set-Cookie', [
`access_token=${accessToken}`,
'HttpOnly', // JS cannot access
'Secure', // HTTPS only
'SameSite=Lax', // CSRF protection
'Path=/',
'Max-Age=900', // 15 minutes
].join('; '))
}
// Server reads from cookie, not from Authorization header:
function getTokenFromCookie(req: Request): string {
const cookies = req.headers.get('cookie') || ''
const match = cookies.match(/access_token=([^;]+)/)
if (!match) throw new AuthError('No session cookie')
return match[1]
}Core rule: Store tokens in httpOnly cookies, hash secrets before persisting, rotate keys on a schedule, and treat refresh token reuse as a breach signal. Auth is the one system where "good enough" is never good enough.
© vibeeval, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/saas-auth-patterns of vibeeval/vibecosystem.
Open the folder on GitHubat commit 3b763b1
SaaS Auth Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| SaaS Auth Patterns this skillvibeeval/vibecosystem | 531 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Supercheck Security Authsupercheck-io/supercheck | 215 | — | ~1.2k | Automated safety check: Pass | AGPL-3.0 | |
| Clerk Orgsgrowupanand/ConvoForm | 101 | — | ~5.4k | Automated safety check: Pass | MIT | |
| Reviewing Security Architecturebitwarden/ai-plugins | 154 | — | ~2.2k | Automated safety check: Pass | Custom licence | |
| Clerk Orgsgeekskai/blog | 103 | — | ~4.8k | Automated safety check: Pass | MIT | |
| Cometchat Securitycometchat/cometchat-skills | 129 | 1 repos | ~1.9k | Automated safety check: Pass | MIT |
supercheck-io/supercheck
Work on Supercheck authentication, RBAC, tenant isolation, sessions, API and trigger keys, invitations, project membership, project variables, OAuth, super-admin behavior, SSRF, or…
growupanand/ConvoForm
Clerk Organizations for B2B and multi-tenant apps - org switching, roles and permissions, verified domains, and enterprise SSO.
bitwarden/ai-plugins
This skill should be used when the user asks to "review the security architecture", "check authentication patterns", "evaluate trust boundaries", "review encryption implementation", "assess…
geekskai/blog
Clerk Organizations for B2B SaaS - create multi-tenant apps with org switching, role-based access, verified domains, and enterprise SSO.
cometchat/cometchat-skills
Enterprise auth & access control for CometChat — SSO/OIDC/SAML via your own IdP, server-minted auth tokens, token revocation & session control, and role-based access (RBAC app-wide roles + group…
NoobyGains/godmode
A skill your agent uses when writing code that processes user input, manages authentication or authorization, constructs database queries, handles file operations, interacts with external data…
vibeeval/vibecosystem
Framework for measuring and tracking agent response quality over time.
vibeeval/vibecosystem
Security-focused differential code review with blast radius analysis, risk-adaptive depth (DEEP/FOCUSED/SURGICAL), git history correlation, and structured finding format.
vibeeval/vibecosystem
A skill your agent uses when making any factual claim about the codebase — existence, absence, or behavior.
vibeeval/vibecosystem
Systematic false positive verification for security findings.
vibeeval/vibecosystem
n8n otomasyon workflow'lari. An agent skill from vibeeval/vibecosystem.
vibeeval/vibecosystem
A skill your agent uses when context compression is imminent, when resuming a session, or when preserving critical decisions across long tasks.
Categories
SaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling. SaaS Auth Patterns is an agent skill from vibeeval/vibecosystem. SaaS authentication and authorization patterns including JWT vs session strategies, multi-tenant isolation, RBAC, API key management, passwordless flows, MFA, and secure session handling.
SaaS Auth Patterns fits situations like: tasks that involve Authentication; tasks that involve Authorization and RBAC; tasks that involve Multi-tenancy.
Run `npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a claude-code`. Or copy the skill folder (skills/saas-auth-patterns in vibeeval/vibecosystem) into .claude/skills/saas-auth-patterns in your project. Claude Code loads it when a task matches its description.
Run `npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a codex`. Or copy the skill folder (skills/saas-auth-patterns in vibeeval/vibecosystem) into .agents/skills/saas-auth-patterns in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add vibeeval/vibecosystem --skill saas-auth-patterns -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/saas-auth-patterns, .gemini/skills/saas-auth-patterns, .github/skills/saas-auth-patterns and .opencode/skills/saas-auth-patterns in your project.
SKILL.md names no scripts, command-line tools or credentials: SaaS Auth Patterns is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
SaaS Auth Patterns is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with SaaS Auth Patterns: Supercheck Security Auth (supercheck-io/supercheck, 215 stars), Clerk Orgs (growupanand/ConvoForm, 101 stars), Reviewing Security Architecture (bitwarden/ai-plugins, 154 stars) and Clerk Orgs (geekskai/blog, 103 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
vibeeval (a GitHub user) maintains it in vibeeval/vibecosystem, which has 531 GitHub stars. The repository holds 144 skills in this directory. The repository was last updated on August 8, 2026.
Source: vibeeval/vibecosystem on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.