CONTEXT & PROVIDERS

Context and Provider are React mechanisms that allow data to be shared between components without passing props. In our case:

ExternalAuthContext

stores information about whether the user is logged in

ExternalAuthProvider

manages authorization logic and automatic redirects

1

Creating context

Create file name ExternalAuthContext.ts in web/src/contexts and paste following code:

import { createContext, useContext } from "react";

export type ExternalAuthContextValue = {
    isAuth: boolean;
    logoutUser: () => void;
};

export const ExternalAuthContext = createContext<ExternalAuthContextValue | null>(null);

export const useExternalAuth = () => {
    const ctx = useContext(ExternalAuthContext);
    if (!ctx) {
        throw new Error("useExternalAuth must be used within <ExternalAuthProvider>");
    }
    return ctx;
};
2

Creating Provider

Create file name ExternalAuthProvider.tsx in web/src/providers and paste following code:

import { ExternalAuthContext } from "@/contexts/ExternalAuthContext";
import { useNavigateWithApps } from "@/hooks/useNavigateWithApps";
import { useEffect, useCallback } from "react";
import { useLocation } from "react-router-dom";

export const ExternalAuthProvider = ({
    authPage,
    homePage,
    children,
}: {
    authPage: string;
    homePage: string;
    children: React.ReactNode;
}) => {
    const isAuth = useIsAuthenticated();
    const location = useLocation();
    const navigate = useNavigateWithApps();

    const path = location.pathname;
    const isInsideAuth = path === authPage || path.startsWith(authPage + "/");

    const logoutUser = useCallback(() => {
        useSignOut();
        navigate(authPage);
    }, [navigate, authPage]);

    useEffect(() => {
        if (!isAuth) {
            if (!isInsideAuth) navigate(authPage);
            return;
        }

        if (isAuth && isInsideAuth) {
            navigate(homePage);
            return;
        }
    }, [isAuth, isInsideAuth, authPage, homePage, navigate]);

    if (!isAuth && !isInsideAuth) return null;
    if (isAuth && isInsideAuth) return null;

    return (
        <ExternalAuthContext.Provider value={{ isAuth, logoutUser }}>
            {children}
        </ExternalAuthContext.Provider>
    );
};
3

Integrating the External Authentication Provider

To enable external authentication, the ExternalAuthProvider must be integrated into the main provider chain within the ProvidersManager component. Go to web/src/providers/index.tsx.

  1. Import the ExternalAuthProvider component:

import { ExternalAuthProvider } from './ExternalAuthProvider';
  1. Wrap the NuiProvider and its children with the ExternalAuthProvider inside the ProvidersManager. The new provider should be placed between the NavigateProvider and the NuiProvider.

import type { ReactNode } from 'react';
import { Provider } from 'react-redux';

import store from '@/store';

import LanguageProvider from './LanguageProvider';
import NavigateProvider from './NavigateProvider';
import NuiProvider from './NuiProvider';
import { ExternalAuthProvider } from './ExternalAuthProvider'

const ProvidersManager = ({ children }: { children: ReactNode }) => {
    return (
        <Provider store={store}>
            <NavigateProvider>
                <ExternalAuthProvider authPage='/auth' homePage='/'>
                    <NuiProvider>
                        <LanguageProvider>{children}</LanguageProvider>
                    </NuiProvider>
                </ExternalAuthProvider>
            </NavigateProvider>
        </Provider>
    );
};

export default ProvidersManager;

The authPage and homePage props are required to configure the redirect paths for authentication handling.

Last updated