A comprehensive, production-ready security module for Spring Boot applications with support for JWT authentication, OAuth2 login, and Multi-Factor Authentication (MFA) via email.
- β Dual Authentication Support: JWT and OAuth2 (Google, GitHub, Microsoft) work simultaneously
- π Multi-Factor Authentication (MFA): Email-based verification codes for enhanced security
- π§ Email Verification: Verify user email addresses during registration
- π JWT Token Management: Access and refresh tokens with automatic rotation
- π OAuth2 Integration: Ready-to-use Google, GitHub, and Microsoft login
- βοΈ Configuration-Driven: No hardcoding, fully customizable via properties
- π§© CORS & CSRF Protection: Built-in security best practices
- πͺΆ Plug-and-Play: Works as a starter module or in multi-module projects
- π₯ Role-Based Access Control: Fine-grained endpoint protection
If published as a JAR:
<dependency>
<groupId>com.darpan.starter</groupId>
<artifactId>security</artifactId>
<version>0.0.1</version>
</dependency>If included locally, ensure your project recognizes the module in your multi-module build.
Add the following to your application.properties:
# ============================================
# SECURITY CONFIGURATION
# ============================================
# --- CORS Configuration ---
security.cors.enabled=true
security.cors.allowed-origins=http://localhost:3000
security.cors.allowed-methods=*
security.cors.allowed-headers=*
security.cors.exposed-headers=*
security.cors.allow-credentials=true
security.cors.max-age=3600
# --- Public Endpoints (no authentication required) ---
security.public-endpoints[0]=/auth/register
security.public-endpoints[1]=/auth/login
security.public-endpoints[2]=/auth/refresh/**
security.public-endpoints[3]=/auth/auth-type
security.public-endpoints[4]=/auth/verify-email
security.public-endpoints[5]=/auth/verify-mfa
security.public-endpoints[6]=/auth/resend-code
# --- CSRF Configuration ---
security.csrf.enabled=true
# --- JWT Configuration ---
security.jwt-secret=REPLACE_WITH_STRONG_SECRET_KEY_AT_LEAST_256_BITS
security.jwt-expiration-seconds=900
security.refresh-token-expiration-seconds=86400
# --- MFA Configuration ---
security.mfa-code-expiration-minutes=10
security.mfa-code-length=6
# --- Role-Based Access Control ---
security.role-endpoints[0].pattern=/admin/**
security.role-endpoints[0].roles=ADMIN
security.role-endpoints[1].pattern=/user/**
security.role-endpoints[1].roles=USER# --- GitHub OAuth2 ---
spring.security.oauth2.client.registration.github.client-id=YOUR_GITHUB_CLIENT_ID
spring.security.oauth2.client.registration.github.client-secret=YOUR_GITHUB_CLIENT_SECRET
spring.security.oauth2.client.registration.github.scope=read:user,user:email
# --- Google OAuth2 ---
spring.security.oauth2.client.registration.google.client-id=YOUR_GOOGLE_CLIENT_ID
spring.security.oauth2.client.registration.google.client-secret=YOUR_GOOGLE_CLIENT_SECRET
spring.security.oauth2.client.registration.google.scope=openid,profile,email
spring.security.oauth2.client.provider.google.issuer-uri=https://accounts.google.com
# --- Microsoft/Azure OAuth2 ---
spring.security.oauth2.client.registration.azure.client-id=YOUR_AZURE_CLIENT_ID
spring.security.oauth2.client.registration.azure.client-secret=YOUR_AZURE_CLIENT_SECRET
spring.security.oauth2.client.registration.azure.scope=openid,profile,email
spring.security.oauth2.client.registration.azure.redirect-uri={baseUrl}/login/oauth2/code/azure
spring.security.oauth2.client.provider.azure.authorization-uri=https://login.microsoftonline.com/common/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.azure.token-uri=https://login.microsoftonline.com/common/oauth2/v2.0/token
spring.security.oauth2.client.provider.azure.user-info-uri=https://graph.microsoft.com/oidc/userinfo
spring.security.oauth2.client.provider.azure.jwk-set-uri=https://login.microsoftonline.com/common/discovery/v2.0/keys
spring.security.oauth2.client.provider.azure.user-name-attribute=subMFA requires an email service. Configure your email provider:
# --- Email Configuration (for MFA codes) ---
messaging.mail.host=smtp.gmail.com
messaging.mail.port=587
messaging.mail.username=your-email@gmail.com
messaging.mail.password=your-app-password
messaging.mail.properties.mail.smtp.auth=true
messaging.mail.properties.mail.smtp.starttls.enable=trueNote: For Gmail, use an App Password instead of your regular password.
Ensure Spring scans the security module packages:
package com.test.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@SpringBootApplication
@EntityScan("com.darpan.starter.security.model")
@EnableJpaRepositories("com.darpan.starter.security.repository")
@ComponentScan(basePackages = {
"com.darpan.starter.security",
"com.test.demo" // Your application package
})
@EnableMethodSecurity
@EnableScheduling // Required for MFA code cleanup
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}POST /auth/register
Content-Type: application/json
{
"username": "john_doe",
"email": "john@example.com",
"password": "SecurePass123!"
}Response:
{
"id": 1,
"username": "john_doe",
"email": "john@example.com",
"enabled": false,
"emailVerified": false
}User receives a 6-digit verification code via email.
POST /auth/verify-email
Content-Type: application/json
{
"userId": 1,
"code": "123456"
}Response:
{
"message": "Email verified successfully"
}POST /auth/login
Content-Type: application/json
{
"username": "john_doe",
"password": "SecurePass123!"
}Response (if MFA is disabled):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Response (if MFA is enabled):
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"userId": 1,
"message": "MFA code sent to your email"
}User receives a 6-digit MFA code via email.
POST /auth/verify-mfa
Content-Type: application/json
{
"userId": 1,
"code": "654321"
}Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Simply redirect users to:
- Google:
http://localhost:8080/oauth2/authorization/google - GitHub:
http://localhost:8080/oauth2/authorization/github - Microsoft:
http://localhost:8080/oauth2/authorization/azure
After successful authentication, users are redirected to your configured success URL with a session cookie.
Note: MFA is not applicable for OAuth2 users as providers (Google, GitHub, etc.) handle their own 2FA.
| Endpoint | Method | Description | Auth Required |
|---|---|---|---|
/auth/register |
POST | Register new user | β |
/auth/login |
POST | Login with username/password | β |
/auth/verify-email |
POST | Verify email with code | β |
/auth/verify-mfa |
POST | Verify MFA code during login | β |
/auth/resend-code |
POST | Resend verification/MFA code | β |
/auth/refresh |
POST | Refresh access token | β |
/auth/me |
GET | Get current user info | β |
/auth/toggle-mfa |
POST | Enable/disable MFA | β |
/auth/change-password |
POST | Change user password | β |
/logout |
POST | Logout (clears session) | β |
POST /auth/toggle-mfa
Authorization: Bearer <access_token>
Content-Type: application/json
{
"enabled": true
}Response:
{
"message": "MFA enabled successfully"
}POST /auth/resend-code
Content-Type: application/json
{
"userId": 1,
"type": "LOGIN" // or "REGISTRATION"
}Response:
{
"message": "Code sent successfully"
}The module automatically creates the following tables:
id(Primary Key)username(Unique)email(Unique)password(Hashed)enabled(Boolean)email_verified(Boolean)mfa_enabled(Boolean)- Timestamps
id(Primary Key)name(e.g., "USER", "ADMIN")
user_idrole_id
id(Primary Key)user_id(Foreign Key)token(Refresh Token)active(Boolean)- Timestamps
id(Primary Key)user_id(Foreign Key)code(6-digit code)type(REGISTRATION or LOGIN)expires_at(Timestamp)verified(Boolean)- Timestamps
| Property | Default | Description |
|---|---|---|
security.jwt-secret |
- | Secret key for JWT signing (required) |
security.jwt-expiration-seconds |
900 | Access token expiration (15 min) |
security.refresh-token-expiration-seconds |
86400 | Refresh token expiration (24 hours) |
security.mfa-code-expiration-minutes |
10 | MFA code validity period |
security.mfa-code-length |
6 | Length of MFA codes |
security.cors.enabled |
false | Enable CORS |
security.csrf.enabled |
true | Enable CSRF protection |
security.public-endpoints |
[] | List of public endpoints |
security.role-endpoints |
[] | Role-based endpoint protection |
- JWT Secret: Use a strong, randomly generated secret (at least 256 bits)
- HTTPS: Always use HTTPS in production
- Password Policy: Enforce strong passwords (implemented via regex validation)
- Token Rotation: Refresh tokens are rotated on each use
- MFA Codes: Automatically expire after 10 minutes
- Code Cleanup: Expired MFA codes are cleaned up hourly via scheduled task
- Transaction Isolation: MFA code generation uses
REQUIRES_NEWpropagation to ensure codes are saved even if parent transactions roll back
// Login with MFA handling
const login = async (username: string, password: string) => {
try {
const response = await axios.post('/auth/login', { username, password });
if (response.status === 202) {
// MFA required
const { userId } = response.data;
// Redirect to MFA verification page
navigate(`/verify-mfa?userId=${userId}`);
} else {
// Login successful
const { accessToken, refreshToken } = response.data;
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
}
} catch (error) {
if (error.response?.status === 403) {
// Email not verified
const userId = error.response.data.message.split(':')[1];
navigate(`/verify-email?userId=${userId}`);
}
}
};1. "User not found" during registration
- Ensure
@EnableSchedulingis added to your main application class - Check that email service is properly configured
2. MFA codes not being saved
- Verify
@Modifyingand@Transactionalannotations are present on repository delete methods - Check database connection
3. OAuth2 login not working
- Verify client IDs and secrets are correct
- Ensure redirect URIs match OAuth provider configuration
- Check that the OAuth provider is properly configured in Google/GitHub/Microsoft console
4. CORS errors
- Add your frontend URL to
security.cors.allowed-origins - Ensure
security.cors.allow-credentials=trueif using cookies
This module is part of a private Spring Boot starter collection.
For issues or feature requests, please contact the module maintainer.