$Ivj|K!}Rv
z9fUDy#_iP+r|hrw35~@KI4k6_H1Qi!SJtPAS}971vMWuzIsyJ;X<~4Saz#!O5u6d}xi784=eqUm9x(FMI!tO{HT}FYAq>D9(9CH?tt0Qt`*6Y^}emrWVp1gkN
z_A)~7$fPj8%a}gH6KBoVlZ^_)ns_%|{D`=UM~0}Eg92DzVf-S{$J4ECRYkYNI186z
zGenzoSaiXA0el*;cW_(GvgOzlP2;OU5k|E+V
zklV%#u>+RMp$u^cH4#_Rl{zd!l?)}sO&w{BXVW;Q{Nz}qatj;5u1AwB&QK!#%B{G5
z2h%Kqul4!K>!*WiuHEpp-E124iGHiPEB^WCkP&zm_uy*JPZzI_Fq*L47*ytq5lT13
z>Z7yiB55R+Xnl;-5l@Z8T__BcEzta|FO7OFIQ>niUq55`H?F=LE3S-2TUj4HUH)YJ-ji?l_ePr0
zd{Tm!LNf%KJ;d$WIOFNsyd05*k*px*LUf14V#gSzj$b)Xmds~YujY#DW3ZZR##G@s
z*k^ySdUp1fSM*NNZ=z-785ulgKk3`~=ziX`=W_{Es~}Gd&QdNY>&6R5Hago_J(QC1
z;^;W6A{(=DAKLm}>MMc$pSv~tE?@oN5|7x{7gc|_k$QGmjY=&LVos>ciQ>0xRH4}<
zQEO~zy6~o#@y<*aufeOBQ(4>@tIR6DD1Xt6TmWJoJRhv@s2;EUZR#{FbT`V0K8iy(
z-Phz|b&k@)PygsU8Zy4-x#g{PR^o#Pv$-&_e`F8coG!l12m8zrJ95ETl-uN%F2?PS
zVfp6MOY1|cjnkigX~CEscz$LrH_5JrV>qp>5kyYLGXevCVEv(pW+N7M|
zAKRCPSfvXs65bOqO3agnpY@g7k7_0*yl{Q=1-*Opm2pg(D4bB*4S%R_nRBNy5hspYs-N2t|H)YR(C)KLO-B0Nlj-KKS9k
zahk=ydFCqvfAYA_c#EL?cLXp3@ph#CPJ?2+Oi
zSz^~@jLn_1#OcYX?4enr>J<1tpCy`1Q93mE=PYB4miwTV=X~?T?Hyx%lKYDs
zayRO_#f!Z}_%x($eX#huW#fNdYyah)($qITYFwZ+8&kXDwf9G3(}_*K9`|rBF_Urk
zz=HSlBRyvHJ-@wYYNogc?oM7eus&tnaNmo)8vBmM
z>l1h)h?2!gEftB11TmEsinRB}cB!HcM
z3vAY`&ml)GO`E#=nKf8ZD=ap)i~fs6y&1TqRYl7gN>t1r4SzEYtuG~i-#R7bKx8*n
zpM`ir-ZHB05`h%Gm5?Q3`wT3YMyZnSFHLp%$tA`!TI-|Avj^`VUev|ylAaWIc@frU
zmkaOgs2#rU@mh+k6pL;%6>qlm3%oN3qC(KgRlg@)yy`Q-;)erVY}-DJ3j2O0vGN
zydmzXoSr^EKkLdzS^D|@Lb2GvxYjqBPhFZTf|jm7Qfgs+wR!c%FS2e8@3XEnr1?@&
zr2zeFe(1R{;rO}tR}Fe`N~uN0QV|b}80*u}b?ZEP@s)Q1>XlkpACJ!N7E@(bepg%w
zS|!`GR4iud`iUSV-@o%0}GP5S(Q})h5#~c0Fw4`yE7*K=<&0%5+D6pxg@wEI*
zpJ^}jdnLdp27djusM>w1-t}tnMSHQWNU
u<4xhJ9$S0PQmV;Y^B+|jyKH^+ab;iJ)(>|p-D+&z`>8S}NnFg5pZGucG(Nom
diff --git a/package-lock.json b/package-lock.json
index 562c538..918f87b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2910,6 +2910,7 @@
"integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -2927,6 +2928,7 @@
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -2938,6 +2940,7 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -2988,6 +2991,7 @@
"integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.38.0",
"@typescript-eslint/types": "8.38.0",
@@ -3220,6 +3224,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3424,6 +3429,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001726",
"electron-to-chromium": "^1.5.173",
@@ -3757,6 +3763,7 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -3838,7 +3845,8 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/embla-carousel-react": {
"version": "8.6.0",
@@ -3936,6 +3944,7 @@
"integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -5490,6 +5499,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -5676,6 +5686,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -5702,6 +5713,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -5735,6 +5747,7 @@
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.61.1.tgz",
"integrity": "sha512-2vbXUFDYgqEgM2RcXcAT2PwDW/80QARi+PKmHy5q2KhuKvOlG8iIYgf7eIlIANR5trW9fJbP4r5aub3a4egsew==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18.0.0"
},
@@ -6294,6 +6307,7 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -6418,6 +6432,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6597,6 +6612,7 @@
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
diff --git a/package.json b/package.json
index bf248a9..adda41e 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "@auth0/auth0-react": "^2.11.0",
"@hookform/resolvers": "^3.10.0",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-alert-dialog": "^1.1.14",
diff --git a/src/App.tsx b/src/App.tsx
index 272ad77..98b6066 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,14 +3,11 @@ import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { BrowserRouter, Routes, Route } from "react-router-dom";
+import { Routes, Route } from "react-router-dom";
-// Pages
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
-// Auth system
-import { AuthProvider } from "./auth/AuthProvider";
import Login from "./auth/Login";
import Signup from "./auth/Signup";
@@ -23,21 +20,12 @@ const App = () => (
-
-
-
- {/* Home page always accessible */}
- } />
-
- {/* Optional login system */}
- } />
- } />
-
- {/* 404 */}
- } />
-
-
-
+
+ } />
+ } />
+ } />
+ } />
+
diff --git a/src/auth/AuthProvider.tsx b/src/auth/AuthProvider.tsx
index 7472989..746954b 100644
--- a/src/auth/AuthProvider.tsx
+++ b/src/auth/AuthProvider.tsx
@@ -1,106 +1,41 @@
-import {
- createContext,
- useContext,
- useEffect,
- useState,
- ReactNode,
-} from "react";
-
-type User = {
- email: string;
-};
-
-type AuthContextType = {
- user: User | null;
- loading: boolean;
- login: (email: string, password: string) => Promise;
- signup: (email: string, password: string) => Promise;
- logout: () => void;
-};
-
-const AuthContext = createContext(undefined);
-
-const USERS_KEY = "app_users";
-const CURRENT_USER_KEY = "app_current_user";
-
-function readUsers(): Record {
- try {
- const raw = localStorage.getItem(USERS_KEY);
- if (!raw) return {};
- return JSON.parse(raw);
- } catch {
- return {};
+import { Auth0Provider } from "@auth0/auth0-react";
+import { ReactNode } from "react";
+import { useNavigate } from "react-router-dom";
+
+export function AuthProvider({ children }: { children: ReactNode }) {
+ const navigate = useNavigate();
+
+ const domain = import.meta.env.VITE_AUTH0_DOMAIN;
+ const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;
+ const redirectUri = import.meta.env.VITE_AUTH0_REDIRECT_URI;
+
+ // Debug logging
+ console.log("Auth0 Config:", {
+ domain,
+ clientId,
+ redirectUri,
+ });
+
+ // Validation
+ if (!domain || !clientId || !redirectUri) {
+ console.error("❌ Missing Auth0 environment variables!");
+ return
+ Auth0 configuration error. Check your .env file.
+
;
}
-}
-
-function writeUsers(users: Record) {
- localStorage.setItem(USERS_KEY, JSON.stringify(users));
-}
-
-export const AuthProvider = ({ children }: { children: ReactNode }) => {
- const [user, setUser] = useState(null);
- const [loading, setLoading] = useState(true);
-
- // Load current user from localStorage on first render
- useEffect(() => {
- try {
- const raw = localStorage.getItem(CURRENT_USER_KEY);
- if (raw) {
- const stored = JSON.parse(raw) as User;
- setUser(stored);
- }
- } catch {
- // ignore
- } finally {
- setLoading(false);
- }
- }, []);
-
- const login = async (email: string, password: string) => {
- const users = readUsers();
- const savedPassword = users[email.toLowerCase()];
-
- if (!savedPassword || savedPassword !== password) {
- throw new Error("Invalid email or password");
- }
-
- const loggedInUser: User = { email };
- setUser(loggedInUser);
- localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(loggedInUser));
- };
-
- const signup = async (email: string, password: string) => {
- const users = readUsers();
- const key = email.toLowerCase();
-
- if (users[key]) {
- throw new Error("An account with this email already exists");
- }
-
- users[key] = password;
- writeUsers(users);
-
- const newUser: User = { email };
- setUser(newUser);
- localStorage.setItem(CURRENT_USER_KEY, JSON.stringify(newUser));
- };
-
- const logout = () => {
- setUser(null);
- localStorage.removeItem(CURRENT_USER_KEY);
- };
return (
-
+ {
+ navigate(appState?.returnTo || "/");
+ }}
+ >
{children}
-
+
);
-};
-
-export const useAuth = () => {
- const ctx = useContext(AuthContext);
- if (!ctx) {
- throw new Error("useAuth must be used inside AuthProvider");
- }
- return ctx;
-};
+}
\ No newline at end of file
diff --git a/src/auth/Login.tsx b/src/auth/Login.tsx
index 9618752..9091acb 100644
--- a/src/auth/Login.tsx
+++ b/src/auth/Login.tsx
@@ -1,40 +1,15 @@
-import { useState } from "react";
-import { useNavigate, Link } from "react-router-dom";
-import { useAuth } from "./AuthProvider";
+import { useAuth0 } from "@auth0/auth0-react";
import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
- CardFooter,
} from "@/components/ui/card";
export default function Login() {
- const { login } = useAuth();
- const navigate = useNavigate();
-
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
- const [submitting, setSubmitting] = useState(false);
- const [error, setError] = useState(null);
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- setError(null);
- setSubmitting(true);
- try {
- await login(email.trim(), password);
- navigate("/", { replace: true });
- } catch (err: any) {
- setError(err.message || "Failed to login");
- } finally {
- setSubmitting(false);
- }
- };
+ const { loginWithRedirect } = useAuth0();
return (
@@ -45,56 +20,19 @@ export default function Login() {
Sign in to continue watching your movies & shows.
-
-