feat: create auth provider context

This commit is contained in:
2026-01-20 11:27:09 +07:00
parent e27b18b22e
commit eae3b2b3fc
10 changed files with 99 additions and 18 deletions

View File

@ -1,7 +1,7 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Geist, Geist_Mono, Inter } from "next/font/google"; import { Geist, Geist_Mono, Inter } from "next/font/google";
import Navbar from "@/shared/widgets/navbar/components/Navbar";
import "./globals.css"; import "./globals.css";
import AuthSessionProviderWrapper from "@/shared/providers/AuthSession";
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" }); const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
@ -30,7 +30,7 @@ export default function RootLayout({
<body <body
className={`${geistSans.variable} ${geistMono.variable} antialiased`} className={`${geistSans.variable} ${geistMono.variable} antialiased`}
> >
{children} <AuthSessionProviderWrapper>{children}</AuthSessionProviderWrapper>
</body> </body>
</html> </html>
); );

View File

@ -1,11 +1,11 @@
"use server"; "use server";
import { backendFetch, BackendResponse } from "@/shared/helper/backendFetch"; import { backendFetch, BackendResponse } from "@/shared/helpers/backendFetch";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
export const submitProviderCallback = async ( export const submitProviderCallback = async (
providerName: string, providerName: string,
queries?: unknown queries?: unknown,
): Promise< ): Promise<
BackendResponse<{ BackendResponse<{
authToken: string; authToken: string;
@ -15,7 +15,7 @@ export const submitProviderCallback = async (
const envKey = providerName.toUpperCase() + "_CALLBACK_URL"; const envKey = providerName.toUpperCase() + "_CALLBACK_URL";
const authClientCallbackUrl = (await backendFetch( const authClientCallbackUrl = (await backendFetch(
"auth/providers/" + providerName + "/callback" "auth/providers/" + providerName + "/callback",
)) as BackendResponse<{ )) as BackendResponse<{
callback_url: string; callback_url: string;
}>; }>;
@ -26,7 +26,7 @@ export const submitProviderCallback = async (
const responseProvision = (await backendFetch( const responseProvision = (await backendFetch(
`${authClientCallbackUrl.data?.callback_url!}?callbackURI=${ `${authClientCallbackUrl.data?.callback_url!}?callbackURI=${
process.env.APP_URL process.env.APP_URL
}${process.env[envKey]}&${queries}` }${process.env[envKey]}&${queries}`,
)) as BackendResponse<{ )) as BackendResponse<{
authToken: string; authToken: string;
}>; }>;

View File

@ -1,14 +1,14 @@
"use client"; "use client";
import { Spinner } from "@/shared/libs/shadcn/ui/spinner"; import { Spinner } from "@/shared/libs/shadcn/ui/spinner";
import { submitProviderCallback } from "@/features/authCallback/actions/submitProviderCallback"; import { submitProviderCallback } from "@/features/authCallback/actions/submitProviderCallback";
import { useParams, useRouter, useSearchParams } from "next/navigation"; import { useParams, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
const AuthCallbackIndex = () => { const AuthCallbackIndex = () => {
const { name } = useParams(); const { name } = useParams();
const queries = useSearchParams().toString(); const queries = useSearchParams().toString();
const [textDescription, setTextDescription] = useState( const [textDescription, setTextDescription] = useState(
"We are processing your authentication." "We are processing your authentication.",
); );
const finishOAuthFlow = (type: string) => { const finishOAuthFlow = (type: string) => {
@ -26,6 +26,7 @@ const AuthCallbackIndex = () => {
setTextDescription("Authentication successful! Redirecting..."); setTextDescription("Authentication successful! Redirecting...");
finishOAuthFlow("oauth-success"); finishOAuthFlow("oauth-success");
} else { } else {
console.error("Error in authentication callback:", response);
setTextDescription("Authentication failed. Please try again."); setTextDescription("Authentication failed. Please try again.");
finishOAuthFlow("oauth-failed"); finishOAuthFlow("oauth-failed");
} }

View File

@ -0,0 +1,14 @@
import { createContext, useContext } from "react";
import { UserSession } from "../models/auth/validateAndDecodeJWT";
type AuthContextType = {
session: UserSession | null;
};
export const AuthContext = createContext<AuthContextType>({
session: null,
});
export function useAuth() {
return useContext(AuthContext);
}

View File

@ -0,0 +1,42 @@
"use server";
import { backendFetch, BackendResponse } from "@/shared/helpers/backendFetch";
import { cookies } from "next/headers";
export interface UserSession {
id: string;
isAuthenticated: boolean;
validUntil: Date;
user: {
id: string;
name: string;
email: string;
username: string;
avatar: string;
birthDate: null;
bioProfile: null;
preference: {
id: string;
userId: string;
langPreference: null;
adultFiltering: string;
adultAlert: string;
videoQuality: string;
serviceDefaultId: null;
};
};
iat: number;
exp: number;
}
export const validateAndDecodeJWT = async (): Promise<UserSession> => {
const cookieHeader = (await cookies()).get("auth_token")?.value;
const res = (await backendFetch("auth/token/validate", {
method: "POST",
body: JSON.stringify({
token: cookieHeader,
}),
})) as BackendResponse<UserSession>;
return res.data!;
};

View File

@ -0,0 +1,17 @@
"use client";
import { AuthContext } from "../contexts/AuthContext";
import React from "react";
import { UserSession } from "../models/auth/validateAndDecodeJWT";
const AuthSessionProvider = ({
children,
session,
}: Readonly<{ children: React.ReactNode; session: UserSession | null }>) => {
return (
<AuthContext.Provider value={{ session: session }}>
{children}
</AuthContext.Provider>
);
};
export default AuthSessionProvider;

View File

@ -1,10 +1,17 @@
import { cookies } from "next/headers"; import {
import React from "react"; UserSession,
validateAndDecodeJWT,
} from "../models/auth/validateAndDecodeJWT";
import AuthSessionProvider from "./AuthSession.client";
const AuthSessionProvider = ({children}: readonly<{children: React.ReactNode}>) => { const AuthSessionProviderWrapper = async ({
const cookieHeader = cookies().toString(); children,
console.log("Cookies in AuthSessionProvider:", cookieHeader); }: Readonly<{ children: React.ReactNode }>) => {
return <AuthContext.Provider value={{ cookie = cookieHeader }}>{children}</AuthContext.Provider>; let session: UserSession | null = await validateAndDecodeJWT();
return (
<AuthSessionProvider session={session}>{children}</AuthSessionProvider>
);
}; };
export default AuthSessionProvider; export default AuthSessionProviderWrapper;

View File

@ -1,5 +1,5 @@
"use server"; "use server";
import { backendFetch, BackendResponse } from "@/shared/helper/backendFetch"; import { backendFetch, BackendResponse } from "@/shared/helpers/backendFetch";
export type GetALlThirdPartyAuthCallback = BackendResponse< export type GetALlThirdPartyAuthCallback = BackendResponse<
{ {

View File

@ -1,5 +1,5 @@
"use server"; "use server";
import { backendFetch, BackendResponse } from "@/shared/helper/backendFetch"; import { backendFetch, BackendResponse } from "@/shared/helpers/backendFetch";
interface GetOauthEndpointParams { interface GetOauthEndpointParams {
endpointUrl: string; endpointUrl: string;
@ -13,7 +13,7 @@ export const getOauthEndpoint = async ({
const envKey = providerName.toUpperCase() + "_CALLBACK_URL"; const envKey = providerName.toUpperCase() + "_CALLBACK_URL";
return (await backendFetch( return (await backendFetch(
`${endpointUrl}?callback=${process.env.APP_URL}${process.env[envKey]}` `${endpointUrl}?callback=${process.env.APP_URL}${process.env[envKey]}`,
)) as BackendResponse<{ )) as BackendResponse<{
endpointUrl: string; endpointUrl: string;
}>; }>;