Skip to content

Commit

Permalink
feat(auth): add database integration and protected routes
Browse files Browse the repository at this point in the history
  • Loading branch information
Pulkitxm committed Oct 7, 2024
1 parent a0eaf4c commit 8d08014
Show file tree
Hide file tree
Showing 23 changed files with 639 additions and 138 deletions.
2 changes: 1 addition & 1 deletion core/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
69 changes: 4 additions & 65 deletions core/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,6 @@
import NextAuth, { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";
import NextAuth from "next-auth";
import { authOptions } from "../../../../lib/options";

const GITHUB_ID = process.env.GITHUB_ID ?? "";
const GITHUB_SECRET = process.env.GITHUB_SECRET ?? "";
const handler = NextAuth(authOptions);

export const authOptions: NextAuthOptions = {
pages: {
signIn: "null",
signOut: "null",
error: "null",
verifyRequest: "null",
newUser: "null",
},
providers: [
GithubProvider({
clientId: GITHUB_ID,
clientSecret: GITHUB_SECRET,
authorization: {
params: {
scope: "repo read:user user:email",
},
},
}),
],
callbacks: {
async signIn({ user, account, profile }) {
const db_data = {
name: profile?.name,
email: user?.email,
avatar_url: profile?.avatar_url,
bio: profile?.bio,
id: profile?.id,
access_token: account?.access_token,
};
for (const entry of Object.keys(db_data)) {
if (!db_data[entry as keyof typeof db_data]) {
return false;
}
}
return true;
},
async session({ session, token }) {
if (session.user) {
session.user.bio = token.bio as string | undefined;
session.user.avatar_url = token.avatar_url as string | undefined;
}
return session;
},
async jwt({ token, user, profile }) {
if (user) {
token.id = user.id;
token.bio = profile?.bio as string | undefined;
token.avatar_url = profile?.avatar_url as string | undefined;
token.name = user.name;
}
return token;
},
},
session: {
strategy: "jwt",
},
secret: process.env.NEXT_AUTH_SECRET,
};

export const GET = NextAuth(authOptions);
export const POST = NextAuth(authOptions);
export { handler as GET, handler as POST };
6 changes: 6 additions & 0 deletions core/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ProtectRoute from "@/components/ProtectRoute";
import React from "react";

export default async function Dashboard() {
return (await ProtectRoute()) ?? <div>page</div>;
}
2 changes: 1 addition & 1 deletion core/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function RootLayout({
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<body className="w-screen h-screen overflow-auto">
<AppWrapper>
<Navbar />
{children}
Expand Down
6 changes: 1 addition & 5 deletions core/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
"use client";

import React from "react";

export default function Page() {
export default async function Page() {
return (
<div className="w-screen h-screen flex items-center justify-center text-white"></div>
);
Expand Down
21 changes: 21 additions & 0 deletions core/components/LoginWithGithub.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";

import { signIn } from "next-auth/react";
import { Button } from "./ui/button";
import { GithubIcon } from "lucide-react";

export default function LoginWithGithub() {
const onSignin = () => {
signIn("github");
};

return (
<Button
className="w-full bg-[#24292e] hover:bg-[#2f363d] text-white"
onClick={onSignin}
>
<GithubIcon className="w-4 h-4 mr-2" />
Login with GitHub
</Button>
);
}
29 changes: 17 additions & 12 deletions core/components/Navbar/AuthButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import React from "react";
import { Button } from "../ui/button";
import { signIn, signOut, useSession } from "next-auth/react";
import Image from "next/image";
import UserDetails from "./UserDetails";
import { REDIRECT_SIGN_IN_PATH, REDIRECT_SIGN_OUT_PATH } from "@/lib/config";

const login = () => {
signIn("github", {
callbackUrl: REDIRECT_SIGN_IN_PATH || "/dashboard",
});
};

const logout = () => {
signOut({
callbackUrl: REDIRECT_SIGN_OUT_PATH || "/",
});
};

export default function AuthButtons() {
const { data: session } = useSession();
return (
<div className="flex frr">
{session ? (
<div>
<UserDetails session={session} />
<UserDetails session={session} logout={logout} />
</div>
) : (
<>
<Button size="sm" onClick={() => signIn("github")}>
<Button size="sm" onClick={login}>
Log in
</Button>
</>
Expand All @@ -28,21 +40,14 @@ export function AuthButtonsSm() {
return (
<>
{session ? (
<Button
className="w-full justify-center"
size="sm"
onClick={() => signOut()}
>
<Button className="w-full justify-center" size="sm" onClick={logout}>
Sign out
</Button>
) : (
<>
<Button variant="ghost" className="w-full justify-center" size="sm" onClick={() => signIn("github")}>
<Button className="w-full justify-center" size="sm" onClick={login}>
Log in
</Button>
<Button className="w-full justify-center" size="sm" onClick={() => signIn("github")}>
Sign up
</Button>
</>
)}
</>
Expand Down
11 changes: 8 additions & 3 deletions core/components/Navbar/UserDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ import {
import { Session } from "next-auth";
import Image from "next/image";
import { LogOut } from "lucide-react";
import { signOut } from "next-auth/react";

export default function UserDetails({ session }: { session: Session }) {
export default function UserDetails({
session,
logout,
}: {
session: Session;
logout: () => void;
}) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand All @@ -27,7 +32,7 @@ export default function UserDetails({ session }: { session: Session }) {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => signOut()}>
<DropdownMenuItem onClick={logout}>
<LogOut className="mr-2 h-4 w-4" />
<span>Logout</span>
</DropdownMenuItem>
Expand Down
79 changes: 30 additions & 49 deletions core/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@ import { Menu, X } from "lucide-react";
import ThemeToggle from "@/components/Navbar/ThemeToggle";
import AuthButtons, { AuthButtonsSm } from "./AuthButtons";

const items = [
{
name: "Home",
href: "/",
},
{
name: "Dashboard",
href: "/dashboard",
},
];

export default function Navbar() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen);
};

return (
<nav className="bg-background shadow-sm fixed top-0 left-0 right-0 z-50 border-b border-border">
<nav className="bg-background shadow-sm fixed top-0 left-0 right-0 z-50 border-b border-gray-400">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex items-center">
Expand All @@ -37,30 +48,15 @@ export default function Navbar() {
</Link>
</div>
<div className="hidden sm:flex sm:items-center sm:space-x-4">
<Link
href="/"
className="px-3 py-2 rounded-md text-sm font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Home
</Link>
<Link
href="/features"
className="px-3 py-2 rounded-md text-sm font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Features
</Link>
<Link
href="/pricing"
className="px-3 py-2 rounded-md text-sm font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Pricing
</Link>
<Link
href="/docs"
className="px-3 py-2 rounded-md text-sm font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Docs
</Link>
{items.map((item, index) => (
<Link
href={item.href}
className="px-3 py-2 rounded-md text-sm font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
key={index}
>
{item.name}
</Link>
))}
</div>
<div className="hidden sm:flex sm:items-center sm:space-x-2">
<ThemeToggle />
Expand All @@ -85,30 +81,15 @@ export default function Navbar() {
{isMenuOpen && (
<div className="sm:hidden">
<div className="px-2 pt-2 pb-3 space-y-1">
<Link
href="/"
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Home
</Link>
<Link
href="/features"
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Features
</Link>
<Link
href="/pricing"
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Pricing
</Link>
<Link
href="/docs"
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
Docs
</Link>
{items.map((item, index) => (
<Link
href={item.href}
key={index}
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-accent hover:text-accent-foreground"
>
{item.name}
</Link>
))}
<div className="mt-4 space-y-2">
<AuthButtonsSm />
</div>
Expand Down
35 changes: 35 additions & 0 deletions core/components/ProtectRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getServerSession } from "next-auth";
import React from "react";

import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import LoginWithGithub from "./LoginWithGithub";
import { authOptions } from "@/lib/options";

export default async function ProtectRoute() {
const session = await getServerSession(authOptions);
console.log("session",session);

if (!session) {
return (
<div className="w-full h-full flex items-center justify-center text-white">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Unauthorized Access</CardTitle>
<CardDescription>
You are not authorized to view this page.
</CardDescription>
</CardHeader>
<CardContent>
<LoginWithGithub />
</CardContent>
</Card>
</div>
);
}
}
Loading

0 comments on commit 8d08014

Please sign in to comment.