Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auth to dashboard using NextAuth #173

Merged
merged 46 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c51ac1d
auth
Sep 20, 2023
91c8bfa
add users to data seed and add pw auth
Sep 20, 2023
5a6d8a8
update login form
Sep 20, 2023
3fbc296
add SessionProvider
Sep 20, 2023
2ad29a7
remove the provider stuff
Sep 20, 2023
63a96ce
re-add providers lol. also add all dashboard paths to middleware
Sep 20, 2023
0c6408c
add ts ignore for auth funct
Sep 20, 2023
dbc2216
re-name sessionprovider compoennt
Sep 20, 2023
8f26ee5
remove unnecessary github secret id from .env
Sep 20, 2023
6d56dd2
remove github client id form env
Sep 20, 2023
fe7f803
Update dashboard/15-final/.env
StephDietz Sep 20, 2023
193e56e
Update dashboard/15-final/app/api/auth/[...nextauth]/route.ts
StephDietz Sep 20, 2023
7888c8e
Update dashboard/15-final/package.json
StephDietz Sep 20, 2023
2659e39
resolve comments from balazs
Sep 21, 2023
4a39dfe
remove authOptions export from naxtauth
Sep 21, 2023
5d3f1bf
update lock file
Sep 21, 2023
91b04e8
update pnpm lock file
Sep 21, 2023
88944f4
Merge branch 'main' of https://github.com/vercel/next-learn into add-…
Sep 21, 2023
8402aab
update package-lock
Sep 21, 2023
5a55d4f
package json
Sep 21, 2023
9dd7189
updates
Sep 21, 2023
2d8fecd
package-lock
Sep 21, 2023
3b7b06b
Revert "resolve comments from balazs"
Sep 21, 2023
9aa6511
rever
Sep 21, 2023
7b4a9aa
lock files
Sep 21, 2023
09ec0e6
lock files again
Sep 21, 2023
018d7bd
pnpm lock
Sep 21, 2023
1be0629
remove .local from env file
Sep 21, 2023
ab4cb21
refactors
Sep 21, 2023
4de1d1e
add edge runtime
Sep 21, 2023
4ec6ccc
remove edge
Sep 21, 2023
cb3703a
debugging
Sep 21, 2023
7eb93a3
more debugging
Sep 21, 2023
d4b106e
more debugging
Sep 21, 2023
3fb81d9
test
Sep 21, 2023
963b6da
middleware change
Sep 21, 2023
3fc0914
comment out middleware
Sep 21, 2023
828f3a4
remove console logs and test middleware
Sep 22, 2023
c610bf7
test middleware
Sep 22, 2023
57a987e
test
Sep 22, 2023
ff5ee73
middleware test again
Sep 22, 2023
bcf34d6
test adding withauth
Sep 22, 2023
c8094e7
update middleware redirect
Sep 25, 2023
e8bbc49
re-add redirect in login page and not in middleware
Sep 27, 2023
f31b2ab
remove env
Sep 27, 2023
c58ad70
update gitignore at root
Sep 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions dashboard/15-final/.env

This file was deleted.

6 changes: 6 additions & 0 deletions dashboard/15-final/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import NextAuth from 'next-auth';
import { authOptions } from '@/auth';

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
7 changes: 6 additions & 1 deletion dashboard/15-final/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import LoginForm from '@/app/ui/login-form';
import { authOptions } from '@/auth';
import { getServerSession } from 'next-auth';
import { redirect } from 'next/navigation';

export default function Page() {
export default async function Page() {
const session = await getServerSession(authOptions);
StephDietz marked this conversation as resolved.
Show resolved Hide resolved
if (session) redirect('/dashboard');
StephDietz marked this conversation as resolved.
Show resolved Hide resolved
return (
<main>
<LoginForm />
Expand Down
15 changes: 15 additions & 0 deletions dashboard/15-final/app/ui/dashboard/log-out-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client';
import { PowerIcon } from '@heroicons/react/24/outline';
import { signOut } from 'next-auth/react';

export default function LogOutButton() {
return (
<button
onClick={() => signOut()}
className="flex gap-2 rounded p-2 font-semibold hover:text-blue-600"
>
<PowerIcon className="w-6" />
<div className="hidden md:block">Sign Out</div>
</button>
);
}
10 changes: 2 additions & 8 deletions dashboard/15-final/app/ui/dashboard/sidenav.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PowerIcon } from '@heroicons/react/24/outline';
import Image from 'next/image';
import Link from 'next/link';
import NavLinks from '@/app/ui/dashboard/nav-links';
import LogOutButton from './log-out-button';

export default function SideNav() {
return (
Expand All @@ -18,13 +18,7 @@ export default function SideNav() {
</Link>
<NavLinks />
</div>
<Link
href="/login"
className="flex gap-2 rounded p-2 font-semibold hover:text-blue-600"
>
<PowerIcon className="w-6" />
<div className="hidden md:block">Sign Out</div>
</Link>
<LogOutButton />
</div>
);
}
34 changes: 30 additions & 4 deletions dashboard/15-final/app/ui/login-form.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use client';

import Link from 'next/link';
import { signIn } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import BackgroundBlur from '@/app/ui/background-blur';
import React, { useState } from 'react';
import Link from 'next/link';
import Image from 'next/image';

// This component contains basic logic for a React Form.
Expand All @@ -12,11 +14,30 @@ export default function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
const [error, setError] = useState('');

const router = useRouter();

const handleSubmit = async (e: { preventDefault: () => void }) => {
e.preventDefault();
console.log(`Email: ${email}, Password: ${password}`);
};

try {
const res = await signIn('credentials', {
email,
password,
redirect: false,
});

if (res?.error) {
setError('Invalid Credentials');
return;
}

router.replace('dashboard');
} catch (error) {
console.log(error);
}
};
return (
<div className="relative mx-auto mt-40 p-4">
<BackgroundBlur />
Expand Down Expand Up @@ -64,6 +85,11 @@ export default function LoginForm() {
>
Log in
</button>
{error && (
<div className="mt-2 w-fit rounded-md bg-red-500 px-3 py-1 text-sm text-white">
{error}
</div>
)}
</div>
</form>
</div>
Expand Down
49 changes: 49 additions & 0 deletions dashboard/15-final/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import bcrypt from 'bcrypt';
import { User } from '@/app/lib/definitions';
import { sql } from '@vercel/postgres';

async function getUser(email: string) {
try {
const user = await sql`SELECT * from USERS where email=${email}`;
return user.rows[0] as User;
} catch (error) {
console.error('Failed to fetch user:', error);
throw new Error('Failed to fetch user.');
}
}

export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({
name: 'Sign-In with Credentials',
credentials: {
password: { label: 'Password', type: 'password' },
email: { label: 'Email', type: 'email' },
},
// @ts-ignore
async authorize(credentials) {
const { email, password } = credentials ?? {};
const user = await getUser(email as string);

if (!user || !password) {
console.log('Missing credentials');
return null;
}

const passwordsMatch = await bcrypt.compare(password, user.password);

if (!passwordsMatch) {
console.log('Invalid credentials');
return null;
}

return user;
},
}),
],
pages: {
signIn: '/login',
},
};
5 changes: 5 additions & 0 deletions dashboard/15-final/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default } from 'next-auth/middleware';

export const config = {
matcher: ['/dashboard/:path*'],
};
Loading
Loading