A full-stack demonstration application showcasing user authentication with login and signup functionality built with Spring Boot and Next.js, using SQLite for persistence.
- Overview
- Technology Stack
- Project Structure
- Prerequisites
- Installation & Setup
- Running the Application
- API Endpoints
- Features
- Security Notes
This project demonstrates a complete user authentication flow with:
- User registration (signup) with email and password
- User login with JWT token-based authentication
- Secure password handling
- Protected API endpoints
- Java 21 - Programming language
- Spring Boot 4.0.3 - Framework
- Spring Data JPA - ORM and database abstraction
- SQLite - Lightweight relational database
- JWT (JSON Web Tokens) - For authentication
- Maven - Dependency management and build tool
- Next.js 16.1.6 - React framework with SSR
- React 19.2.3 - UI library
- TypeScript - Type safety
- Tailwind CSS - Utility-first CSS framework
- Shadcn UI - Component library
- Next Themes - Dark mode support
- Sonner - Toast notifications
login_signup/
├── README.md (this file)
├── backend/ # Spring Boot application
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/example/demo/
│ │ │ │ ├── DemoApplication.java
│ │ │ │ ├── config/ # Spring configurations
│ │ │ │ │ ├── WebConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── exception/ # Custom exceptions
│ │ │ │ │ ├── DuplicateResourceException.java
│ │ │ │ │ ├── ErrorResponse.java
│ │ │ │ │ ├── GlobalExceptionHandler.java
│ │ │ │ │ └── ResourceNotFoundException.java
│ │ │ │ ├── security/ # Authentication & JWT
│ │ │ │ │ ├── AuthController.java
│ │ │ │ │ ├── AuthEntryPointJwt.java
│ │ │ │ │ ├── AuthService.java
│ │ │ │ │ ├── AuthTokenFilter.java
│ │ │ │ │ ├── CustomUserDetailsService.java
│ │ │ │ │ ├── JwtUtil.java
│ │ │ │ │ └── UserPrincipal.java
│ │ │ │ └── user/ # User domain
│ │ │ │ ├── User.java
│ │ │ │ ├── UserDto.java
│ │ │ │ ├── UserRepository.java
│ │ │ │ └── UserService.java
│ │ │ └── resources/
│ │ │ └── application.yaml # Configuration file
│ │ └── test/
│ └── target/ # Build output
├── frontend/ # Next.js application
│ ├── package.json
│ ├── tsconfig.json
│ ├── next.config.ts
│ ├── tailwind.config.js
│ ├── app/ # App directory (Next.js 13+)
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/ # React components
│ │ ├── (landing)/ # Landing page components
│ │ │ ├── login-badge.tsx
│ │ │ ├── login-dialog.tsx
│ │ │ ├── logout-button.tsx
│ │ │ └── signup-dialog.tsx
│ │ ├── ui/ # Shadcn UI components
│ │ ├── theme-provider.tsx
│ │ └── mode-toggle.tsx
│ ├── context/ # React Context
│ │ └── AuthContext.tsx
│ ├── lib/
│ │ └── utils.ts
│ └── public/
Ensure you have the following installed:
- Java 21 or higher
- Maven 3.6.0 or higher (for building the backend)
- Node.js 18.17 or higher
- pnpm (or npm/yarn)
- Git (optional, for version control)
-
Navigate to the backend directory:
cd backend -
Set up the database and build the project:
./mvnw clean install
(On Windows, use
mvnw.cmdinstead of./mvnw) -
Configuration:
- The SQLite database file (
user.db) will be created automatically in the backend root directory - Default configuration is in
src/main/resources/application.yaml - Important: For production, update the JWT secret key in
application.yaml:jwt: secret: your-very-secure-secret-key-at-least-256-bits-long
- The SQLite database file (
-
Navigate to the frontend directory:
cd frontend -
Install dependencies:
pnpm install
cd backend
./mvnw spring-boot:runThe backend will start on http://localhost:8080
In a new terminal:
cd frontend
pnpm run devThe frontend will start on http://localhost:3000
Visit http://localhost:3000 in your browser to access the application.
All endpoints are prefixed with http://localhost:8080/api/auth
- POST
/signup - Request body:
{ "email": "user@example.com", "password": "securePassword123" } - Response:
- Status:
201 Created - Headers:
Set-Cookiewith JWT token in httpOnly cookie (24 hour expiration) - Body: Empty
⚠️ Demo Note: In production, should return a DTO with user data or similar (e.g.,AuthResponsecontaining user ID, email, success message)
- Status:
- POST
/login - Request body:
{ "email": "user@example.com", "password": "securePassword123" } - Response:
- Status:
200 OK - Headers:
Set-Cookiewith JWT token in httpOnly cookie (24 hour expiration) - Body: Empty
⚠️ Demo Note: In production, should return a DTO with user data or similar (e.g.,AuthResponsecontaining user ID, email, token details)
- Status:
- POST
/logout - Response:
- Status:
200 OK - Headers:
Set-Cookiewith expired token (maxAge=0) - Body:
"Logged out successfully"
- Status:
- GET
/me - Headers: Requires valid JWT cookie (or Authorization header)
- Response:
- Status:
200 OK - Body: Empty
⚠️ Demo Note: In production, should return a DTO with user details or similar (e.g.,UserResponsewith user ID, email, roles)
- Status:
- ✅ User Registration - Create new user accounts with email and password
- ✅ User Login - Authenticate with JWT tokens
- ✅ Password Security - Passwords are hashed before storage
- ✅ Duplicate Prevention - Email uniqueness validation
- ✅ Error Handling - Comprehensive error responses
- ✅ Dark Mode Support - Toggle between light and dark themes
- ✅ Toast Notifications - User-friendly feedback messages
- ✅ Responsive Design - Mobile-friendly UI with Tailwind CSS
- ✅ Type Safety - Full TypeScript support in frontend
- JWT Secret Key: The default secret key is weak. Change it to a strong, random string at least 256 bits long.
- Password Hashing: Ensure Spring Security's password encoder is properly configured in production.
- CORS Configuration: Review and configure CORS settings in
WebConfig.javafor your specific domain. - HTTPS: Always use HTTPS in production.
- Token Expiration: The default token expiration is 24 hours. Adjust as needed.
- Environment Variables: Store sensitive configuration (JWT secret, database credentials) in environment variables, not in code.
- Input Validation: Additional validation should be added for email format and password strength.
- The SQLite database is file-based and stored in the backend root directory as
user.db - The application uses JWT tokens for stateless authentication
- The frontend uses React Context for state management
This project is provided as a demonstration for educational purposes.