feat: init new auth

This commit is contained in:
swve 2024-05-25 14:56:28 +02:00
parent f838a8512c
commit 1708b36818
34 changed files with 1853 additions and 3613 deletions

View file

@ -0,0 +1,6 @@
import NextAuth from 'next-auth'
import { nextAuthOptions } from 'app/auth/options'
const handler = NextAuth(nextAuthOptions)
export { handler as GET, handler as POST }

View file

@ -0,0 +1,92 @@
import {
getNewAccessTokenUsingRefreshTokenServer,
getUserSession,
loginAndGetToken,
loginWithOAuthToken,
} from '@services/auth/auth'
import { getResponseMetadata } from '@services/utils/ts/requests'
import CredentialsProvider from 'next-auth/providers/credentials'
import GoogleProvider from 'next-auth/providers/google'
export const nextAuthOptions = {
providers: [
CredentialsProvider({
// The name to display on the sign in form (e.g. 'Sign in with...')
name: 'Credentials',
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the <input> tag through the object.
credentials: {
email: { label: 'Email', type: 'text', placeholder: 'jsmith' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
// logic to verify if user exists
let unsanitized_req = await loginAndGetToken(
credentials?.email,
credentials?.password
)
let res = await getResponseMetadata(unsanitized_req)
if (res.success) {
// If login failed, then this is the place you could do a registration
return res.data
} else {
return null
}
},
}),
GoogleProvider({
clientId: process.env.LEARNHOUSE_GOOGLE_CLIENT_ID || '',
clientSecret: process.env.LEARNHOUSE_GOOGLE_CLIENT_SECRET || '',
}),
],
callbacks: {
async jwt({ token, user, account }) {
// First sign in with Credentials provider
if (account?.provider == 'credentials' && user) {
token.user = user
}
// Sign up with Google
if (account?.provider == 'google' && user) {
let unsanitized_req = await loginWithOAuthToken(
user.email,
'google',
account.access_token
)
let userFromOAuth = await getResponseMetadata(unsanitized_req)
token.user = userFromOAuth.data
}
// Refresh token
// TODO : Improve this implementation
if (token?.user?.tokens) {
const RefreshedToken = await getNewAccessTokenUsingRefreshTokenServer(
token?.user?.tokens?.refresh_token
)
token = {
...token,
user: {
...token.user,
tokens: {
...token.user.tokens,
access_token: RefreshedToken.access_token,
},
},
}
}
return token
},
async session({ session, token }) {
// Include user information in the session
if (token.user) {
let api_SESSION = await getUserSession(token.user.tokens.access_token)
session.user = api_SESSION.user
session.roles = api_SESSION.roles
session.tokens = token.user.tokens
}
return session
},
},
}

View file

@ -1,6 +0,0 @@
import PageLoading from '@components/Objects/Loaders/PageLoading'
export default function Loading() {
// Or a custom loading skeleton component
return <PageLoading></PageLoading>
}

View file

@ -6,7 +6,6 @@ import { Metadata } from 'next'
import { getActivityWithAuthHeader } from '@services/courses/activities'
import { getAccessTokenFromRefreshTokenCookie } from '@services/auth/auth'
import { getOrganizationContextInfoWithId } from '@services/organizations/orgs'
import SessionProvider from '@components/Contexts/SessionContext'
import EditorOptionsProvider from '@components/Contexts/Editor/EditorContext'
import AIEditorProvider from '@components/Contexts/AI/AIEditorContext'
const EditorWrapper = dynamic(() => import('@components/Objects/Editor/EditorWrapper'), { ssr: false })
@ -58,14 +57,12 @@ const EditActivity = async (params: any) => {
return (
<EditorOptionsProvider options={{ isEditable: true }}>
<AIEditorProvider>
<SessionProvider>
<EditorWrapper
org={org}
course={courseInfo}
activity={activity}
content={activity.content}
></EditorWrapper>
</SessionProvider>
</AIEditorProvider>
</EditorOptionsProvider>
)

View file

@ -1,8 +1,8 @@
'use client'
import '../styles/globals.css'
import StyledComponentsRegistry from '../components/Utils/libs/styled-registry'
import { motion } from 'framer-motion'
import { SessionProvider } from 'next-auth/react'
export default function RootLayout({
children,
@ -18,18 +18,20 @@ export default function RootLayout({
<html className="" lang="en">
<head />
<body>
<StyledComponentsRegistry>
<motion.main
variants={variants} // Pass the variant object into Framer Motion
initial="hidden" // Set the initial state to variants.hidden
animate="enter" // Animated state to variants.enter
exit="exit" // Exit state (used later) to variants.exit
transition={{ type: 'linear' }} // Set the transition to linear
className=""
>
{children}
</motion.main>
</StyledComponentsRegistry>
<SessionProvider>
<StyledComponentsRegistry>
<motion.main
variants={variants} // Pass the variant object into Framer Motion
initial="hidden" // Set the initial state to variants.hidden
animate="enter" // Animated state to variants.enter
exit="exit" // Exit state (used later) to variants.exit
transition={{ type: 'linear' }} // Set the transition to linear
className=""
>
{children}
</motion.main>
</StyledComponentsRegistry>
</SessionProvider>
</body>
</html>
)

View file

@ -1,6 +1,7 @@
'use client'
import '@styles/globals.css'
import { Menu } from '@components/Objects/Menu/Menu'
import SessionProvider from '@components/Contexts/SessionContext'
import { SessionProvider } from 'next-auth/react'
export default function RootLayout({
children,

View file

@ -1,7 +1,8 @@
import SessionProvider from '@components/Contexts/SessionContext'
import LeftMenu from '@components/Dashboard/UI/LeftMenu'
import AdminAuthorization from '@components/Security/AdminAuthorization'
import ClientComponentSkeleton from '@components/Utils/ClientComp'
import { Metadata } from 'next'
import { SessionProvider } from 'next-auth/react'
import React from 'react'
export const metadata: Metadata = {
@ -17,14 +18,12 @@ function DashboardLayout({
}) {
return (
<>
<SessionProvider>
<AdminAuthorization authorizationMode="page">
<div className="flex">
<LeftMenu />
<div className="flex w-full">{children}</div>
</div>
</AdminAuthorization>
</SessionProvider>
<AdminAuthorization authorizationMode="page">
<div className="flex">
<LeftMenu />
<div className="flex w-full">{children}</div>
</div>
</AdminAuthorization>
</>
)
}

View file

@ -7,7 +7,7 @@ import Link from 'next/link'
import { getUriWithOrg } from '@services/config/config'
import { Info, Lock } from 'lucide-react'
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
import { useSession } from '@components/Contexts/SessionContext'
import { useSession } from 'next-auth/react'
export type SettingsParams = {
subpage: string

View file

@ -5,7 +5,7 @@ import Link from 'next/link'
import { getUriWithOrg } from '@services/config/config'
import { ScanEye, SquareUserRound, UserPlus, Users } from 'lucide-react'
import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs'
import { useSession } from '@components/Contexts/SessionContext'
import { useSession } from 'next-auth/react'
import { useOrg } from '@components/Contexts/OrgContext'
import OrgUsers from '@components/Dashboard/Users/OrgUsers/OrgUsers'
import OrgAccess from '@components/Dashboard/Users/OrgAccess/OrgAccess'

View file

@ -1,8 +1,8 @@
'use client'
import { OrgProvider } from '@components/Contexts/OrgContext'
import SessionProvider from '@components/Contexts/SessionContext'
import Toast from '@components/StyledElements/Toast/Toast'
import '@styles/globals.css'
import { SessionProvider } from 'next-auth/react'
export default function RootLayout({
children,

View file

@ -14,6 +14,7 @@ import { loginAndGetToken } from '@services/auth/auth'
import { AlertTriangle } from 'lucide-react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { signIn, useSession } from "next-auth/react"
import { getUriWithOrg } from '@services/config/config'
interface LoginClientProps {
@ -40,7 +41,9 @@ const validate = (values: any) => {
const LoginClient = (props: LoginClientProps) => {
const [isSubmitting, setIsSubmitting] = React.useState(false)
const router = useRouter()
const router = useRouter();
const session = useSession();
const [error, setError] = React.useState('')
const formik = useFormik({
initialValues: {
@ -50,25 +53,23 @@ const LoginClient = (props: LoginClientProps) => {
validate,
onSubmit: async (values) => {
setIsSubmitting(true)
let res = await loginAndGetToken(values.email, values.password)
let message = await res.json()
if (res.status == 200) {
//let res = await loginAndGetToken(values.email, values.password)
const res = await signIn('credentials', {
redirect: false,
email: values.email,
password: values.password,
});
if (res && res.error) {
setError("Wrong Email or password");
setIsSubmitting(false);
}
else {
router.push(`/`)
setIsSubmitting(false)
} else if (
res.status == 401 ||
res.status == 400 ||
res.status == 404 ||
res.status == 409
) {
setError(message.detail)
setIsSubmitting(false)
} else {
setError('Something went wrong')
setIsSubmitting(false)
}
},
})
return (
<div className="grid grid-flow-col justify-stretch h-screen">
<div
@ -165,7 +166,6 @@ const LoginClient = (props: LoginClientProps) => {
Forgot password?
</Link>
</div>
<div className="flex py-4">
<Form.Submit asChild>
<button className="w-full bg-black text-white font-bold text-center p-2 rounded-md shadow-md hover:cursor-pointer">
@ -174,6 +174,11 @@ const LoginClient = (props: LoginClientProps) => {
</Form.Submit>
</div>
</FormLayout>
<div className='flex h-0.5 rounded-2xl bg-slate-100 mt-5 mb-5 mx-10'></div>
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
<img src="https://fonts.gstatic.com/s/i/productlogos/googleg/v6/24px.svg" alt="" />
<span>Sign in with Google</span>
</button>
</div>
</div>
</div>

View file

@ -13,6 +13,7 @@ import { AlertTriangle, Check, User } from 'lucide-react'
import Link from 'next/link'
import { signup } from '@services/auth/auth'
import { useOrg } from '@components/Contexts/OrgContext'
import { signIn } from 'next-auth/react'
const validate = (values: any) => {
const errors: any = {}
@ -176,6 +177,13 @@ function OpenSignUpComponent() {
</Form.Submit>
</div>
</FormLayout>
<div>
<div className='flex h-0.5 rounded-2xl bg-slate-100 mt-5 mb-5 mx-10'></div>
<button onClick={() => signIn('google')} className="flex justify-center py-3 text-md w-full bg-white text-slate-600 space-x-3 font-semibold text-center p-2 rounded-md shadow hover:cursor-pointer">
<img src="https://fonts.gstatic.com/s/i/productlogos/googleg/v6/24px.svg" alt="" />
<span>Sign in with Google</span>
</button>
</div>
</div>
)
}

View file

@ -4,7 +4,7 @@ import Image from 'next/image'
import { getOrgLogoMediaDirectory } from '@services/media/media'
import Link from 'next/link'
import { getUriWithOrg } from '@services/config/config'
import { useSession } from '@components/Contexts/SessionContext'
import { useSession } from 'next-auth/react'
import React, { useEffect } from 'react'
import { MailWarning, Shield, Ticket, UserPlus } from 'lucide-react'
import { useOrg } from '@components/Contexts/OrgContext'
@ -92,14 +92,14 @@ function SignUpClient(props: SignUpClientProps) {
</div>
<div className="left-join-part bg-white flex flex-row">
{joinMethod == 'open' &&
(session.isAuthenticated ? (
(session.status == 'authenticated' ? (
<LoggedInJoinScreen inviteCode={inviteCode} />
) : (
<OpenSignUpComponent />
))}
{joinMethod == 'inviteOnly' &&
(inviteCode ? (
session.isAuthenticated ? (
session.status == 'authenticated' ? (
<LoggedInJoinScreen />
) : (
<InviteOnlySignUpComponent inviteCode={inviteCode} />
@ -130,7 +130,7 @@ const LoggedInJoinScreen = (props: any) => {
<span className="items-center">Hi</span>
<span className="capitalize flex space-x-2 items-center">
<UserAvatar rounded="rounded-xl" border="border-4" width={35} />
<span>{session.user.username},</span>
<span>{session.data.username},</span>
</span>
<span>join {org?.name} ?</span>
</p>
@ -157,7 +157,7 @@ const NoTokenScreen = (props: any) => {
const validateCode = async () => {
setIsLoading(true)
let res = await validateInviteCode(org?.id, inviteCode)
let res = await validateInviteCode(org?.id, inviteCode,session?.user?.tokens.access_token)
//wait for 1s
if (res.success) {
toast.success(