-
Notifications
You must be signed in to change notification settings - Fork 0
Add auth #6
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 #6
Changes from 3 commits
9d7a385
52ae4fd
c227001
6b14ba6
224f1e9
115a954
50448d8
235fab5
1345ce8
851c89a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { NextResponse } from "next/server"; | ||
| // The client you created from the Server-Side Auth instructions | ||
| import { createClient } from "@/lib/supabase/server"; | ||
|
|
||
| export async function GET(request: Request) { | ||
| const { searchParams, origin } = new URL(request.url); | ||
| const code = searchParams.get("code"); | ||
| // if "next" is in param, use it as the redirect URL | ||
| let next = searchParams.get("next") ?? "/"; | ||
| if (!next.startsWith("/")) { | ||
| // if "next" is not a relative URL, use the default | ||
| next = "/"; | ||
| } | ||
|
|
||
| if (code) { | ||
| const supabase = await createClient(); | ||
| const { error } = await supabase.auth.exchangeCodeForSession(code); | ||
| if (!error) { | ||
| const forwardedHost = request.headers.get("x-forwarded-host"); // original origin before load balancer | ||
| const isLocalEnv = process.env.NODE_ENV === "development"; | ||
| if (isLocalEnv) { | ||
| // we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host | ||
| return NextResponse.redirect(`${origin}${next}`); | ||
| } else if (forwardedHost) { | ||
| return NextResponse.redirect(`https://${forwardedHost}${next}`); | ||
| } else { | ||
| return NextResponse.redirect(`${origin}${next}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // return the user to an error page with instructions | ||
| return NextResponse.redirect(`${origin}/auth/auth-code-error`); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,170 @@ | ||||||
| "use client"; | ||||||
|
|
||||||
| import { Button } from "@/components/ui/button"; | ||||||
| import { | ||||||
| Card, | ||||||
| CardContent, | ||||||
| CardDescription, | ||||||
| CardHeader, | ||||||
| CardTitle, | ||||||
| } from "@/components/ui/card"; | ||||||
| import { | ||||||
| Field, | ||||||
| FieldDescription, | ||||||
| FieldGroup, | ||||||
| FieldLabel, | ||||||
| FieldSeparator, | ||||||
| } from "@/components/ui/field"; | ||||||
| import { Input } from "@/components/ui/input"; | ||||||
| import { createClient } from "@/lib/supabase/client"; | ||||||
| import { Provider } from "@supabase/supabase-js"; | ||||||
| import Link from "next/link"; | ||||||
| import { redirect, useRouter } from "next/navigation"; | ||||||
|
||||||
| import { redirect, useRouter } from "next/navigation"; | |
| import { useRouter } from "next/navigation"; |
Copilot
AI
Oct 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
redirectTo points to /auth/callback and uses process.env.SITE_URL in a client component. Client-side env vars must be prefixed with NEXT_PUBLIC_, and your callback route is implemented at /api/auth/callback. Update to use the correct path and a client-safe origin, e.g.: redirectTo: ${window.location.origin}/api/auth/callback.
| redirectTo: `${process.env.SITE_URL}/auth/callback`, | |
| redirectTo: `${window.location.origin}/api/auth/callback`, |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| const Signup = () => { | ||
| return <div>Signup</div>; | ||
| }; | ||
|
|
||
| export default Signup; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| "use client"; | ||
|
|
||
| import { createClient } from "@/lib/supabase/client"; | ||
| import Link from "next/link"; | ||
| import { useEffect, useState } from "react"; | ||
|
|
||
| const AuthButtons = () => { | ||
| const supabase = createClient(); | ||
| const [user, setUser] = useState<any>(null); | ||
| const [loading, setLoading] = useState(true); | ||
|
|
||
| useEffect(() => { | ||
| const fetchUser = async () => { | ||
| const { data } = await supabase.auth.getUser(); | ||
| console.log(data); | ||
Shitanshukumar607 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| setUser(data.user); | ||
| setLoading(false); | ||
| }; | ||
| fetchUser(); | ||
| }, []); | ||
|
|
||
| return ( | ||
| <div> | ||
| {user ? ( | ||
| <button className="hidden sm:flex text-xs border border-emerald-500 dark:border-purple-500 px-3 py-1.5 rounded-md hover:bg-emerald-100 dark:hover:bg-violet-900 transition-colors duration-200 items-center gap-1.5"> | ||
| <span>Logout</span> | ||
| {!loading && ( | ||
| <span className="text-xs opacity-70">{`(${user.user_metadata.name})`}</span> | ||
| )} | ||
| </button> | ||
|
Comment on lines
24
to
29
|
||
| ) : ( | ||
| <Link | ||
| href="/login" | ||
| className="text-sm border border-emerald-500 dark:border-purple-500 px-4 py-2 rounded-md hover:bg-emerald-100 dark:hover:bg-violet-900 transition-colors duration-200" | ||
| > | ||
| Login | ||
| </Link> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default AuthButtons; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import * as React from "react"; | ||
|
|
||
| import { cn } from "@/lib/utils"; | ||
|
Comment on lines
+1
to
+3
|
||
|
|
||
| function Card({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card" | ||
| className={cn( | ||
| "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", | ||
| className, | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-header" | ||
| className={cn( | ||
| "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", | ||
| className, | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-title" | ||
| className={cn("leading-none font-semibold", className)} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardDescription({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-description" | ||
| className={cn("text-muted-foreground text-sm", className)} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardAction({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-action" | ||
| className={cn( | ||
| "col-start-2 row-span-2 row-start-1 self-start justify-self-end", | ||
| className, | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-content" | ||
| className={cn("px-6", className)} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| function CardFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| return ( | ||
| <div | ||
| data-slot="card-footer" | ||
| className={cn("flex items-center px-6 [.border-t]:pt-6", className)} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| export { | ||
| Card, | ||
| CardHeader, | ||
| CardFooter, | ||
| CardTitle, | ||
| CardAction, | ||
| CardDescription, | ||
| CardContent, | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.