A complete, production-ready authentication module with email/password registration and OAuth2 social login support (Google, Facebook, GitHub, Twitter). Built with Spring Boot and React.
Version 1.0.0 - Production Ready | Changelog | Deployment Guide
- Email/Password Registration with industry-standard password requirements
- OAuth2 Social Login - Google, Facebook, GitHub, Twitter
- Multi-Device Session Management with JWT access and refresh tokens
- Automatic Token Refresh on expiration
-
Industry-Standard Password Requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one digit
- At least one special character
- No whitespace allowed
-
Session Management:
- JWT access tokens (15 minutes expiration)
- Refresh tokens (7 days expiration)
- Multi-device support with device tracking
- Automatic token refresh mechanism
-
Security Protections:
- Rate limiting (20 requests/minute per IP)
- Account lockout after 5 failed login attempts (24-hour lock)
- CORS protection
- Secure password hashing (BCrypt)
- XSS and injection prevention
Backend:
- Java 21 LTS (Required - Java 25 is not yet fully supported by Lombok)
- Spring Boot 3.2.1
- Spring Security
- Spring Data JPA
- PostgreSQL
- JWT (JSON Web Tokens)
- OAuth2 Client
- Lombok 1.18.34
Frontend:
- React 18
- TypeScript
- Vite
- Zustand (state management)
- Axios
- React Router
Authentication/
├── src/main/java/com/auth/module/ # Backend (Spring Boot)
│ ├── config/ # Security, CORS, Rate limiting
│ ├── controller/ # REST API endpoints
│ ├── model/ # User, RefreshToken entities
│ ├── repository/ # JPA repositories
│ ├── security/ # JWT, OAuth2, User details
│ ├── service/ # Business logic
│ ├── filter/ # Rate limiting filter
│ └── exception/ # Custom exceptions
├── src/main/resources/
│ └── application.yml # Application configuration
├── frontend/ # Frontend (React)
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API services
│ │ └── store/ # State management
│ └── package.json
├── pom.xml # Maven dependencies
└── README.md
- Java 21 LTS (Required - see note below about Java 25)
- Maven 3.6+
- PostgreSQL 12+
- Node.js 18+
- npm or yarn
This project requires Java 21 LTS. If you have Java 25 installed, Lombok will not work correctly due to compatibility issues.
If you're on macOS with Java 25 installed:
Java 21 has been installed at /opt/homebrew/opt/openjdk@21/. To use it for this project:
# Use Java 21 for the current terminal session
source ./use-java-21.sh
# Or manually set JAVA_HOME
export JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"To make Java 21 your system default (requires sudo):
sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-21.jdkThen verify:
java -version # Should show "openjdk version "21.0.9""Create a PostgreSQL database:
CREATE DATABASE authdb;- Copy the environment example file:
cp .env.example .env-
Generate a secure JWT secret (256-bit minimum):
Option 1 - Using OpenSSL (Recommended):
openssl rand -base64 64
Option 2 - Using Node.js:
node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"Option 3 - Using Python:
python3 -c "import secrets; print(secrets.token_urlsafe(64))"Option 4 - Online Generator:
- Visit: https://generate-secret.vercel.app/64
- Or use any reputable random key generator
Copy the generated key for the next step.
-
Configure your
.envfile:
# Database
DB_USERNAME=postgres
DB_PASSWORD=your_password
# JWT Secret (use the generated key from step 2)
JWT_SECRET=<paste-your-generated-secret-here>
# OAuth2 Credentials (get these from OAuth provider consoles)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
FACEBOOK_CLIENT_ID=your-facebook-app-id
FACEBOOK_CLIENT_SECRET=your-facebook-app-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
TWITTER_CLIENT_ID=your-twitter-client-id
TWITTER_CLIENT_SECRET=your-twitter-client-secret- Update
src/main/resources/application.ymlif needed
Step-by-step guide to create Google OAuth2 credentials:
-
Access Google Cloud Console
- Navigate to Google Cloud Console
- Sign in with your Google account
-
Create a New Project (or select an existing one)
- Click the project dropdown at the top of the page
- Click "New Project"
- Enter a project name (e.g., "Authentication Module")
- Click "Create"
- Wait for the project to be created and select it
-
Enable Required APIs
- In the left sidebar, go to "APIs & Services" > "Library"
- Search for "Google+ API" or "Google People API"
- Click on it and press "Enable"
- Alternatively, search for "Google Identity Services" and enable it
-
Configure OAuth Consent Screen (Required before creating credentials)
- Go to "APIs & Services" > "OAuth consent screen"
- Select "External" user type (unless you have a Google Workspace)
- Click "Create"
- Fill in the required information:
- App name: Your application name (e.g., "Authentication Module")
- User support email: Your email address
- Developer contact information: Your email address
- Click "Save and Continue"
- On the "Scopes" page, click "Add or Remove Scopes"
- Add these scopes:
userinfo.emailuserinfo.profileopenid
- Click "Update" then "Save and Continue"
- Add these scopes:
- On "Test users" page, click "Save and Continue"
- Review the summary and click "Back to Dashboard"
-
Create OAuth 2.0 Credentials
- Go to "APIs & Services" > "Credentials"
- Click "Create Credentials" > "OAuth client ID"
- Select "Web application" as the application type
- Configure the OAuth client:
- Name: Give it a descriptive name (e.g., "Auth Module Web Client")
- Authorized JavaScript origins: Add
http://localhost:8080 - Authorized redirect URIs: Add the following URIs:
http://localhost:8080/oauth2/callback/googlehttp://localhost:8080/login/oauth2/code/google(Spring Security default)
- Click "Create"
-
Save Your Credentials
- A dialog will appear showing your Client ID and Client Secret
- IMPORTANT: Copy both values immediately
- Add them to your
.envfile:GOOGLE_CLIENT_ID=your-client-id-here.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=your-client-secret-here
-
For Production Deployment
- Go back to "OAuth consent screen"
- Click "Publish App" to make it available to all users
- Add your production redirect URIs in the OAuth client settings:
https://yourdomain.com/oauth2/callback/googlehttps://yourdomain.com/login/oauth2/code/google
Common Issues:
- If you get "redirect_uri_mismatch" error, ensure the redirect URI in your app exactly matches what's registered in Google Cloud Console
- The consent screen must be configured before creating OAuth credentials
- For testing, you can keep the app in "Testing" mode and add test users manually
- Go to Facebook Developers
- Create a new app
- Add Facebook Login product
- Add redirect URI:
http://localhost:8080/oauth2/callback/facebook
- Go to GitHub Settings > Developer settings > OAuth Apps
- Create new OAuth App
- Add callback URL:
http://localhost:8080/oauth2/callback/github
- Go to Twitter Developer Portal
- Create a new app
- Enable OAuth 2.0
- Add callback URI:
http://localhost:8080/oauth2/callback/twitter
# From project root
mvn clean install
mvn spring-boot:runBackend will run on http://localhost:8080
# Navigate to frontend directory
cd frontend
# Install dependencies
npm install
# Start development server
npm run devFrontend will run on http://localhost:3000
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/signup |
Register with email/password |
| POST | /api/auth/login |
Login with email/password |
| POST | /api/auth/refresh |
Refresh access token |
| POST | /api/auth/logout |
Logout and revoke refresh token |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user/me |
Get current user profile |
| Method | Endpoint | Description |
|---|---|---|
| GET | /oauth2/authorize/{provider} |
Initiate OAuth2 login |
| GET | /oauth2/callback/{provider} |
OAuth2 callback |
- Copy the
com.auth.modulepackage to your project - Add dependencies from
pom.xml - Configure
application.ymlwith your database and OAuth2 settings - Extend security configuration as needed
- Copy the
frontend/src/componentsfolder (Login, Signup, OAuth2RedirectHandler) - Copy
frontend/src/services/authService.ts - Copy
frontend/src/store/authStore.ts - Install dependencies:
react-router-dom,axios,zustand - Import and use components:
import Login from './components/Login';
import Signup from './components/Signup';
function App() {
return (
<Login onSuccess={() => console.log('Logged in!')} />
);
}The module enforces NIST-compliant password standards:
- ✅ Minimum 8 characters
- ✅ At least 1 uppercase letter (A-Z)
- ✅ At least 1 lowercase letter (a-z)
- ✅ At least 1 digit (0-9)
- ✅ At least 1 special character (!@#$%^&*...)
- ✅ No whitespace
- ✅ Protection against common passwords
- ✅ Protection against sequential patterns
- Access Token: 15 minutes (industry standard for high-security apps)
- Refresh Token: 7 days (stored securely in database)
- Automatic token refresh before expiration
- Multi-device support - each device gets its own refresh token
- Each login creates a unique refresh token
- Users can be logged in on multiple devices simultaneously
- Track device info and IP address for each session
- Revoke tokens individually or all at once
- Never commit
.envfile - it contains secrets - Generate strong JWT secret - use at least 256 bits (64 characters in base64)
# Quick command to generate a secure secret: openssl rand -base64 64 - Use HTTPS in production - update CORS and OAuth redirect URIs
- Rotate JWT secrets periodically (every 90 days recommended)
- Monitor failed login attempts - investigate patterns
- Review active sessions regularly - check for suspicious devices
- Keep dependencies updated - run
mvn versions:display-dependency-updates - Use different secrets for different environments (dev, staging, production)
-
Update
application.ymlfor production:- Change database URL
- Use environment variables for secrets
- Enable HTTPS
- Update CORS allowed origins
-
Build production JAR:
mvn clean package -DskipTests
java -jar target/authentication-module-1.0.0.jar- Update API URLs in
vite.config.ts - Build production bundle:
npm run build- Deploy
dist/folder to your hosting service
Edit application.yml:
app:
auth:
jwt-expiration-ms: 900000 # 15 minutes
jwt-refresh-expiration-ms: 604800000 # 7 daysEdit RateLimitConfig.java:
Bandwidth limit = Bandwidth.classic(20, Refill.intervally(20, Duration.ofMinutes(1)));- Update
Userentity inmodel/User.java - Update database migrations
- Update DTOs and responses
The application includes comprehensive test coverage with unit tests and integration tests.
# Run all tests
mvn test
# Run tests with coverage report
mvn test jacoco:report
# Run specific test class
mvn test -Dtest=PasswordValidationServiceTest
# Run tests in a specific package
mvn test -Dtest=com.auth.module.service.*src/test/java/com/auth/module/
├── controller/
│ ├── AuthControllerIntegrationTest.java # API endpoint tests
│ └── UserControllerIntegrationTest.java # User profile tests
├── service/
│ ├── PasswordValidationServiceTest.java # Password validation tests
│ └── RefreshTokenServiceTest.java # Token management tests
└── security/
└── JwtTokenProviderTest.java # JWT token tests
Unit Tests:
-
✅ Password validation (17 test cases)
- Valid/invalid password formats
- Length requirements
- Character requirements (uppercase, lowercase, digits, special chars)
- Whitespace handling
-
✅ JWT token operations (14 test cases)
- Token generation and validation
- Token expiration
- User ID extraction
- Invalid/malformed token handling
-
✅ Refresh token management (12 test cases)
- Token creation and verification
- Token revocation
- Multi-device support
- Active token filtering
Integration Tests:
-
✅ Authentication endpoints (11 test cases)
- User registration
- Login/logout flows
- Token refresh
- Input validation
-
✅ User profile endpoints (6 test cases)
- Authenticated access
- Token-based security
- Response validation
Tests use H2 in-memory database for isolation:
# src/test/resources/application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
jpa:
hibernate:
ddl-auto: create-drop- JUnit 5: Test framework
- Mockito: Mocking framework
- Spring Boot Test: Integration testing
- H2 Database: In-memory database for tests
- MockMvc: API endpoint testing
- AssertJ: Fluent assertions
Unit Test Example:
@Test
@DisplayName("Should validate correct password successfully")
void shouldValidateCorrectPassword() {
// Given
String validPassword = "SecurePass123!";
// When
PasswordValidationResult result =
passwordValidationService.validatePassword(validPassword);
// Then
assertTrue(result.isValid());
}Integration Test Example:
@Test
@DisplayName("Should register new user successfully")
void shouldRegisterNewUserSuccessfully() throws Exception {
// Given
SignUpRequest request = new SignUpRequest();
request.setEmail("test@example.com");
request.setPassword("SecurePass123!");
// When & Then
mockMvc.perform(post("/api/auth/signup")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.accessToken").exists());
}Tests are designed to run in CI/CD pipelines:
# Example GitHub Actions
- name: Run tests
run: mvn clean test
- name: Generate coverage report
run: mvn jacoco:reportThe application includes comprehensive logging throughout all components with configurable log levels.
Configure logging in .env file or directly in application.yml:
# Set to DEBUG for development, INFO for production
LOG_LEVEL=INFO
LOG_LEVEL_CONTROLLER=INFO
LOG_LEVEL_SERVICE=INFO
LOG_LEVEL_SECURITY=INFO
LOG_LEVEL_FILTER=INFO- DEBUG: Detailed information including request parameters, token processing, validation steps
- INFO: General operational messages (user actions, successful operations)
- WARN: Warning messages (invalid tokens, rate limit violations, validation failures)
- ERROR: Error messages with stack traces
Controllers (AuthController, UserController):
- Request received (INFO)
- Request parameters and IP addresses (DEBUG)
- Success/failure outcomes (INFO/ERROR)
Services (AuthService, RefreshTokenService):
- Operation start/completion (INFO)
- Processing steps (DEBUG)
- Validation failures (WARN)
- Errors with details (ERROR)
Security (JwtTokenProvider, JwtAuthenticationFilter):
- Token generation/validation (DEBUG)
- Authentication success/failure (INFO/WARN)
- JWT signature/expiration errors (ERROR)
Filters (RateLimitFilter):
- Rate limit checks (DEBUG)
- Rate limit exceeded (WARN)
Logs are written to:
- Console: All environments
- File:
logs/authentication-module.log
Log files automatically rotate:
- Maximum file size: 10MB
- History kept: 30 days
The logging implementation ensures:
- ✅ Passwords are NEVER logged
- ✅ Full tokens are NEVER logged (only first 10 characters)
- ✅ Sensitive user data is excluded from logs
- ✅ Stack traces only logged at ERROR level
2026-01-09 10:30:45 - c.a.m.controller.AuthController - Received login request for email: user@example.com
2026-01-09 10:30:45 - c.a.m.service.AuthService - Starting authentication process for email: user@example.com
2026-01-09 10:30:45 - c.a.m.service.RefreshTokenService - Creating refresh token for userId: 123
2026-01-09 10:30:45 - c.a.m.controller.AuthController - User authentication successful for email: user@example.com
- Ensure PostgreSQL is running
- Check database credentials in
.env - Verify database exists
- Check OAuth2 client IDs and secrets
- Verify redirect URIs match in provider console
- Ensure frontend and backend URLs are correct
- Check if refresh token is expired or revoked
- Verify JWT secret is consistent
- Check axios interceptor configuration
For troubleshooting issues:
-
Enable DEBUG logging:
LOG_LEVEL=DEBUG LOG_LEVEL_CONTROLLER=DEBUG LOG_LEVEL_SERVICE=DEBUG
-
Check log file:
logs/authentication-module.log -
Common patterns:
- Authentication failures: Search for "authentication failed"
- Token issues: Search for "JWT" or "token"
- Rate limiting: Search for "rate limit exceeded"
- OAuth2 issues: Search for "OAuth2"
MIT License - feel free to use this in your projects!
For issues and questions, please check the code comments and configuration files. All major components are well-documented.