Skip to content

Commit

Permalink
feat: implemented complete GitHub authentication with session handlin…
Browse files Browse the repository at this point in the history
…g and JWT
  • Loading branch information
Pulkitxm committed Oct 6, 2024
1 parent 4ac8bb9 commit a0eaf4c
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 36 deletions.
2 changes: 0 additions & 2 deletions core/.env

This file was deleted.

57 changes: 53 additions & 4 deletions core/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,67 @@
import NextAuth from "next-auth";
import NextAuth, { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";

const GITHUB_ID = process.env.GITHUB_ID ?? "";
const GITHUB_SECRET = process.env.GITHUB_SECRET ?? "";

export const 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 const POST = NextAuth(authOptions);
12 changes: 3 additions & 9 deletions core/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
"use client";

import { signIn, useSession } from "next-auth/react";
import React from "react";

export default function Page() {
const session = useSession();
console.log(session);

if (!session.data) {
return <button onClick={() => signIn()}>Signin</button>;
}

return <div></div>;
return (
<div className="w-screen h-screen flex items-center justify-center text-white"></div>
);
}
50 changes: 50 additions & 0 deletions core/components/Navbar/AuthButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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";

export default function AuthButtons() {
const { data: session } = useSession();
return (
<div className="flex frr">
{session ? (
<div>
<UserDetails session={session} />
</div>
) : (
<>
<Button size="sm" onClick={() => signIn("github")}>
Log in
</Button>
</>
)}
</div>
);
}

export function AuthButtonsSm() {
const { data: session } = useSession();
return (
<>
{session ? (
<Button
className="w-full justify-center"
size="sm"
onClick={() => signOut()}
>
Sign out
</Button>
) : (
<>
<Button variant="ghost" className="w-full justify-center" size="sm" onClick={() => signIn("github")}>
Log in
</Button>
<Button className="w-full justify-center" size="sm" onClick={() => signIn("github")}>
Sign up
</Button>
</>
)}
</>
);
}
File renamed without changes.
37 changes: 37 additions & 0 deletions core/components/Navbar/UserDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
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 }) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Image
src={session.user?.image || ""}
alt="user image"
width={40}
height={40}
className="rounded-full"
/>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => signOut()}>
<LogOut className="mr-2 h-4 w-4" />
<span>Logout</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
24 changes: 4 additions & 20 deletions core/components/Navbar.tsx → core/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import { useState } from "react";
import Link from "next/link";
import { Menu, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import ThemeToggle from "@/components/ui/ThemeToggle";
import { signIn } from "next-auth/react";
import ThemeToggle from "@/components/Navbar/ThemeToggle";
import AuthButtons, { AuthButtonsSm } from "./AuthButtons";

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

const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen);
};
Expand Down Expand Up @@ -66,12 +64,7 @@ export default function Navbar() {
</div>
<div className="hidden sm:flex sm:items-center sm:space-x-2">
<ThemeToggle />
<Button variant="ghost" size="sm">
Log in
</Button>
<Button size="sm" onClick={() => signIn()}>
Sign up
</Button>
<AuthButtons />
</div>
<div className="flex items-center sm:hidden">
<ThemeToggle />
Expand Down Expand Up @@ -117,16 +110,7 @@ export default function Navbar() {
Docs
</Link>
<div className="mt-4 space-y-2">
<Button
variant="ghost"
className="w-full justify-center"
size="sm"
>
Log in
</Button>
<Button className="w-full justify-center" size="sm">
Sign up
</Button>
<AuthButtonsSm />
</div>
</div>
</div>
Expand Down
13 changes: 12 additions & 1 deletion core/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "avatars.githubusercontent.com",
port: "",
pathname: "/u/**",
},
],
},
};

export default nextConfig;
20 changes: 20 additions & 0 deletions core/types/nat-auth.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import "next-auth";

declare module "next-auth" {
interface User {
id: string;
}

interface Profile {
bio: string;
avatar_url: string;
id: string;
}

interface Session {
user: User & {
bio?: string;
avatar_url?: string;
};
}
}

0 comments on commit a0eaf4c

Please sign in to comment.