From clerk-pack
Implements Clerk sign-up/sign-in flows in Next.js with pre-built components, custom forms, and OAuth social login. Use for auth UI customization.
How this skill is triggered — by the user, by Claude, or both
Slash command
/clerk-pack:clerk-core-workflow-aThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Implement authentication flows with Clerk: pre-built components for rapid setup, custom forms for full UI control, OAuth social login, email/phone verification, and multi-factor authentication.
Implement authentication flows with Clerk: pre-built components for rapid setup, custom forms for full UI control, OAuth social login, email/phone verification, and multi-factor authentication.
clerk-install-auth completed)// app/sign-in/[[...sign-in]]/page.tsx
import { SignIn } from '@clerk/nextjs'
export default function SignInPage() {
return (
<div className="flex min-h-screen items-center justify-center">
<SignIn
appearance={{
elements: {
rootBox: 'mx-auto',
card: 'shadow-xl rounded-2xl',
headerTitle: 'text-2xl',
socialButtonsBlockButton: 'rounded-lg',
},
}}
routing="path"
path="/sign-in"
signUpUrl="/sign-up"
/>
</div>
)
}
// app/sign-up/[[...sign-up]]/page.tsx
import { SignUp } from '@clerk/nextjs'
export default function SignUpPage() {
return (
<div className="flex min-h-screen items-center justify-center">
<SignUp routing="path" path="/sign-up" signInUrl="/sign-in" />
</div>
)
}
# .env.local — routing configuration
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding
'use client'
import { useSignIn } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
export function CustomSignIn() {
const { signIn, setActive, isLoaded } = useSignIn()
const router = useRouter()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
if (!isLoaded) return null
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setError('')
setLoading(true)
try {
const result = await signIn.create({
identifier: email,
password,
})
if (result.status === 'complete') {
// Session created — activate it and redirect
await setActive({ session: result.createdSessionId })
router.push('/dashboard')
} else if (result.status === 'needs_second_factor') {
// MFA required — handled in Step 5
router.push('/sign-in/mfa')
} else if (result.status === 'needs_identifier') {
setError('Please enter your email address')
}
} catch (err: any) {
const clerkError = err.errors?.[0]
switch (clerkError?.code) {
case 'form_identifier_not_found':
setError('No account found with this email')
break
case 'form_password_incorrect':
setError('Incorrect password')
break
case 'session_exists':
router.push('/dashboard')
break
default:
setError(clerkError?.message || 'Sign-in failed')
}
} finally {
setLoading(false)
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-sm mx-auto">
<input
type="email" value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Email address" required
className="w-full p-2 border rounded"
/>
<input
type="password" value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Password" required
className="w-full p-2 border rounded"
/>
{error && <p className="text-red-500 text-sm">{error}</p>}
<button type="submit" disabled={loading} className="w-full p-2 bg-blue-600 text-white rounded">
{loading ? 'Signing in...' : 'Sign In'}
</button>
</form>
)
}
'use client'
import { useSignIn } from '@clerk/nextjs'
export function OAuthButtons() {
const { signIn, isLoaded } = useSignIn()
if (!isLoaded) return null
const signInWith = (strategy: 'oauth_google' | 'oauth_github' | 'oauth_apple') => {
signIn.authenticateWithRedirect({
strategy,
redirectUrl: '/sso-callback',
redirectUrlComplete: '/dashboard',
})
}
return (
<div className="flex flex-col gap-3">
<button onClick={() => signInWith('oauth_google')} className="p-2 border rounded">
Continue with Google
</button>
<button onClick={() => signInWith('oauth_github')} className="p-2 border rounded">
Continue with GitHub
</button>
<button onClick={() => signInWith('oauth_apple')} className="p-2 border rounded">
Continue with Apple
</button>
</div>
)
}
// app/sso-callback/page.tsx — handles OAuth redirect
import { AuthenticateWithRedirectCallback } from '@clerk/nextjs'
export default function SSOCallback() {
return <AuthenticateWithRedirectCallback />
}
'use client'
import { useSignUp } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
export function CustomSignUp() {
const { signUp, setActive, isLoaded } = useSignUp()
const router = useRouter()
const [step, setStep] = useState<'form' | 'verify'>('form')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [code, setCode] = useState('')
const [error, setError] = useState('')
if (!isLoaded) return null
const handleSignUp = async (e: React.FormEvent) => {
e.preventDefault()
try {
await signUp.create({ emailAddress: email, password })
// Send verification email
await signUp.prepareEmailAddressVerification({ strategy: 'email_code' })
setStep('verify')
} catch (err: any) {
setError(err.errors?.[0]?.longMessage || 'Sign-up failed')
}
}
const handleVerify = async (e: React.FormEvent) => {
e.preventDefault()
try {
const result = await signUp.attemptEmailAddressVerification({ code })
if (result.status === 'complete') {
await setActive({ session: result.createdSessionId })
router.push('/onboarding')
}
} catch (err: any) {
setError(err.errors?.[0]?.longMessage || 'Verification failed')
}
}
if (step === 'verify') {
return (
<form onSubmit={handleVerify} className="space-y-4">
<p>Check your email for a verification code</p>
<input
value={code} onChange={e => setCode(e.target.value)}
placeholder="Enter 6-digit code" required
/>
{error && <p className="text-red-500">{error}</p>}
<button type="submit">Verify Email</button>
</form>
)
}
return (
<form onSubmit={handleSignUp} className="space-y-4">
<input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="Email" required />
<input type="password" value={password} onChange={e => setPassword(e.target.value)} placeholder="Password" required />
{error && <p className="text-red-500">{error}</p>}
<button type="submit">Create Account</button>
</form>
)
}
'use client'
import { useSignIn } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
export function MFAVerification() {
const { signIn, setActive } = useSignIn()
const router = useRouter()
const [code, setCode] = useState('')
const [error, setError] = useState('')
const handleMFA = async (e: React.FormEvent) => {
e.preventDefault()
try {
const result = await signIn!.attemptSecondFactor({
strategy: 'totp',
code,
})
if (result.status === 'complete') {
await setActive!({ session: result.createdSessionId })
router.push('/dashboard')
}
} catch (err: any) {
setError(err.errors?.[0]?.message || 'Invalid code')
}
}
return (
<form onSubmit={handleMFA} className="space-y-4">
<h2>Two-Factor Authentication</h2>
<p>Enter the code from your authenticator app</p>
<input
value={code} onChange={e => setCode(e.target.value)}
placeholder="6-digit TOTP code" maxLength={6} required
inputMode="numeric" pattern="[0-9]*"
/>
{error && <p className="text-red-500">{error}</p>}
<button type="submit">Verify</button>
</form>
)
}
| Error | Cause | Solution |
|---|---|---|
form_identifier_not_found | Email not registered | Show sign-up link or check Clerk instance |
form_password_incorrect | Wrong password | Display error, offer password reset link |
session_exists | Already signed in | Redirect to dashboard |
verification_failed | Wrong or expired code | Allow retry; offer "Resend code" button |
oauth_callback_error | OAuth misconfigured | Check redirect URIs in Dashboard > Social Connections |
identifier_already_signed_in | Multi-session not enabled | Enable multi-session or redirect to dashboard |
appearance prop or custom CSS -- matches your design system without building from scratch<SignIn> component handles the redirect automaticallyphone_code strategy instead of email_codeemail_link strategy for passwordless authuser.created webhooks<UserProfile /> component or user.createTOTP() APIProceed to clerk-core-workflow-b for session management and middleware.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin clerk-packPre-built and custom Clerk authentication component templates with theming and customization patterns. Use when building authentication UI, creating sign-in/sign-up pages, customizing Clerk components, implementing user buttons, theming auth flows, or when user mentions Clerk components, SignIn, SignUp, UserButton, auth UI, appearance customization, or authentication theming.
Installs Clerk SDK and configures authentication for Next.js, React, or Express apps. Sets up env vars, ClerkProvider, middleware, and verifies initial auth.
Build custom sign-in/sign-up flows with useSignIn/useSignUp hooks and style Clerk components with themes, colors, fonts, and CSS.