This document outlines the security implementation for the Book Shelf application, including JWT authentication, OAuth2 integration, and authorization controls.
- Security Features
- Authentication Methods
- Authorization Model
- Public vs Protected Endpoints
- OAuth2 Integration
- JWT Token Management
- Security Best Practices
- Testing OAuth2 Flow
- ✅ JWT-based stateless authentication
- ✅ OAuth2 login (Google & GitHub)
- ✅ Role-based access control (RBAC)
- ✅ Password encryption (BCrypt with strength 12)
- ✅ Token expiration (30 minutes for access, 7 days for refresh)
- ✅ Role version tracking (token invalidation on role change)
- ✅ Ownership validation for comments
- ✅ Input validation and sanitization
- ✅ CORS support
- ✅ Public read-only endpoints for browsing
Endpoint: POST /login
Request Body:
{
"username": "user@example.com",
"password": "password123"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "user@example.com",
"role": "USER"
}Endpoints:
- Google:
GET /oauth2/authorization/google - GitHub:
GET /oauth2/authorization/github
Flow:
- User clicks "Login with Google/GitHub"
- Redirected to OAuth2 provider
- User authorizes the application
- Redirected back to app with authorization code
- Backend exchanges code for user info
- Backend creates/finds user and generates JWT
- Redirected to frontend with JWT token:
http://localhost:3000/oauth2/redirect?token={JWT}
- ADMIN: Full access (CRUD operations on books, comments, ratings)
- USER: Can rate and comment on books
| Action | Public | USER | ADMIN |
|---|---|---|---|
| Browse books (GET /books) | ✅ | ✅ | ✅ |
| View book details (GET /bookid/{id}) | ✅ | ✅ | ✅ |
| Search books (GET /books/search) | ✅ | ✅ | ✅ |
| View ratings (GET /book/{id}/ratings) | ✅ | ✅ | ✅ |
| View comments (GET /book/{id}/comment) | ✅ | ✅ | ✅ |
| Add book (POST /addbook) | ❌ | ❌ | ✅ |
| Update book (PUT /book/{id}) | ❌ | ❌ | ✅ |
| Delete book (DELETE /book/{id}) | ❌ | ❌ | ✅ |
| Add rating (POST /book/{id}/rating) | ❌ | ✅ | ✅ |
| Add comment (POST /book/{id}/comment) | ❌ | ✅ | ✅ |
| Update own comment (PUT /book/{id}/comment) | ❌ | ✅ (own) | ✅ |
| Delete own comment (DELETE /comment/{id}) | ❌ | ✅ (own) | ✅ (any) |
GET /books - List all books (paginated)
GET /bookid/{id} - Get book details
GET /books/search - Search books by title/author/category
GET /book/{id}/ratings - Get rating statistics
GET /book/{id}/comment - Get comments for a book
POST /register - Register new user
POST /login - Login with credentials
GET /oauth2/authorization/* - OAuth2 login endpoints
POST /addbook - Add new book (ADMIN only)
PUT /book/{id} - Update book (ADMIN only)
DELETE /book/{id} - Delete book (ADMIN only)
POST /book/{id}/rating - Add rating (USER/ADMIN)
POST /book/{id}/comment - Add comment (USER/ADMIN)
PUT /book/{id}/comment - Update comment (USER/ADMIN, ownership check)
DELETE /comment/{commentId} - Delete comment (USER/ADMIN, ownership check)
Google OAuth2:
- Client ID: Configured in
application.properties - Scopes:
profile,email - Redirect URI:
http://localhost:8080/login/oauth2/code/google
GitHub OAuth2:
- Client ID: Configured in
application.properties - Scopes:
user:email - Redirect URI:
http://localhost:8080/login/oauth2/code/github
The OAuth2LoginSuccessHandler handles successful OAuth2 authentication:
- Extracts user email and name from OAuth2 provider
- Creates new user if doesn't exist (role: USER)
- Generates JWT token with user info
- Redirects to frontend with token parameter
// Redirect user to OAuth2 provider
window.location.href = 'http://localhost:8080/oauth2/authorization/google';
// Handle callback
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
if (token) {
localStorage.setItem('jwt_token', token);
// Redirect to dashboard
}{
"sub": "user@example.com",
"role": "USER",
"roleVersion": 0,
"userId": 123,
"iat": 1634567890,
"exp": 1634569690
}- Access Token: Short-lived (30 minutes), used for API requests
- Refresh Token: Long-lived (7 days), used to get new access tokens
# Include JWT in Authorization header
curl -H "Authorization: Bearer {JWT_TOKEN}" \
http://localhost:8080/book/1/comment- Access tokens expire after 30 minutes
- Frontend should handle 401 responses and refresh tokens
- Role version changes invalidate all existing tokens
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-
Password Security
- BCrypt hashing with strength 12
- No plain text storage
-
Token Security
- Short expiration times
- Signature validation
- Role version tracking for invalidation
-
Input Validation
- Comment length limited to 1000 characters
- Rating values validated (1-5)
- Empty content rejected
-
Ownership Validation
- Users can only modify their own comments
- Admins can delete any comment
-
Error Handling
- Generic error messages (no info leakage)
- Proper HTTP status codes
- Detailed logging (server-side only)
-
Production Security
# Generate strong JWT secret (DO NOT use in production as-is) jwt.secret=USE_OPENSSL_RAND_BASE64_32_TO_GENERATE # Use environment variables JWT_SECRET=${JWT_SECRET} GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
-
Rate Limiting
- Add rate limiting for login/register endpoints
- Prevent brute force attacks
-
HTTPS
- Use HTTPS in production
- Enable HSTS headers
-
CORS Configuration
- Restrict allowed origins in production
- Update
WebConfig.javawith specific domains
-
Database Security
- Use database user with minimum required privileges
- Enable SSL for database connections
- Navigate to:
http://localhost:8080/oauth2/authorization/google - Login with Google account
- Grant permissions
- Verify redirect with JWT token
- Use token for authenticated requests
- Navigate to:
http://localhost:8080/oauth2/authorization/github - Login with GitHub account
- Grant permissions
- Verify redirect with JWT token
- Use token for authenticated requests
# Login
TOKEN=$(curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"user@example.com","password":"password123"}' \
| jq -r '.token')
# Use token
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/book/1/commentKey security configurations:
- JWT secret and expiration times
- OAuth2 client credentials
- Session management
- Error message inclusion
- Defines public vs protected endpoints
- Configures OAuth2 login
- Sets up JWT filter chain
- Configures password encoder
- Validates JWT tokens
- Sets authentication context
- Handles token errors gracefully
-
401 Unauthorized
- Token expired (check expiration time)
- Invalid token signature
- Role version mismatch
-
403 Forbidden
- User doesn't have required role
- Attempting to modify another user's content
-
OAuth2 Redirect Issues
- Check redirect URI configuration
- Verify OAuth2 app credentials
- Ensure frontend URL is correct
Enable debug logging in application.properties:
logging.level.com.marvel.springsecurity=DEBUG
logging.level.org.springframework.security=DEBUGThis implementation provides:
- ✅ Secure JWT-based authentication
- ✅ OAuth2 integration for social login
- ✅ Role-based access control
- ✅ Public browsing without authentication
- ✅ Ownership validation for user-generated content
- ✅ Industry-standard security practices
All critical endpoints are protected, and the system follows the principle of least privilege.