Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JWT-based user authentication and registration #27

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

cbrianbet
Copy link
Member

@cbrianbet cbrianbet commented Dec 3, 2024

Summary by Sourcery

Add user management features including login, registration, and token refresh using JWT. Simplify registration form by requiring a username instead of first and last names. Clean up code by removing unused Firebase social login components and sample routes.

New Features:

  • Introduce user authentication and registration functionalities using JWT tokens.

Enhancements:

  • Implement token refresh mechanism to maintain user session without re-login.
  • Refactor registration form to use username instead of first and last name.

Chores:

  • Remove unused components and routes related to Firebase social login and sample pages.

Copy link
Contributor

sourcery-ai bot commented Dec 3, 2024

Reviewer's Guide by Sourcery

This PR implements user authentication functionality, including login, registration, and token management. The changes include adding JWT-based authentication, removing unused components, and updating the authentication UI forms.

Sequence diagram for user login process

sequenceDiagram
    actor User
    participant AuthLogin
    participant useUserLogin
    participant API
    participant LocalStorage
    participant Navigate

    User->>AuthLogin: Submit login form
    AuthLogin->>useUserLogin: Call mutateAsync with credentials
    useUserLogin->>API: POST /user/login
    API-->>useUserLogin: Return access and refresh tokens
    useUserLogin-->>AuthLogin: Return tokens
    AuthLogin->>LocalStorage: Store access_token and refresh_token
    AuthLogin->>Navigate: Redirect to home page
Loading

Sequence diagram for user registration process

sequenceDiagram
    actor User
    participant AuthRegister
    participant useUserRegistration
    participant API
    participant Navigate

    User->>AuthRegister: Submit registration form
    AuthRegister->>useUserRegistration: Call mutateAsync with user data
    useUserRegistration->>API: POST /user/register
    API-->>useUserRegistration: Return success response
    useUserRegistration-->>AuthRegister: Return success
    AuthRegister->>Navigate: Redirect to login page
Loading

Sequence diagram for token refresh process

sequenceDiagram
    participant MainLayout
    participant useRefreshAccessToken
    participant API
    participant LocalStorage

    MainLayout->>LocalStorage: Get access_token
    MainLayout->>useRefreshAccessToken: Call mutateAsync if token is expiring
    useRefreshAccessToken->>API: POST /user/refresh
    API-->>useRefreshAccessToken: Return new access_token
    useRefreshAccessToken-->>LocalStorage: Update access_token
Loading

Class diagram for authentication mutations

classDiagram
    class useUserLogin {
        +mutateAsync(user)
    }
    class useUserRegistration {
        +mutateAsync(body)
    }
    class useRefreshAccessToken {
        +mutateAsync()
    }
    class LocalStorage {
        +getItem(key)
        +setItem(key, value)
        +removeItem(key)
    }
    useUserLogin --> API : POST /user/login
    useUserRegistration --> API : POST /user/register
    useRefreshAccessToken --> API : POST /user/refresh
    useRefreshAccessToken --> LocalStorage : Update access_token
    LocalStorage <.. useUserLogin : Store tokens
    LocalStorage <.. useRefreshAccessToken : Get/Update tokens
Loading

File-Level Changes

Change Details Files
Implemented JWT-based authentication system
  • Added token validation and refresh functionality
  • Created authentication API mutations for login and registration
  • Added automatic token refresh mechanism with 30-minute intervals
  • Implemented isAuthenticated check for protected routes
src/layout/MainLayout/index.js
src/store/auth/mutations.js
Updated authentication forms and UI
  • Simplified login form by removing social login options
  • Updated registration form to use username instead of first/last name
  • Removed unused form fields and components
  • Added form validation and error handling
src/pages/authentication/auth-forms/AuthLogin.js
src/pages/authentication/auth-forms/AuthRegister.js
src/pages/authentication/AuthWrapper.js
Cleaned up routing and removed unused components
  • Removed sample pages and unused utility components
  • Cleaned up main routes configuration
  • Removed unused authentication background and footer components
src/routes/MainRoutes.js
src/components/Logo/Logo.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @cbrianbet - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider moving the token refresh logic from MainLayout into a dedicated auth context/provider component to better centralize authentication state management and token handling
Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟡 Security: 1 issue found
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

}

try {
const response = await fetch(`${API_URL}/user/refresh`, { refresh_token: refreshToken });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The refresh token API call is missing proper request configuration

The API call should include Content-Type header and send the refresh token in the request body properly formatted as JSON.


return newAccessToken;
} catch (error) {
console.error('Failed to refresh access token:', error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Token refresh error handling leaves application in invalid state

After clearing tokens on error, the application should redirect to login to ensure user session is properly terminated.


// ==============================|| MAIN LAYOUT ||============================== //

const isAuthenticated = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Token validation logic is duplicated between isAuthenticated and token refresh

Consider extracting the token validation logic into a shared utility function to ensure consistent behavior.

import { validateToken } from 'utils/tokenUtils';

const isAuthenticated = () => validateToken();

})
if(!res.ok){
const error = await res.json()
throw Error(error.detail || 'Login Failed')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 issue (security): Error handling exposes raw server error messages

Consider mapping server errors to user-friendly messages to avoid exposing implementation details.

}
}


const MainLayout = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting authentication logic into a dedicated custom hook

The authentication logic should be extracted into a custom hook to reduce complexity and improve maintainability. Here's how:

// useAuth.js
export const useAuth = () => {
  const refreshToken = useRefreshAccessToken();

  useEffect(() => {
    const checkAndRefreshToken = async () => {
      const token = localStorage.getItem('access_token');
      if (!token) return;

      try {
        const { exp } = jwtDecode(token);
        const currentTime = Date.now() / 1000;
        if (exp < currentTime + 60) {
          await refreshToken.mutateAsync();
        }
      } catch (error) {
        console.error('Token decoding failed:', error);
      }
    };

    checkAndRefreshToken();
    const interval = setInterval(checkAndRefreshToken, 30 * 60 * 1000);
    return () => clearInterval(interval);
  }, [refreshToken]);

  const isAuthenticated = () => {
    const token = localStorage.getItem('access_token');
    if (!token) return false;
    try {
      const { exp } = jwtDecode(token);
      return exp > Date.now() / 1000;
    } catch {
      return false;
    }
  };

  return { isAuthenticated };
};

// MainLayout.js
const MainLayout = () => {
  const { isAuthenticated } = useAuth();
  // ... other existing layout logic ...

  return isAuthenticated() ? (
    <Box sx={{ display: 'flex', width: '100%' }}>
      {/* ... existing layout JSX ... */}
    </Box>
  ) : <Navigate to="/login" replace />;
};

This change:

  1. Encapsulates all authentication logic in a reusable hook
  2. Eliminates duplicate token decoding logic
  3. Makes MainLayout more focused on layout concerns
  4. Improves testability by separating concerns

@cbrianbet cbrianbet changed the title Feat/user management @sourcery-ai Dec 3, 2024
@sourcery-ai sourcery-ai bot changed the title @sourcery-ai Add JWT-based user authentication and registration Dec 3, 2024
cbrianbet and others added 2 commits December 3, 2024 15:16
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant