Upgraded to Next Auth v5
This commit is contained in:
parent
a3352af981
commit
4505654a05
@ -9,9 +9,6 @@ export async function GET(req: Request) {
|
|||||||
const scope = searchParams.get('scope') as string
|
const scope = searchParams.get('scope') as string
|
||||||
const state = searchParams.get('state') as string
|
const state = searchParams.get('state') as string
|
||||||
|
|
||||||
console.log("CODE:", code)
|
|
||||||
console.log("SCOPE:", scope)
|
|
||||||
console.log("STATE:", state)
|
|
||||||
if (!code || !scope || !state) {
|
if (!code || !scope || !state) {
|
||||||
return new NextResponse("Bad Request", { status: 400 });
|
return new NextResponse("Bad Request", { status: 400 });
|
||||||
}
|
}
|
||||||
@ -38,21 +35,17 @@ export async function GET(req: Request) {
|
|||||||
|
|
||||||
// Fetch values from token.
|
// Fetch values from token.
|
||||||
const { access_token, expires_in, refresh_token, token_type } = token
|
const { access_token, expires_in, refresh_token, token_type } = token
|
||||||
// console.log("AT", access_token)
|
|
||||||
// console.log("RT", refresh_token)
|
|
||||||
// console.log("TT", token_type)
|
|
||||||
|
|
||||||
if (!access_token || !refresh_token || token_type !== "bearer") {
|
if (!access_token || !refresh_token || token_type !== "bearer") {
|
||||||
return new NextResponse("Unauthorized", { status: 401 });
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = await axios.get("https://api.twitch.tv/helix/users?login=" + user.username, {
|
let info = await axios.get("https://api.twitch.tv/helix/users?login=" + user.name, {
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": "Bearer " + access_token,
|
"Authorization": "Bearer " + access_token,
|
||||||
"Client-Id": process.env.TWITCH_BOT_CLIENT_ID
|
"Client-Id": process.env.TWITCH_BOT_CLIENT_ID
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log(info.data.data)
|
|
||||||
const broadcasterId = info.data.data[0]['id']
|
const broadcasterId = info.data.data[0]['id']
|
||||||
|
|
||||||
await db.twitchConnection.create({
|
await db.twitchConnection.create({
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { db } from "@/lib/db"
|
import { db } from "@/lib/db"
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { GET as authorize } from '../authorize/route'
|
|
||||||
|
|
||||||
export async function GET(req: Request) {
|
export async function GET(req: Request) {
|
||||||
try {
|
try {
|
||||||
@ -11,7 +10,6 @@ export async function GET(req: Request) {
|
|||||||
id: req.headers.get('x-api-key') as string
|
id: req.headers.get('x-api-key') as string
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return new NextResponse("Forbidden", { status: 403 });
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
@ -46,9 +44,6 @@ export async function GET(req: Request) {
|
|||||||
|
|
||||||
// Fetch values from token.
|
// Fetch values from token.
|
||||||
const { access_token, expires_in, refresh_token, token_type } = token
|
const { access_token, expires_in, refresh_token, token_type } = token
|
||||||
// console.log("AT", access_token)
|
|
||||||
// console.log("RT", refresh_token)
|
|
||||||
// console.log("TT", token_type)
|
|
||||||
|
|
||||||
if (!access_token || !refresh_token || token_type !== "bearer") {
|
if (!access_token || !refresh_token || token_type !== "bearer") {
|
||||||
return new NextResponse("Unauthorized", { status: 401 });
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { db } from "@/lib/db"
|
import { db } from "@/lib/db"
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { getServerSession } from "next-auth";
|
import { auth } from "@/auth";
|
||||||
import { generateToken } from "../token/route";
|
|
||||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||||
|
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ export async function GET(req: Request) {
|
|||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
try {
|
try {
|
||||||
const session = await getServerSession()
|
const session = await auth()
|
||||||
const user = session?.user?.name
|
const user = session?.user?.name
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return new NextResponse("Internal Error", { status: 401 })
|
return new NextResponse("Internal Error", { status: 401 })
|
||||||
@ -24,26 +23,26 @@ export async function POST(req: Request) {
|
|||||||
|
|
||||||
const exist = await db.user.findFirst({
|
const exist = await db.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
username: user.toLowerCase() as string
|
name: user
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist) {
|
if (exist) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
id: exist.id,
|
id: exist.id,
|
||||||
username: exist.username
|
username: exist.name
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newUser = await db.user.create({
|
const newUser = await db.user.create({
|
||||||
data: {
|
data: {
|
||||||
username: user.toLowerCase() as string,
|
name: user,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
id: newUser.id,
|
id: newUser.id,
|
||||||
username: newUser.username
|
username: newUser.name
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("[ACCOUNT]", error);
|
console.log("[ACCOUNT]", error);
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
import type { NextAuthOptions } from "next-auth";
|
|
||||||
import TwitchProvider from "next-auth/providers/twitch";
|
|
||||||
|
|
||||||
export interface TwitchProfile extends Record<string, any> {
|
|
||||||
sub: string
|
|
||||||
preferred_username: string
|
|
||||||
email: string
|
|
||||||
picture: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const options: NextAuthOptions = {
|
|
||||||
providers: [
|
|
||||||
TwitchProvider({
|
|
||||||
clientId: process.env.TWITCH_CLIENT_ID as string,
|
|
||||||
clientSecret: process.env.TWITCH_CLIENT_SECRET as string,
|
|
||||||
authorization: {
|
|
||||||
params: {
|
|
||||||
scope: "openid user:read:email",
|
|
||||||
claims: {
|
|
||||||
id_token: {
|
|
||||||
email: null,
|
|
||||||
picture: null,
|
|
||||||
preferred_username: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
idToken: true,
|
|
||||||
profile(profile) {
|
|
||||||
return {
|
|
||||||
id: profile.sub,
|
|
||||||
name: profile.preferred_username,
|
|
||||||
email: profile.email,
|
|
||||||
image: profile.picture,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
],
|
|
||||||
secret: process.env.NEXTAUTH_SECRET
|
|
||||||
}
|
|
@ -1,6 +1 @@
|
|||||||
import NextAuth from 'next-auth'
|
export { GET, POST } from "@/auth"
|
||||||
import { options } from './options'
|
|
||||||
|
|
||||||
const handler = NextAuth(options)
|
|
||||||
|
|
||||||
export { handler as GET, handler as POST }
|
|
@ -1,4 +1,3 @@
|
|||||||
import axios from "axios"
|
|
||||||
import { db } from "@/lib/db"
|
import { db } from "@/lib/db"
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||||
@ -7,7 +6,6 @@ export async function GET(req: Request) {
|
|||||||
try {
|
try {
|
||||||
const user = await fetchUserUsingAPI(req)
|
const user = await fetchUserUsingAPI(req)
|
||||||
if (!user) {
|
if (!user) {
|
||||||
console.log("TWITCH CONNECT", user)
|
|
||||||
return new NextResponse("Unauthorized", { status: 401 });
|
return new NextResponse("Unauthorized", { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,56 +24,6 @@ export async function GET(req: Request) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json(connection);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[CONNECTION/TWITCH]", error);
|
|
||||||
return new NextResponse("Internal Error", { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
|
||||||
try {
|
|
||||||
const { id, secret } = await req.json();
|
|
||||||
const user = await fetchUserUsingAPI(req)
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return new NextResponse("Unauthorized", { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = null;
|
|
||||||
try {
|
|
||||||
response = await axios.post("https://id.twitch.tv/oauth2/token", {
|
|
||||||
client_id: id,
|
|
||||||
client_secret: secret,
|
|
||||||
grant_type: "client_credentials"
|
|
||||||
});
|
|
||||||
console.log(response.data)
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[CONNECTIONS/TWITCH/TOKEN]", error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(user.username)
|
|
||||||
let info = await axios.get("https://api.twitch.tv/helix/users?login=" + user.username, {
|
|
||||||
headers: {
|
|
||||||
"Authorization": "Bearer " + response.data['access_token'],
|
|
||||||
"Client-Id": id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log(info.data.data)
|
|
||||||
const broadcasterId = info.data.data[0]['id']
|
|
||||||
const username = info.data.data[0]['login']
|
|
||||||
|
|
||||||
const connection = await db.twitchConnection.create({
|
|
||||||
data: {
|
|
||||||
id: id,
|
|
||||||
secret,
|
|
||||||
userId: user.id as string,
|
|
||||||
broadcasterId,
|
|
||||||
username
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(connection);
|
return NextResponse.json(connection);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("[CONNECTION/TWITCH]", error);
|
console.log("[CONNECTION/TWITCH]", error);
|
||||||
|
@ -14,7 +14,6 @@ export async function GET(req: Request) {
|
|||||||
userId: user.id
|
userId: user.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!api) {
|
if (!api) {
|
||||||
return new NextResponse("Forbidden", { status: 403 });
|
return new NextResponse("Forbidden", { status: 403 });
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { db } from "@/lib/db"
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
export async function GET(req: Request, { params } : { params: { id: string } }) {
|
|
||||||
try {
|
|
||||||
let id = req.headers.get('x-api-key')
|
|
||||||
if (id == null) {
|
|
||||||
return NextResponse.json(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokens = await db.apiKey.findFirst({
|
|
||||||
where: {
|
|
||||||
id: id as string
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(tokens);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[VALIDATE/GET]", error);
|
|
||||||
return new NextResponse("Internal Error", { status: 500});
|
|
||||||
}
|
|
||||||
}
|
|
9
app/auth/layout.tsx
Normal file
9
app/auth/layout.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const AuthLayout = ({ children } : { children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div className="h-full flex items-center justify-center bg-black">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AuthLayout;
|
9
app/auth/login/page.tsx
Normal file
9
app/auth/login/page.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { LoginForm } from "@/components/auth/login-form";
|
||||||
|
|
||||||
|
const LoginPage = () => {
|
||||||
|
return (
|
||||||
|
<LoginForm />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoginPage;
|
@ -7,14 +7,13 @@ const SettingsLayout = async (
|
|||||||
{ children } : { children:React.ReactNode } ) => {
|
{ children } : { children:React.ReactNode } ) => {
|
||||||
const headersList = headers();
|
const headersList = headers();
|
||||||
const header_url = headersList.get('x-url') || "";
|
const header_url = headersList.get('x-url') || "";
|
||||||
console.log("HEADER URL: " + header_url)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full">
|
<div className="h-full">
|
||||||
<div className={cn("hidden md:flex h-full w-[250px] z-30 flex-col fixed inset-y-0", header_url.endsWith("/settings") && "md:flex h-full w-full z-30 flex-col fixed inset-y-0")}>
|
<div className={cn("hidden md:flex h-full w-[250px] z-30 flex-col fixed inset-y-0", header_url.endsWith("/settings") && "md:flex h-full w-full z-30 flex-col fixed inset-y-0")}>
|
||||||
<SettingsNavigation />
|
<SettingsNavigation />
|
||||||
</div>
|
</div>
|
||||||
|
{header_url}
|
||||||
<main className={cn("md:pl-[250px] h-full", header_url.endsWith("/settings") && "hidden")}>
|
<main className={cn("md:pl-[250px] h-full", header_url.endsWith("/settings") && "hidden")}>
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
"use client";
|
import { auth } from "@/auth";
|
||||||
|
|
||||||
const SettingsPage = () => {
|
const SettingsPage = async () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
{JSON.stringify(await auth())}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
17
auth.config.ts
Normal file
17
auth.config.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Twitch from "next-auth/providers/twitch"
|
||||||
|
|
||||||
|
import type { NextAuthConfig } from "next-auth"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
providers: [
|
||||||
|
Twitch({
|
||||||
|
clientId: process.env.TWITCH_CLIENT_ID,
|
||||||
|
clientSecret: process.env.TWITCH_CLIENT_SECRET,
|
||||||
|
authorization: {
|
||||||
|
params: {
|
||||||
|
scope: "openid user:read:email",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
} satisfies NextAuthConfig
|
35
auth.ts
Normal file
35
auth.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import NextAuth from "next-auth"
|
||||||
|
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
|
|
||||||
|
import { db } from "@/lib/db"
|
||||||
|
import authConfig from "@/auth.config"
|
||||||
|
|
||||||
|
export const {
|
||||||
|
handlers: { GET, POST },
|
||||||
|
auth,
|
||||||
|
signIn,
|
||||||
|
signOut,
|
||||||
|
} = NextAuth({
|
||||||
|
events: {
|
||||||
|
async linkAccount({ user }) {
|
||||||
|
await db.user.update({
|
||||||
|
where: {id: user.id },
|
||||||
|
data: { emailVerified: new Date() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
async session({ session, user, token }) {
|
||||||
|
if (token.sub && session.user) {
|
||||||
|
session.user.id = token.sub
|
||||||
|
}
|
||||||
|
return session
|
||||||
|
},
|
||||||
|
async jwt({ token, user, account, profile, isNewUser }) {
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
},
|
||||||
|
adapter: PrismaAdapter(db),
|
||||||
|
session: { strategy: "jwt" },
|
||||||
|
...authConfig,
|
||||||
|
})
|
40
components/auth/card-wrapper.tsx
Normal file
40
components/auth/card-wrapper.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { LoginForm } from "@/components/auth/login-form";
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import { Header } from "@/components/auth/header";
|
||||||
|
import { Social } from "@/components/auth/social";
|
||||||
|
|
||||||
|
|
||||||
|
interface CardWrapperProps {
|
||||||
|
children: React.ReactNode
|
||||||
|
headerLabel: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CardWrapper = ({
|
||||||
|
children,
|
||||||
|
headerLabel
|
||||||
|
}: CardWrapperProps) => {
|
||||||
|
return (
|
||||||
|
<Card className="w-[400px] shadow-md bg-white text-black">
|
||||||
|
<CardHeader>
|
||||||
|
<Header label={headerLabel} />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
{children}
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter>
|
||||||
|
<Social />
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardWrapper
|
25
components/auth/header.tsx
Normal file
25
components/auth/header.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Poppins } from "next/font/google";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|
||||||
|
const font = Poppins({
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: ["600"]
|
||||||
|
})
|
||||||
|
|
||||||
|
interface HeaderProps {
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Header = ({ label }: HeaderProps) => {
|
||||||
|
return (
|
||||||
|
<div className="w-full flex flex-col gap-y-4 items-center justify-center">
|
||||||
|
<h1 className={cn(
|
||||||
|
"text-3xl font-semibold", font.className
|
||||||
|
)}>Login</h1>
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
|
{label}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
11
components/auth/login-form.tsx
Normal file
11
components/auth/login-form.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { CardWrapper } from "./card-wrapper"
|
||||||
|
|
||||||
|
export const LoginForm = () => {
|
||||||
|
return (
|
||||||
|
<CardWrapper
|
||||||
|
headerLabel="Welcome back"
|
||||||
|
>
|
||||||
|
Login Form
|
||||||
|
</CardWrapper>
|
||||||
|
)
|
||||||
|
}
|
27
components/auth/social.tsx
Normal file
27
components/auth/social.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { signIn } from "next-auth/react"
|
||||||
|
import { FaTwitch } from "react-icons/fa"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { DEFAULT_REDIRECT } from "@/routes"
|
||||||
|
|
||||||
|
export const Social = () => {
|
||||||
|
const onClick = (provider: "twitch") => {
|
||||||
|
signIn(provider, {
|
||||||
|
callbackUrl: DEFAULT_REDIRECT,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center w-full gap-x-2">
|
||||||
|
<Button
|
||||||
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
|
className="w-full bg-white hover:bg-purple-500"
|
||||||
|
onClick={() => onClick("twitch")}
|
||||||
|
>
|
||||||
|
<FaTwitch className="h-5 w-5" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -2,40 +2,37 @@
|
|||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { User } from "@prisma/client";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { usePathname } from 'next/navigation'
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const UserProfile = () => {
|
const UserProfile = () => {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [previousUsername, setPreviousUsername] = useState<string>()
|
const [user, setUser] = useState<{ id: string, username: string }>()
|
||||||
const [user, setUser] = useState<User>()
|
|
||||||
const [loading, setLoading] = useState<boolean>(true)
|
let previousUsername = ""
|
||||||
const pathname = usePathname()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status !== "authenticated" || previousUsername == session.user?.name) {
|
if (status !== "authenticated" || previousUsername == session.user?.name) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setPreviousUsername(session.user?.name as string)
|
previousUsername = session.user?.name || ""
|
||||||
if (session.user) {
|
if (session.user) {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
var userData: User = (await axios.get("/api/account")).data
|
var userData = (await axios.get("/api/account")).data
|
||||||
setUser(userData)
|
setUser(userData)
|
||||||
setLoading(false)
|
console.log(userData)
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchData().catch(console.error)
|
fetchData().catch(console.error)
|
||||||
|
|
||||||
// TODO: check cookies if impersonation is in use.
|
// TODO: check session if impersonation is in use.
|
||||||
}
|
}
|
||||||
}, [session])
|
}, [session])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("px-10 py-6 rounded-md bg-blue-300 overflow-hidden wrap", loading && "hidden")}>
|
<div className={cn("px-10 py-6 rounded-md bg-blue-300 overflow-hidden wrap", user == null && "hidden")}>
|
||||||
<p className="text-xs text-gray-400">Logged in as:</p>
|
<p className="text-xs text-gray-400">Logged in as:</p>
|
||||||
<p>{user?.username}</p>
|
<p>{user?.username}</p>
|
||||||
</div>
|
</div>
|
||||||
|
10
data/user.ts
Normal file
10
data/user.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { db } from "@/lib/db";
|
||||||
|
|
||||||
|
export const getUserById = async (id: string) => {
|
||||||
|
try {
|
||||||
|
const user = await db.user.findUnique({ where: { id }})
|
||||||
|
return user;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,23 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { auth } from "@/auth";
|
||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
|
|
||||||
export default async function fetchUserUsingAPI(req: Request) {
|
export default async function fetchUserUsingAPI(req: Request) {
|
||||||
const session = await getServerSession()
|
const session = await auth()
|
||||||
console.log("server session:", session)
|
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
const user = await db.user.findFirst({
|
const user = await db.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
username: session.user?.name?.toLowerCase() as string
|
name: session.user?.name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: user?.id,
|
id: user?.id,
|
||||||
username: user?.username
|
username: user?.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = req.headers?.get('x-api-key')
|
const token = req.headers?.get('x-api-key')
|
||||||
console.log("x-api-key:", token)
|
|
||||||
if (token === null || token === undefined)
|
if (token === null || token === undefined)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
@ -35,10 +33,8 @@ export default async function fetchUserUsingAPI(req: Request) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log("user:", user)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: user?.id,
|
id: user?.id,
|
||||||
username: user?.username
|
username: user?.name
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,64 +1,43 @@
|
|||||||
// import { authMiddleware } from "@clerk/nextjs";
|
import authConfig from "@/auth.config"
|
||||||
// import { NextResponse } from "next/server";
|
import NextAuth from "next-auth"
|
||||||
|
|
||||||
// // This example protects all routes including api/trpc routes
|
|
||||||
// // Please edit this to allow other routes to be public as needed.
|
|
||||||
// // See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your middleware
|
|
||||||
// export default authMiddleware({
|
|
||||||
// publicRoutes: ["/api/:path*"],
|
|
||||||
// ignoredRoutes: ["/api/validate/:path*"],
|
|
||||||
|
|
||||||
// beforeAuth: async (req) => {
|
import {
|
||||||
// // if (req.url.startsWith("https://localhost:3000/api") /*&& !req.url.startsWith("https://localhost:3000/api/validate/")*/) {
|
DEFAULT_REDIRECT,
|
||||||
// // const apiKey = req.headers.get("x-api-key") as string
|
PUBLIC_ROUTES,
|
||||||
// // let api = null
|
AUTH_ROUTES,
|
||||||
// // if (apiKey != null) {
|
API_PREFIX
|
||||||
// // console.log("API KEY:", apiKey)
|
} from "@/routes"
|
||||||
// // api = await fetch("http://localhost:3000/api/validate")
|
|
||||||
// // }
|
|
||||||
// // if (api == null) {
|
|
||||||
// // console.log("Invalid API key attempted")
|
|
||||||
// // return NextResponse.rewrite(
|
|
||||||
// // `${req.nextUrl.protocol}//${req.nextUrl.host}`,
|
|
||||||
// // {
|
|
||||||
// // status: 401,
|
|
||||||
// // headers: {
|
|
||||||
// // "WWW-Authenticate": 'Basic realm="Secure Area"',
|
|
||||||
// // },
|
|
||||||
// // }
|
|
||||||
// // );
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// return NextResponse.next();
|
const { auth } = NextAuth(authConfig)
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// export const config = {
|
|
||||||
// matcher: ["/((?!.*\\..*|_next).*)", "/", "/(trpc)(.*)"],
|
|
||||||
// };
|
|
||||||
|
|
||||||
import { NextResponse } from "next/server";
|
export default auth((req) => {
|
||||||
import { redirect } from 'next/navigation';
|
const isLoggedIn = !!req.auth
|
||||||
import { withAuth } from 'next-auth/middleware';
|
|
||||||
import { getServerSession } from "next-auth";
|
|
||||||
|
|
||||||
export default withAuth(
|
const { nextUrl } = req
|
||||||
async function middleware(req) {
|
|
||||||
const requestHeaders = new Headers(req.headers);
|
|
||||||
requestHeaders.set('x-url', req.url);
|
|
||||||
|
|
||||||
return NextResponse.next({
|
const isApiRoute = nextUrl.pathname.startsWith(API_PREFIX)
|
||||||
request: {
|
const isPublicRoute = PUBLIC_ROUTES.includes(nextUrl.pathname)
|
||||||
// Apply new request headers
|
const isAuthRoute = AUTH_ROUTES.includes(nextUrl.pathname)
|
||||||
headers: requestHeaders,
|
|
||||||
}
|
if (isApiRoute) {
|
||||||
});
|
return null
|
||||||
},
|
|
||||||
{
|
|
||||||
callbacks: {
|
|
||||||
authorized: async ({ req, token }) =>
|
|
||||||
req.nextUrl.pathname?.slice(0, 4) === '/api' ||
|
|
||||||
!!token
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (isAuthRoute) {
|
||||||
|
if (isLoggedIn) {
|
||||||
|
return Response.redirect(new URL(DEFAULT_REDIRECT, nextUrl))
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoggedIn && !isPublicRoute) {
|
||||||
|
return Response.redirect(new URL("/auth/login", nextUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
// Optionally, don't invoke Middleware on some paths
|
||||||
|
export const config = {
|
||||||
|
matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
|
||||||
|
}
|
@ -9,10 +9,14 @@ datasource db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid())
|
id String @id @default(cuid())
|
||||||
username String @unique
|
name String?
|
||||||
|
email String? @unique
|
||||||
|
emailVerified DateTime?
|
||||||
|
image String?
|
||||||
|
|
||||||
apiKeys ApiKey[]
|
apiKeys ApiKey[]
|
||||||
|
accounts Account[]
|
||||||
twitchConnections TwitchConnection[]
|
twitchConnections TwitchConnection[]
|
||||||
createdProfiles TtsProfile[]
|
createdProfiles TtsProfile[]
|
||||||
profileStatus TtsProfileStatus[]
|
profileStatus TtsProfileStatus[]
|
||||||
@ -21,6 +25,25 @@ model User {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Account {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String
|
||||||
|
type String
|
||||||
|
provider String
|
||||||
|
providerAccountId String
|
||||||
|
refresh_token String? @db.Text
|
||||||
|
access_token String? @db.Text
|
||||||
|
expires_at Int?
|
||||||
|
token_type String?
|
||||||
|
scope String?
|
||||||
|
id_token String? @db.Text
|
||||||
|
session_state String?
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@unique([provider, providerAccountId])
|
||||||
|
}
|
||||||
|
|
||||||
model ApiKey {
|
model ApiKey {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
label String
|
label String
|
||||||
@ -88,7 +111,7 @@ model TtsBadgeFilter {
|
|||||||
|
|
||||||
model TtsUsernameFilter {
|
model TtsUsernameFilter {
|
||||||
username String
|
username String
|
||||||
white Boolean
|
tag String
|
||||||
|
|
||||||
profileId String
|
profileId String
|
||||||
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
profile TtsProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
||||||
|
Loading…
Reference in New Issue
Block a user