Authentication: Building Login Features
Learning Objectives
- Understand what Authentication is
- Implement login functionality with Supabase Auth
- Integrate social login (Google, GitHub)
- Control page access based on login status
3.1 What is Authentication?
Authentication vs Authorization
| Concept | Meaning | Example |
|---|---|---|
| Authentication | Verify "who you are" | Login |
| Authorization | Verify "what you can do" | Only admins can delete |
Why Not Build It Yourself?
Building authentication yourself requires considering too many things:
- Password encryption (hashing, salting)
- Session/token management
- Security vulnerability prevention (CSRF, XSS)
- Password recovery, email verification...
That's why we use services like Supabase Auth. It's free and already security-verified.
3.2 Magic Link Login
Magic Link is a passwordless login via email. Click the link and you're logged in.
Creating Login Page
Create a login page.
- Email input field
- "Send Login Link" button
- Use Supabase Auth's Magic Link
- Show loading state and success messageHow It Works
- User enters email
- Supabase sends login link to email
- User clicks link
- Automatically logged in → Navigate to dashboard
// Magic Link login request
const { error } = await supabase.auth.signInWithOtp({
email: email,
options: {
emailRedirectTo: window.location.origin + '/dashboard'
}
})3.3 Social Login Integration
Adding social logins like Google and GitHub makes it easier for users to sign up.
Google Login Setup
Google Cloud Console Setup
- Go to Google Cloud Console (console.cloud.google.com)
- Create new project
- APIs & Services → Credentials → Create Credentials → OAuth client ID
- Select Web application
- Add to Authorized redirect URIs:
https://[projectID].supabase.co/auth/v1/callback - Copy Client ID and Secret
Supabase Integration
- Supabase Dashboard → Auth → Providers → Google → Enable and enter keys
GitHub Login Setup
- GitHub Settings → Developer settings → OAuth Apps → New OAuth App
- Authorization callback URL:
https://[projectID].supabase.co/auth/v1/callback - Copy Client ID and Secret
- Enable GitHub Provider in Supabase
Adding Social Login Buttons
Add Google and GitHub social login buttons to the login page.
Use Supabase Auth's signInWithOAuth.
Style buttons with each brand's colors.// Google login
await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: window.location.origin + '/dashboard' }
})
// GitHub login
await supabase.auth.signInWithOAuth({
provider: 'github',
options: { redirectTo: window.location.origin + '/dashboard' }
})3.4 Managing Login State
Checking Current User
// Get currently logged in user
const { data: { user } } = await supabase.auth.getUser()
if (user) {
console.log('Logged in:', user.email)
} else {
console.log('Not logged in')
}Modifying Header Component
Modify the header.
- If not logged in: "Login" button
- If logged in: user email, profile icon, "Logout" button
Check Supabase session to handle this.Implementing Logout
const handleLogout = async () => {
await supabase.auth.signOut()
router.push('/') // Navigate to home
}3.5 Page Access Control
Dashboard should only be accessible to logged-in users.
Protecting with Middleware
Create Next.js middleware:
- All pages starting with /dashboard require login
- If not logged in, redirect to /login
- If already logged in and going to /login, redirect to /dashboard
Check Supabase session to handle this.3.6 Row Level Security (RLS)
RLS is a feature that enforces "access only your own data" at the database level.
Why Is It Needed?
Even if you check user_id on the frontend, malicious users can access other people's data by calling the API directly. RLS blocks this at the database.
Setting Up RLS Policies
Run in Supabase SQL Editor:
-- Enable RLS on profiles table
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- Profiles are publicly viewable (for public profile pages)
CREATE POLICY "Profiles are publicly viewable"
ON profiles FOR SELECT
USING (true);
-- Can only create own profile
CREATE POLICY "Users can create own profile"
ON profiles FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Can only update own profile
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
USING (auth.uid() = user_id);
-- Enable RLS on links table
ALTER TABLE links ENABLE ROW LEVEL SECURITY;
-- Links are publicly viewable (for public profile pages)
CREATE POLICY "Links are publicly viewable"
ON links FOR SELECT
USING (true);
-- Can only create links for own profile
CREATE POLICY "Users can create own links"
ON links FOR INSERT
WITH CHECK (profile_id IN (
SELECT id FROM profiles WHERE user_id = auth.uid()
));
-- Can only update/delete own links
CREATE POLICY "Users can update own links"
ON links FOR UPDATE
USING (profile_id IN (
SELECT id FROM profiles WHERE user_id = auth.uid()
));
CREATE POLICY "Users can delete own links"
ON links FOR DELETE
USING (profile_id IN (
SELECT id FROM profiles WHERE user_id = auth.uid()
));What is auth.uid()?
auth.uid() is a Supabase function that returns the currently logged-in user's ID. Returns null if not logged in.
3.7 Other Authentication Options
Besides Supabase Auth, there are other authentication services suitable for vibe coding.
Options Comparison
| Service | Features | Free Tier | Recommended For |
|---|---|---|---|
| Supabase Auth | DB integrated, RLS support | Unlimited MAU | When using Supabase DB |
| Clerk | Easiest, provides components | 10,000 MAU | Quick implementation |
| Auth.js | Open source, flexible | Free (self-hosted) | Need customization |
| Firebase Auth | Google ecosystem | Unlimited | When using Firebase DB |
| Lucia | Lightweight, type-safe | Free (self-hosted) | Want direct control |
| Kinde | Fast setup, B2B features | 7,500 MAU | Need enterprise features |
Clerk
The easiest authentication solution. Even provides UI components.
Implement authentication with Clerk.
Use @clerk/nextjs package.
Include social login (Google, GitHub).// Clerk usage example
import { SignIn, SignUp, UserButton } from '@clerk/nextjs';
// Login page
export default function LoginPage() {
return <SignIn />;
}
// User button in header
<UserButton afterSignOutUrl="/" />Clerk's Advantages
- Auto-generate UI with
<SignIn />,<SignUp />components - Protect pages with one line of middleware
- Provides user management dashboard
Auth.js (NextAuth.js)
Open source and most flexible. Supports various Providers.
Implement authentication with Auth.js (NextAuth).
Use next-auth package.
Include Google, GitHub, email login.
Store sessions in DB with Prisma adapter.// Auth.js setup example
import NextAuth from 'next-auth';
import Google from 'next-auth/providers/google';
import GitHub from 'next-auth/providers/github';
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [Google, GitHub],
});Firebase Auth
Natural choice if you're using Google ecosystem.
Implement authentication with Firebase Auth.
Use firebase package.
Include Google, GitHub social login.Lucia
Lightweight and type-safe authentication library. Good when you need direct control.
Implement authentication with Lucia.
Use lucia package.
Store sessions in Supabase.Which One Should You Choose?
| Situation | Recommendation |
|---|---|
| Using Supabase DB | Supabase Auth |
| Want quickest implementation | Clerk |
| Need full customization | Auth.js |
| Using Firebase DB | Firebase Auth |
| Want lightweight, direct control | Lucia |
| B2B SaaS, need organization management | Kinde |
Vibe Coding Tip
Authentication is hard to change later. Choose carefully from the start. If unsure, recommend Supabase Auth (DB integrated) or Clerk (easiest).
Chapter Summary
- Understood the difference between authentication and authorization
- Implemented Magic Link email login
- Integrated Google, GitHub social login
- Changed UI based on login status
- Protected pages with middleware
- Controlled data access with RLS
- Learned about various authentication options
In the next chapter, we'll implement real-time communication.