UNPKG

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
// 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 };