
authjs-skills
Auth.js v5 setup for Next.js authentication including Google OAuth, credentials provider, environment configuration, and core API integration
- Installs
- 792
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/gocallum/nextjs16-agent-skills --skill authjs-skills- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads authjs-skills automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Links
- Getting Started: https://authjs.dev/getting-started/installation?framework=Next.js
- Migrating to v5: https://authjs.dev/getting-started/migrating-to-v5
- Google Provider: https://authjs.dev/getting-started/providers/google
- Credentials Provider: https://authjs.dev/getting-started/providers/credentials
- Core API Reference: https://authjs.dev/reference/core
- Session Management: https://authjs.dev/getting-started/session-management
- Concepts: https://authjs.dev/concepts
Installation
pnpm add next-auth@beta
Note: Auth.js v5 is currently in beta. Use next-auth@beta to install the latest v5 version.
What's New in Auth.js v5?
Key Changes from v4
- Simplified Configuration: More streamlined setup with better TypeScript support
- Universal
auth()Export: Single function for authentication across all contexts - Enhanced Security: Improved CSRF protection and session handling
- Edge Runtime Support: Full compatibility with Edge Runtime and middleware
- Better Type Safety: Improved TypeScript definitions throughout
Environment Variables
Required Environment Variables
# Auth.js Configuration
AUTH_SECRET=your_secret_key_here
# Google OAuth (if using Google provider)
AUTH_GOOGLE_ID=your_google_client_id
AUTH_GOOGLE_SECRET=your_google_client_secret
# For production deployments
AUTH_URL=https://yourdomain.com
# For development (optional, defaults to http://localhost:3000)
# AUTH_URL=http://localhost:3000
Generating AUTH_SECRET
# Generate a random secret (Unix/Linux/macOS)
openssl rand -base64 32
# Alternative using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# Using pnpm
pnpm dlx auth secret
Important: Never commit AUTH_SECRET to version control. Use .env.local for development.
Basic Setup (Next.js App Router)
1. Create auth.ts Configuration File
Create auth.ts at the project root (next to package.json):
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
import Credentials from "next-auth/providers/credentials"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
}),
Credentials({
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
// TODO: Implement your authentication logic here
// This is a basic example - see Credentials Provider section below for complete implementation
if (!credentials?.email || !credentials?.password) {
return null
}
// Example: validate against database (placeholder)
// See "Credentials Provider" section for full implementation with bcrypt
const user = { id: "1", email: credentials.email, name: "User" } // Replace with actual DB lookup
if (!user) {
return null
}
return {
id: user.id,
email: user.email,
name: user.name,
}
},
}),
],
pages: {
signIn: '/auth/signin',
},
callbacks: {
authorized: async ({ auth }) => {
// Return true if user is authenticated
return !!auth
},
},
})
Note: This is a basic setup example. For production-ready credentials authentication, see the "Credentials Provider" section below which includes proper password hashing with bcrypt and database integration.
2. Create API Route Handler
Create app/api/auth/[...nextauth]/route.ts:
import { handlers } from "@/auth"
export const { GET, POST } = handlers
3. Add Middleware (Optional but Recommended)
Create middleware.ts at the project root:
export { auth as middleware } from "@/auth"
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
For more control:
import { auth } from "@/auth"
export default auth((req) => {
const isLoggedIn = !!req.auth
const isOnDashboard = req.nextUrl.pathname.startsWith('/dashboard')
if (isOnDashboard && !isLoggedIn) {
return Response.redirect(new URL('/auth/signin', req.url))
}
})
export const config = {
matcher: ['/dashboard/:path*', '/profile/:path*'],
}
Google OAuth Provider
1. Google Cloud Console Setup
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google+ API
- Create OAuth 2.0 credentials:
- Application type: Web application
- Authorized redirect URIs:
- Development:
http://localhost:3000/api/auth/callback/google - Production:
https://yourdomain.com/api/auth/callback/google
- Development:
- Copy Client ID and Client Secret to
.env.local
2. Configuration
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code"
}
}
}),
],
})
3. Google Provider Options
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
// Request additional scopes
authorization: {
params: {
scope: "openid email profile",
prompt: "select_account", // Force account selection
}
},
// Allow specific domains only
allowDangerousEmailAccountLinking: false,
})
Credentials Provider (Username/Password)
Required Dependencies
# Install required packages for credentials provider
pnpm add bcryptjs zod
pnpm add -D @types/bcryptjs
1. Basic Configuration
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import { z } from "zod"
import bcrypt from "bcryptjs"
import { prisma } from "@/lib/prisma"
const credentialsSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
})
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Credentials({
credentials: {
email: { label: "Email", type: "email", placeholder: "user@example.com" },
password: { label: "Password", type: "password" },
},
authorize: async (credentials) => {
try {
const { email, password } = credentialsSchema.parse(credentials)
// Fetch user from database
const user = await prisma.user.findUnique({
where: { email },
})
if (!user) {
throw new Error("User not found")
}
// Verify password
const isValidPassword = await bcrypt.compare(password, user.hashedPassword)
if (!isValidPassword) {
throw new Error("Invalid password")
}
// Return user object (must include id)
return {
id: user.id,
email: user.email,
name: user.name,
image: user.image,
}
} catch (error) {
console.error("Authentication error:", error)
return null
}
},
}),
],
session: {
strategy: "jwt", // Required for credentials provider
},
})
2. User Registration Example
// app/api/auth/register/route.ts
import { NextResponse } from "next/server"
import bcrypt from "bcryptjs"
import { z } from "zod"
import { prisma } from "@/lib/prisma"
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(2),
})
export async function POST(req: Request) {
try {
const body = await req.json()
const { email, password, name } = registerSchema.parse(body)
// Check if user exists
const existingUser = await prisma.user.findUnique({
where: { email },
})
if (existingUser) {
return NextResponse.json(
{ error: "User already exists" },
{ status: 400 }
)
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10)
// Create user
const user = await prisma.user.create({
data: {
email,
name,
hashedPassword,
},
})
return NextResponse.json(
{ message: "User created successfully", userId: user.id },
{ status: 201 }
)
} catch (error) {
console.error("Registration error:", error)
return NextResponse.json(
{ error: "Failed to register user" },
{ status: 500 }
)
}
}
Using Auth in Components
Server Components
import { auth } from "@/auth"
export default async function ProfilePage() {
const session = await auth()
if (!session?.user) {
return <div>Not authenticated</div>
}
return (
<div>
<h1>Welcome, {session.user.name}!</h1>
<p>Email: {session.user.email}</p>
</div>
)
}
Server Actions
"use server"
import { auth } from "@/auth"
import { revalidatePath } from "next/cache"
import { prisma } from "@/lib/prisma"
export async function updateProfile(formData: FormData) {
const session = await auth()
if (!session?.user) {
throw new Error("Not authenticated")
}
const name = formData.get("name") as string
// Update database
await prisma.user.update({
where: { id: session.user.id },
data: { name },
})
revalidatePath("/profile")
}
Client Components (with SessionProvider)
// app/providers.tsx
"use client"
import { SessionProvider } from "next-auth/react"
export function Providers({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>
}
// app/layout.tsx
import { Providers } from "./providers"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
// app/components/user-profile.tsx
"use client"
import { useSession, signIn, signOut } from "next-auth/react"
export function UserProfile() {
const { data: session, status } = useSession()
if (status === "loading") {
return <div>Loading...</div>
}
if (!session) {
return (
<button onClick={() => signIn()}>
Sign In
</button>
)
}
return (
<div>
<p>Signed in as {session.user?.email}</p>
<button onClick={() => signOut()}>
Sign Out
</button>
</div>
)
}
Sign In/Out Actions
Programmatic Sign In
import { signIn } from "@/auth"
// Server Action
export async function handleSignIn(provider: string) {
"use server"
await signIn(provider)
}
// With credentials
export async function handleCredentialsSignIn(formData: FormData) {
"use server"
await signIn("credentials", formData)
}
// With redirect
export async function handleGoogleSignIn() {
"use server"
await signIn("google", { redirectTo: "/dashboard" })
}
Sign In Form Component
// app/auth/signin/page.tsx
import { signIn } from "@/auth"
export default function SignInPage() {
return (
<div>
<h1>Sign In</h1>
{/* Google OAuth */}
<form
action={async () => {
"use server"
await signIn("google")
}}
>
<button type="submit">Sign in with Google</button>
</form>
{/* Credentials */}
<form
action={async (formData) => {
"use server"
await signIn("credentials", formData)
}}
>
<input name="email" type="email" placeholder="Email" required />
<input name="password" type="password" placeholder="Password" required />
<button type="submit">Sign In</button>
</form>
</div>
)
}
Sign Out
import { signOut } from "@/auth"
export default function SignOutButton() {
return (
<form
action={async () => {
"use server"
await signOut()
}}
>
<button type="submit">Sign Out</button>
</form>
)
}
Session Management
Session Strategy
Auth.js v5 supports two session strategies:
- JWT (Default): Stores session in encrypted JWT token
- Database: Stores session in database
export const { handlers, signIn, signOut, auth } = NextAuth({
session: {
strategy: "jwt", // or "database"
maxAge: 30 * 24 * 60 * 60, // 30 days
updateAge: 24 * 60 * 60, // 24 hours
},
})
Extending the Session
import NextAuth from "next-auth"
import type { DefaultSession } from "next-auth"
declare module "next-auth" {
interface Session {
user: {
id: string
role: string
} & DefaultSession["user"]
}
}
export const { handlers, signIn, signOut, auth } = NextAuth({
callbacks: {
jwt({ token, user }) {
if (user) {
token.id = user.id
token.role = user.role
}
return token
},
session({ session, token }) {
if (session.user) {
session.user.id = token.id as string
session.user.role = token.role as string
}
return session
},
},
})
Callbacks
Essential Callbacks
export const { handlers, signIn, signOut, auth } = NextAuth({
callbacks: {
// Called when user signs in
async signIn({ user, account, profile }) {
// Return true to allow sign in, false to deny
// Example: Check if email is verified
if (account?.provider === "google") {
return profile?.email_verified === true
}
return true
},
// Called whenever a JWT is created or updated
async jwt({ token, user, account }) {
if (user) {
token.id = user.id
}
if (account) {
token.accessToken = account.access_token
}
return token
},
// Called whenever a session is checked
async session({ session, token }) {
session.user.id = token.id as string
session.accessToken = token.accessToken as string
return session
},
// Called on middleware and server-side auth checks
async authorized({ auth, request }) {
const isLoggedIn = !!auth?.user
const isOnDashboard = request.nextUrl.pathname.startsWith("/dashboard")
if (isOnDashboard) {
return isLoggedIn
}
return true
},
// Called when user is redirected
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
if (url.startsWith("/")) return `${baseUrl}${url}`
// Allows callback URLs on the same origin
else if (new URL(url).origin === baseUrl) return url
return baseUrl
},
},
})
Database Adapter (Optional)
For persisting users, accounts, and sessions in a database, install the Prisma adapter:
pnpm add @auth/prisma-adapter
Then configure it in your auth.ts:
import NextAuth from "next-auth"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/lib/prisma"
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
session: {
strategy: "database",
},
providers: [
// ... providers
],
})
Required Prisma schema:
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
API Routes
Custom API Endpoints
// app/api/user/route.ts
import { auth } from "@/auth"
import { NextResponse } from "next/server"
export async function GET() {
const session = await auth()
if (!session?.user) {
return NextResponse.json(
{ error: "Unauthorized" },
{ status: 401 }
)
}
return NextResponse.json({
user: session.user,
})
}
Protected Route Helper
// lib/auth-helpers.ts
import { auth } from "@/auth"
import { NextResponse } from "next/server"
import type { Session } from "next-auth"
export async function withAuth(
handler: (session: Session) => Promise<NextResponse>
) {
const session = await auth()
if (!session?.user) {
return NextResponse.json(
{ error: "Unauthorized" },
{ status: 401 }
)
}
return handler(session)
}
// Usage
export async function GET() {
return withAuth(async (session) => {
return NextResponse.json({ userId: session.user.id })
})
}
Best Practices
Security
- Always hash passwords: Use bcrypt, argon2, or similar
- Use HTTPS in production: Required for secure cookie transmission
- Validate environment variables: Check AUTH_SECRET and provider credentials
- Set secure cookie options:
cookies: { sessionToken: { name: `__Secure-next-auth.session-token`, options: { httpOnly: true, sameSite: 'lax', path: '/', secure: process.env.NODE_ENV === 'production', }, }, } - Implement rate limiting: Protect sign-in endpoints
- Use CSRF protection: Enabled by default in v5
- Validate redirects: Use the
redirectcallback to prevent open redirects
Session Management
- Use appropriate maxAge: Default 30 days, adjust based on security requirements
- Update sessions regularly: Use
updateAgeto refresh session data - Handle session expiry gracefully: Provide clear UI feedback
- Secure session storage: Use database strategy for sensitive applications
Provider Configuration
- Google OAuth: Request minimum required scopes
- Credentials: Always validate input with zod or similar
- Multiple providers: Allow account linking carefully
- Provider-specific logic: Use callbacks to handle provider differences
Performance
- Cache session checks: Use middleware for route protection
- Minimize database calls: Use JWT strategy when appropriate
- Optimize database queries: Add indexes on frequently queried fields
- Use Edge Runtime: For faster authentication checks in middleware
Type Safety
- Extend types properly: Use module augmentation for custom session fields
- Validate inputs: Use zod for runtime type checking
- TypeScript strict mode: Enable for better type safety
Common Patterns
Protected Pages with Middleware
import { auth } from "@/auth"
import { NextResponse } from "next/server"
export default auth((req) => {
const isLoggedIn = !!req.auth
const { pathname } = req.nextUrl
// Public routes
const publicRoutes = ['/auth/signin', '/auth/register', '/']
if (publicRoutes.includes(pathname)) {
return NextResponse.next()
}
// Protected routes
if (!isLoggedIn) {
const signInUrl = new URL('/auth/signin', req.url)
signInUrl.searchParams.set('callbackUrl', pathname)
return NextResponse.redirect(signInUrl)
}
// Role-based access
const adminRoutes = ['/admin']
if (adminRoutes.some(route => pathname.startsWith(route))) {
if (req.auth.user.role !== 'admin') {
return NextResponse.redirect(new URL('/unauthorized', req.url))
}
}
return NextResponse.next()
})
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}
Multi-Provider Setup
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
import GitHub from "next-auth/providers/github"
import Credentials from "next-auth/providers/credentials"
import { prisma } from "@/lib/prisma"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
}),
GitHub({
clientId: process.env.AUTH_GITHUB_ID,
clientSecret: process.env.AUTH_GITHUB_SECRET,
}),
Credentials({
// ... credentials config
}),
],
callbacks: {
async signIn({ user, account, profile }) {
// Link accounts with same email
if (account?.provider !== "credentials") {
const existingUser = await prisma.user.findUnique({
where: { email: user.email },
})
if (existingUser) {
// Link account to existing user
await prisma.account.create({
data: {
userId: existingUser.id,
type: account.type,
provider: account.provider,
providerAccountId: account.providerAccountId,
access_token: account.access_token,
refresh_token: account.refresh_token,
},
})
}
}
return true
},
},
})
Custom Sign In Page
// app/auth/signin/page.tsx
import { signIn } from "@/auth"
import { redirect } from "next/navigation"
export default function SignInPage({
searchParams,
}: {
searchParams: { callbackUrl?: string }
}) {
const callbackUrl = searchParams.callbackUrl || "/dashboard"
return (
<div className="flex min-h-screen items-center justify-center">
<div className="w-full max-w-md space-y-8 p-8">
<h1 className="text-2xl font-bold text-center">Sign In</h1>
{/* OAuth Providers */}
<div className="space-y-4">
<form
action={async () => {
"use server"
await signIn("google", { redirectTo: callbackUrl })
}}
>
<button
type="submit"
className="w-full bg-white border border-gray-300 text-gray-700 py-2 px-4 rounded hover:bg-gray-50"
>
Continue with Google
</button>
</form>
</div>
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300" />
</div>
<div className="relative flex justify-center text-sm">
<span className="bg-white px-2 text-gray-500">Or</span>
</div>
</div>
{/* Credentials Form */}
<form
action={async (formData) => {
"use server"
try {
await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirectTo: callbackUrl,
})
} catch (error) {
redirect(`/auth/signin?error=CredentialsSignin&callbackUrl=${callbackUrl}`)
}
}}
className="space-y-4"
>
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email
</label>
<input
id="email"
name="email"
type="email"
required
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
</label>
<input
id="password"
name="password"
type="password"
required
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md"
/>
</div>
<button
type="submit"
className="w-full bg-blue-600 text-white py-2 px-4 rounded hover:bg-blue-700"
>
Sign In
</button>
</form>
</div>
</div>
)
}
Role-Based Access Control (RBAC)
// lib/auth-rbac.ts
import { auth } from "@/auth"
export type Role = "admin" | "user" | "guest"
export async function checkRole(allowedRoles: Role[]) {
const session = await auth()
if (!session?.user) {
return false
}
const userRole = session.user.role as Role
return allowedRoles.includes(userRole)
}
// Usage in Server Component
export default async function AdminPage() {
const hasAccess = await checkRole(["admin"])
if (!hasAccess) {
redirect("/unauthorized")
}
return <div>Admin Dashboard</div>
}
// Usage in Server Action
export async function deleteUser(userId: string) {
"use server"
const hasAccess = await checkRole(["admin"])
if (!hasAccess) {
throw new Error("Unauthorized")
}
const { prisma } = await import("@/lib/prisma")
await prisma.user.delete({ where: { id: userId } })
}
Migration from v4 to v5
Key Differences
- Import changes:
next-authpackage remains the same, but imports are simplified - Universal
auth(): ReplacegetServerSessionwithauth() - Middleware: Use
authas middleware directly - Configuration: More streamlined, fewer options needed
Migration Steps
// v4 (old)
import { getServerSession } from "next-auth/next"
import { authOptions } from "@/lib/auth"
export async function GET() {
const session = await getServerSession(authOptions)
}
// v5 (new)
import { auth } from "@/auth"
export async function GET() {
const session = await auth()
}
// v4 middleware (old)
import { withAuth } from "next-auth/middleware"
export default withAuth({
callbacks: {
authorized: ({ token }) => !!token,
},
})
// v5 middleware (new)
export { auth as middleware } from "@/auth"
Troubleshooting
Common Issues
AUTH_SECRET not set:
Error: AUTH_SECRET environment variable is not set
Generate and set AUTH_SECRET in .env.local
Google OAuth redirect mismatch:
Error: redirect_uri_mismatch
Ensure redirect URI in Google Console matches: http://localhost:3000/api/auth/callback/google
Session not persisting:
- Check
AUTH_URLis set correctly - Verify cookies are not blocked
- Ensure
sessionTokencookie is being set (check browser DevTools)
TypeScript errors with session:
- Extend the
SessionandJWTtypes using module augmentation - Run
pnpm tsc --noEmitto check for type errors
Credentials provider not working:
- Ensure
session.strategyis set to"jwt" - Check
authorizefunction returns correct user object withidfield - Verify password hashing/comparison logic
Resources
- Official Docs: https://authjs.dev
- GitHub: https://github.com/nextauthjs/next-auth
- Discord Community: https://discord.gg/nextauth
- Examples: https://github.com/nextauthjs/next-auth/tree/main/apps/examples
- Provider List: https://authjs.dev/getting-started/providers
FAQ
What does the authjs-skills skill do?
Auth.js v5 setup for Next.js authentication including Google OAuth, credentials provider, environment configuration, and core API integration
How do I install authjs-skills?
Run npx skills add https://github.com/gocallum/nextjs16-agent-skills --skill authjs-skills in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/authjs-skills/ (personal) or .claude/skills/authjs-skills/ (project).
Which AI agents can use authjs-skills?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is authjs-skills safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains authjs-skills?
It is published by gocallum in gocallum/nextjs16-agent-skills. It has 792 recorded installs.
More from gocallum/nextjs16-agent-skills
prisma-orm-v7-skills
gocallum/nextjs16-agent-skills
Key facts and breaking changes for upgrading to Prisma ORM 7. Consider version 7 changes before generation or troubleshooting
nextjs16-skills
gocallum/nextjs16-agent-skills
Key facts and links for Next.js 16. Use for planning, writing, and troubleshooting Next.js 16 changes.
ai-sdk-6-skills
gocallum/nextjs16-agent-skills
AI SDK 6 Beta overview, agents, tool approval, Groq (Llama), and Vercel AI Gateway. Key breaking changes from v5 and new patterns.
clerk-nextjs-skills
gocallum/nextjs16-agent-skills
Open the skill to read its SKILL.md instructions.
resend-integration-skills
gocallum/nextjs16-agent-skills
Open the skill to read its SKILL.md instructions.
mcp-server-skills
gocallum/nextjs16-agent-skills
Open the skill to read its SKILL.md instructions.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.