create-filip-app
Version:
A modern CLI tool for creating Next.js applications with best practices, shadcn components, and MongoDB integration.
218 lines (195 loc) • 7.6 kB
JavaScript
// auth.ts configuration file for next-auth
const authConfig = `import { NextAuthOptions } from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"
import { MongoDBAdapter } from "@auth/mongodb-adapter"
import { clientPromise } from "@/lib/mongodb"
export const authOptions: NextAuthOptions = {
adapter: MongoDBAdapter(clientPromise),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
}),
GitHubProvider({
clientId: process.env.GITHUB_ID as string,
clientSecret: process.env.GITHUB_SECRET as string,
}),
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" }
},
async authorize(credentials) {
// This is where you would validate the user's credentials
// For example, you could check against a database
// For demo purposes, we're just checking if the email contains "user"
// and the password contains "pass"
if (credentials.email.includes("user") && credentials.password.includes("pass")) {
return {
id: "1",
name: "Demo User",
email: credentials.email,
}
}
// Return null if credentials are invalid
return null
}
}),
],
pages: {
signIn: '/auth/signin',
signOut: '/auth/signout',
error: '/auth/error',
},
callbacks: {
async session({ session, token }) {
if (token) {
session.user.id = token.id
session.user.role = token.role
}
return session
},
async jwt({ token, user }) {
// Initial sign in
if (user) {
token.id = user.id
token.role = user.role || "user"
}
return token
}
},
session: {
strategy: "jwt",
},
secret: process.env.NEXTAUTH_SECRET,
}`;
// auth.ts route handler for app router
const authRouteHandler = `import NextAuth from "next-auth"
import { authOptions } from "@/lib/auth"
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }`;
// Example SignIn page with form
const signInPage = `"use client"
import { useState } from "react"
import { signIn } from "next-auth/react"
import { useRouter } from "next/navigation"
import { Github, Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
export default function SignIn() {
const router = useRouter()
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState("")
async function handleSubmit(e) {
e.preventDefault()
setIsLoading(true)
setError("")
const result = await signIn("credentials", {
email,
password,
redirect: false,
})
setIsLoading(false)
if (result?.error) {
setError("Invalid credentials")
} else {
router.push("/")
router.refresh()
}
}
return (
<div className="flex justify-center items-center min-h-screen bg-muted/40">
<Card className="w-full max-w-md shadow-lg">
<CardHeader className="space-y-1">
<CardTitle className="text-2xl font-bold">Sign in</CardTitle>
<CardDescription>Choose your preferred sign in method</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<Button variant="outline" onClick={() => signIn("github", { callbackUrl: "/" })}>
<Github className="mr-2 h-4 w-4" />
GitHub
</Button>
<Button variant="outline" onClick={() => signIn("google", { callbackUrl: "/" })}>
<svg xmlns="http://www.w3.org/2000/svg" className="mr-2 h-4 w-4" viewBox="0 0 48 48">
<path fill="#FFC107" d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"></path>
<path fill="#FF3D00" d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"></path>
<path fill="#4CAF50" d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"></path>
<path fill="#1976D2" d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"></path>
</svg>
Google
</Button>
</div>
<div className="flex items-center">
<Separator className="flex-1" />
<span className="mx-2 text-xs text-muted-foreground">OR</span>
<Separator className="flex-1" />
</div>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="your@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p className="text-sm text-red-500">{error}</p>}
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "Signing in..." : "Sign in with Email"}
</Button>
</form>
</CardContent>
<CardFooter className="flex flex-col items-center justify-center text-xs text-muted-foreground">
<p>Demo credentials: user@example.com / password</p>
<p className="mt-1">This is a demo application. Do not use real credentials.</p>
</CardFooter>
</Card>
</div>
)
}`
// Properly typed AuthProvider component
const authProviderContent = `"use client"
import { SessionProvider } from "next-auth/react"
import { ReactNode } from "react"
type AuthProviderProps = {
children: ReactNode;
}
export function AuthProvider({ children }: AuthProviderProps) {
return (
<SessionProvider
// Force refetch session when window focused to prevent stale session
refetchInterval={0}
refetchOnWindowFocus={true}
>
{children}
</SessionProvider>
)
}`
export {
authConfig,
authRouteHandler,
signInPage,
authProviderContent
};