25
loading...
This website collects cookies to deliver better user experience
npx create-next-app@latest --ts nextjs-supabase
, supabase-nextjs is the app’s name, so it can be anything you want to name your app.npx create-next-app@latest --ts nextjs-supabase
npm install -D tailwindcss postcss autoprefixer
tailwind.config.js
and postcss.config.js
configuration file by running:npx tailwindcss init -p
tailwind.config.js
:// tailwind.config.js
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
styles/global.css
file replace the content by the following code:@tailwind base;
@tailwind components;
@tailwind utilities;
npm install @supabase/supabase-js
.env.local
file:NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
src/utils/SupabaseClient.ts
:import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || "";
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "";
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
const { error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/signin');
}
supabase.auth.signUp()
function accepts the email and password of the user. Then, if the user is successfully created, the user is notified and redirected to the sign in page.pages/signup.tsx
file and paste the following code:import React, { useState } from 'react';
import { useRouter } from 'next/router';
import { supabase } from '../src/utils/SupabaseClient';
const SignUp = () => {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/signin');
}
};
return (
<div className="h-screen flex items-center justify-center bg-gray-800">
<div className="max-w-lg w-full">
<h1 className="text-3xl font-semibold text-center text-white">
Create new account
</h1>
<form className="mt-2 flex flex-col p-6" onSubmit={handleSubmit}>
<label htmlFor="email" className="text-gray-200">
Email
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<label htmlFor="password" className="mt-6 text-gray-200">
Password
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
className="mt-10 text-lg text-white font-semibold bg-green-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
type="submit"
>
Sign up
</button>
</form>
</div>
</div>
);
};
export default SignUp;
const { error } = await supabase.auth.signIn({
email,
password,
});
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/dashboard');
}
supabase.auth.signIn()
function verifies if the user has an account and makes sure that only verified user has access to the dashboard page. When the user is successfully authenticated, it redirects the user to the protected dashboard page.pages/signin.tsx
file:import React, { useState } from 'react';
import { useRouter } from 'next/router';
import { supabase } from '../src/utils/SupabaseClient';
const SignIn = () => {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSignIn = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await supabase.auth.signIn({
email,
password,
});
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/dashboard');
}
};
return (
<div className="h-screen flex items-center justify-center bg-gray-800">
<div className="max-w-lg w-full">
<h1 className="text-3xl font-semibold text-center text-white">
Sign in to your account
</h1>
<div className="flex flex-col p-6">
<form className="flex flex-col" onSubmit={handleSignIn}>
<label htmlFor="email" className="text-gray-200">
Email
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<label htmlFor="password" className="mt-6 text-gray-200">
Password
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
className="mt-10 text-lg text-white font-semibold bg-green-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
type="submit"
>
Sign in with Email
</button>
</form>
</div>
</div>
</div>
);
};
export default SignIn;
pages/dashboard.tsx
:import React, { MouseEventHandler, useEffect, useState } from 'react';
import { User } from '@supabase/supabase-js';
import { useRouter } from 'next/router';
import { supabase } from '../src/utils/SupabaseClient';
const Dashboard = () => {
const router = useRouter();
const [user, setUser] = useState<User | null>();
const handleLogOut: MouseEventHandler = async (e) => {
e.preventDefault();
const { error } = await supabase.auth.signOut();
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/signin');
}
};
useEffect(() => {
const getProfile = () => {
const profile = supabase.auth.user();
if (profile) {
setUser(profile);
} else {
router.push('/signin');
}
};
getProfile();
}, []);
if (!user) {
// Currently loading asynchronously User Supabase Information
return null;
}
return (
<div className="h-screen flex items-center justify-center bg-gray-800">
<div className="max-w-lg w-full text-center">
<h1 className="text-2xl font-semibold text-white">
Welcome, your email is {user.email}
</h1>
<button
className="mt-6 text-lg text-white font-semibold bg-green-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
onClick={handleLogOut}
>
Log out
</button>
</div>
</div>
);
};
export default Dashboard;
supabase.auth.user()
contains the user's details if a user is logged in, these details are available for use everywhere in your application. The function supabase.auth.signOut()
enable users to logged out of the application. The useEffect
function redirects the user to the login page if he/she is not signed in.pages/signin.tsx
for social auth with GitHub. But you can replace by any other third-party login system like Google, Apple, Facebook, Twitter etc.const handleSignInWithGitHub: MouseEventHandler = async (e) => {
e.preventDefault();
const { error } = await supabase.auth.signIn(
{
provider: 'github',
},
{
redirectTo: 'http://localhost:3000/callback/',
}
);
if (error) {
alert(JSON.stringify(error));
}
};
render
function, you also need to add the GitHub social button:<button
className="text-lg text-white font-semibold bg-blue-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
onClick={handleSignInWithGitHub}
>
Sign In with GitHub
</button>
<hr className="bg-gray-600 border-0 h-px my-8" />
pages/callback.tsx
to handle this:import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { supabase } from '../src/utils/SupabaseClient';
const Callback = () => {
const router = useRouter();
useEffect(() => {
const { data: authListener } = supabase.auth.onAuthStateChange(
(event, sessionState) => {
if (sessionState?.user) {
router.push('/dashboard');
}
}
);
return () => {
authListener?.unsubscribe();
};
}, []);
return null;
};
export default Callback;
import React, { MouseEventHandler, useState } from 'react';
import { useRouter } from 'next/router';
import { supabase } from '../src/utils/SupabaseClient';
const SignIn = () => {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSignIn = async (e: React.FormEvent) => {
e.preventDefault();
const { error } = await supabase.auth.signIn({
email,
password,
});
if (error) {
alert(JSON.stringify(error));
} else {
router.push('/dashboard');
}
};
const handleSignInWithGitHub: MouseEventHandler = async (e) => {
e.preventDefault();
const { error } = await supabase.auth.signIn(
{
provider: 'github',
},
{
redirectTo: 'http://localhost:3000/callback/',
}
);
if (error) {
alert(JSON.stringify(error));
}
};
return (
<div className="h-screen flex items-center justify-center bg-gray-800">
<div className="max-w-lg w-full">
<h1 className="text-3xl font-semibold text-center text-white">
Sign in to your account
</h1>
<div className="flex flex-col p-6">
<button
className="text-lg text-white font-semibold bg-blue-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
onClick={handleSignInWithGitHub}
>
Sign In with GitHub
</button>
<hr className="bg-gray-600 border-0 h-px my-8" />
<form className="flex flex-col" onSubmit={handleSignIn}>
<label htmlFor="email" className="text-gray-200">
Email
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<label htmlFor="password" className="mt-6 text-gray-200">
Password
</label>
<input
className="py-2 px-4 rounded-md focus:outline-none focus:ring-2"
type="password"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
className="mt-10 text-lg text-white font-semibold bg-green-500 py-3 px-6 rounded-md focus:outline-none focus:ring-2"
type="submit"
>
Sign in with Email
</button>
</form>
</div>
</div>
</div>
);
};
export default SignIn;