# Auth

### Functionality

The Auth module ensures secure access to the system by managing user login, registration, password recovery, and session handling. It includes role-based access controls and integrates with OAuth providers.

### Auth Provider

The `AuthProvider` component and `AuthContext` provide authentication management and user context for the application. It handles storing and managing authentication tokens, user information, and team-related updates.

#### Key Features:

**1. State Management:**

* **`token` & `refreshToken`:** Stored in localStorage using the `useLocalStorage` hook. These hold the access token and refresh token for authenticated sessions.
* **`currentUser`:** Holds the currently authenticated user's data.

**2. Functions:**

* **`fetchUser`:**
  * Fetches the current user data from the API using `userService.getUser()`.
  * Updates user roles and checks if the user has a team. If no team exists, it navigates to the team creation page.
* **`setAuth`:** Stores the access token and refresh token in localStorage.
* **`logout`:**
  * Logs the user out by deactivating their membership (if applicable) and clears the authentication tokens.
  * Redirects to the sign-in page.
* **`changeTeam`:**
  * Switches the active team by calling the `authService.changeTeam` API and updating tokens.
  * Re-fetches the user data after changing the team.

**3. Context Usage:**

* **`AuthContext.Provider`:** Provides the authentication-related values and functions (`token`, `setAuth`, `logout`, etc.) to the component tree.
* **`useAuth`:** Hook to access the `AuthContext` values and functions within any component.

#### Usage Example:

To access the authentication context:

```jsx
const { token, logout, fetchUser, currentUser } = useAuth();
```

This structure allows centralized control of authentication, token management, and user/team updates throughout the app.

{% code title="AuthContext.js" %}

```javascript
import { createContext, useCallback, useContext, useState } from 'react';
import { useLocalStorage } from '../common/hooks/useLocalStorage';
import { useNavigate } from 'react-router-dom';
import { useUserService } from '../services/userService';
import { REFRESH_TOKEN, TOKEN, USER_ROLES } from '../common/constants/localStorage';
import { updateToken } from '../services/tokenService';
import { useAuthService } from '../services/authService';
import globalNotification from '../common/hooks/globalNotification';
import { useTeamService } from '../services/teamService';

export const AuthContext = createContext(null);

export const AuthProvider = ({ children }) => {
    const [token, setToken] = useLocalStorage(TOKEN, null);
    const [refreshToken, setRefreshToken] = useLocalStorage(REFRESH_TOKEN, null);
    const [currentUser, setCurrentUser] = useState();
    const [isUserLoading, setIsUserLoading] = useState(true);

    const navigate = useNavigate();
    const userService = useUserService();
    const authService = useAuthService();
    const { updateMembership, findUserMembership } = useTeamService();

    const fetchUser = useCallback(async () => {
        try {
            if (token) {
                setIsUserLoading(true);
                const { data } = await userService.getUser();

                setCurrentUser(data);
                updateToken(USER_ROLES, data.userRoleNames);
                setTimeout(() => {
                    setIsUserLoading(false);
                }, 1000);

                if (!data.teamId) {
                    navigate('/create-team');
                }
            }
        } catch (e) {
            logout();
            console.error(e);
        }
    }, []);

    const setAuth = (token, refreshToken) => {
        setToken(token);
        setRefreshToken(refreshToken);
    };

    const logout = async () => {
        try {
            if (!currentUser) {
                throw new Error();
            }

            const { data } = await findUserMembership(currentUser.id);

            if (!data) {
                throw new Error();
            }

            await updateMembership({ id: data.id, isActive: false });
        } catch (e) {
            console.log(e);
        } finally {
            updateToken(TOKEN, null);
            updateToken(REFRESH_TOKEN, null);
            updateToken(USER_ROLES, null);
            navigate('/auth/sign-in');
        }
    };

    const changeTeam = async teamId => {
        try {
            const { data } = await authService.changeTeam(teamId);

            setAuth(data.accessToken, data.refreshToken || data.accessToken);
        } catch (error) {
            globalNotification.open({ message: 'This membership is not valid' });
        } finally {
            await fetchUser();
        }
    };

    return (
        <AuthContext.Provider
            value={{
                token,
                setAuth,
                logout,
                fetchUser,
                currentUser,
                isUserLoading,
                changeTeam,
            }}
        >
            {children}
        </AuthContext.Provider>
    );
};

export const useAuth = () => {
    return useContext(AuthContext);
};
```

{% endcode %}

### Components

Components Necessary for Optimal Functioning of the Auth Module

#### Auth Guard

The `AuthGuard` component is a route protection mechanism that checks if a user is authenticated before granting access to specific routes.

#### Key Features:

1. **Authentication Check:**
   * It verifies if the user is on an "auth" route (e.g., `/auth/sign-in`) by checking the URL path.
   * If the user is already authenticated (i.e., has valid tokens stored), they are redirected to the dashboard route.
2. **Route Protection:**
   * If the user is accessing a non-auth route and doesn't have valid tokens (`TOKEN` and `REFRESH_TOKEN` in localStorage), they are redirected to the sign-in page (`auth/sign-in`).

```javascript
import { useLocation } from 'react-router-dom';
import { Navigate } from 'react-router-dom';
import { routesPath } from '../../common/constants/routesPath';
import { TOKEN, REFRESH_TOKEN } from '../../common/constants/localStorage';

function AuthGuard({ children }) {
    const location = useLocation();
    const isAuth = location.pathname.split('/')[1] === 'auth';
    if (isAuth) {
        return getToken(TOKEN) && getToken(REFRESH_TOKEN) ? <Navigate to={routesPath.ROOT.DASHBOARD} /> : children;
    } else {
        return getToken(TOKEN) && getToken(REFRESH_TOKEN) ? children : <Navigate to={'auth/sign-in'} />;
    }
}

const getToken = tokenName => {
    const token = localStorage.getItem(tokenName);

    if (token === null || token === 'undefined') {
        return null;
    }
    return JSON.parse(localStorage.getItem(tokenName));
};

export default AuthGuard;
```

#### GetUser Decorator

This decorator retrieves user data parsed by JwtAuthenticationGuard

```typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { JwtUserPayload } from 'src/common/interfaces/jwt-user-payload.interface';

export const GetUser = createParamDecorator((data, ctx: ExecutionContext): JwtUserPayload => {
    const req = ctx.switchToHttp().getRequest();
    return req.user;
});
```

### Auth Flow Schema

<figure><img src="https://1713127421-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4m1xTBS7F2xndGsJd16w%2Fuploads%2F2gmivWBkayCKQ0FJe2f2%2Fimage.png?alt=media&#x26;token=e51baa31-b4b2-4b3c-9d7a-018480d3e44d" alt="" width="279"><figcaption><p>Auth Flow Block Schema</p></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://intercode.gitbook.io/intercode-saas-kit/pages/auth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
