A secure Twitter-like web application that allows authenticated users to create and view short posts (maximum 140 characters) in a single public global stream. The project begins as a Spring Boot monolith with full Swagger/OpenAPI documentation and evolves into independent microservices (Posts, Feed, and User Authentication) communicating asynchronously via RabbitMQ events. The entire API is secured using Auth0 JWT tokens, and the frontend is built with React using the Auth0 React SDK.
Phase 1 – Monolith
Phase 2 – Microservices
User → Auth0 Login → JWT Access Token
JWT Token → Spring Boot OAuth2 Resource Server
Resource Server → Validates issuer (https://YOUR_DOMAIN.auth0.com/)
→ Validates audience (https://twitter-api)
→ Grants/denies access
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
- Java 21 – Download
- Maven 3.8+ – Download
- Node.js 18+ and npm – Download
- MongoDB – Local installation or MongoDB Atlas (free tier)
- RabbitMQ – CloudAMQP free tier (Little Lemur plan)
- Auth0 account – Sign up free
- Git – Download
# Verify Java
java -version # should show 21.x
# Verify Maven
mvn -version
# Verify Node
node -version # should show 18.x or higherBefore running the application, set up Auth0:
-
Create a Single Page Application (SPA) in your Auth0 dashboard.
- Note the Domain and Client ID.
- Set Allowed Callback URLs:
http://localhost:3000 - Set Allowed Logout URLs:
http://localhost:3000 - Set Allowed Web Origins:
http://localhost:3000
-
Create an API in Auth0.
- Set the Identifier (Audience) to:
https://twitter-api - Enable RBAC and add the following permissions/scopes:
read:posts,write:posts,read:profile
- Set the Identifier (Audience) to:
1. Clone the repository
git clone https://github.com/tulio3101/TwitterSpringBoot.git
cd TwitterSpringBoot2. Set up RabbitMQ via CloudAMQP
This project uses CloudAMQP (free tier) as its AMQP broker — no local installation required.
- Create a free account at cloudamqp.com
- Create a new instance — select the Little Lemur plan (free)
- Open the instance details and copy the AMQP URL (format:
amqps://user:password@host/vhost) - Use the individual parts of that URL to populate the
RABBITMQ_*environment variables in the next step
3. Configure environment variables
Each Spring Boot service reads configuration from environment variables. Set the following before running each service:
| Variable | Used By | Description |
|---|---|---|
MONGODB_URI |
All services | MongoDB connection string |
AUTH0_ISSUER_URI |
Twitter (Gateway) | https://YOUR_DOMAIN.auth0.com/ |
CORS_ALLOWED_ORIGIN |
Twitter (Gateway) | Frontend origin, e.g. http://localhost:3000 |
SERVER_PORT |
Twitter (Gateway) | Service port (default: 4040) |
RABBITMQ_HOST |
PostsService, FeedService | CloudAMQP hostname (e.g. your-instance.cloudamqp.com) |
RABBITMQ_PORT |
PostsService, FeedService | AMQP port (5672 for AMQP, 5671 for AMQPS) |
RABBITMQ_USERNAME |
PostsService, FeedService | CloudAMQP username |
RABBITMQ_PASSWORD |
PostsService, FeedService | CloudAMQP password |
RABBITMQ_VIRTUAL_HOST |
PostsService, FeedService | CloudAMQP virtual host (same as your username by default) |
Example (Linux/macOS):
export MONGODB_URI="mongodb+srv://user:password@cluster.mongodb.net/twitter"
export AUTH0_ISSUER_URI="https://YOUR_DOMAIN.auth0.com/"
export CORS_ALLOWED_ORIGIN="http://localhost:3000"
export RABBITMQ_HOST="your-instance.cloudamqp.com"
export RABBITMQ_PORT="5672"
export RABBITMQ_USERNAME="your-cloudamqp-user"
export RABBITMQ_PASSWORD="your-cloudamqp-password"
export RABBITMQ_VIRTUAL_HOST="your-cloudamqp-vhost"4. Build and run the Spring Boot services
Run each service in a separate terminal:
# Terminal 1 – Twitter API Gateway (Monolith / Gateway)
cd Twitter
mvn spring-boot:run
# Runs on port 4040# Terminal 2 – PostsService (Microservice)
cd PostsService
mvn spring-boot:run
# Runs on port 8081# Terminal 3 – FeedService (Microservice)
cd FeedService
mvn spring-boot:run
# Runs on port 8082# Terminal 4 – UserAuthentication (Microservice)
cd UserAuthentication
mvn spring-boot:run
# Runs on port 80825. Configure and run the frontend
Create a .env file inside the twitter-frontend directory:
REACT_APP_AUTH0_DOMAIN=YOUR_DOMAIN.auth0.com
REACT_APP_AUTH0_CLIENT_ID=YOUR_CLIENT_ID
REACT_APP_API_BASE_URL=http://localhost:4040Then install dependencies and start the dev server:
cd twitter-frontend
npm install
npm startThe frontend will be available at http://localhost:3000.
6. Quick demo – create your first post
After logging in via the frontend, you can also test the API directly. Obtain a JWT token from your Auth0 tenant and run:
curl -X POST http://localhost:4040/api/posts/create \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"message": "Hello from TwitterSpringBoot!"}'Then view the public stream (no authentication needed):
curl http://localhost:4040/api/streamThe monolith exposes a full Swagger UI powered by Springdoc OpenAPI 2.6.0:
- Swagger UI:
http://localhost:4040/swagger-ui.html - OpenAPI JSON spec:
http://localhost:4040/v3/api-docs
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
GET |
/api/posts |
No | Retrieve all posts |
POST |
/api/posts/create |
Yes | Create a new post (max 140 chars) |
PUT |
/api/posts/update/{postId} |
Yes | Update an existing post |
DELETE |
/api/posts/{postId} |
Yes | Delete a post |
GET |
/api/stream |
No | Get the global public feed |
DELETE |
/api/stream/{postId} |
Yes | Remove a post from the stream |
POST |
/api/users/me |
Yes | Register the currently authenticated user |
GET |
/api/users/me |
Yes | Get the current user's profile |
GET |
/api/users/{id} |
No | Get a user profile by ID |
Protected endpoints require a valid JWT Bearer token issued by Auth0 with audience https://twitter-api.
Explain how to run the automated tests for this system.
Each microservice includes a Spring Boot application context test. Run from each service directory:
# Run from each service root directory (Twitter, PostsService, FeedService, UserAuthentication)
mvn testThese tests verify that the Spring Boot application context loads correctly with all beans, security configuration, and database connections.
Via Swagger UI:
- Open
http://localhost:4040/swagger-ui.html - Click Authorize and paste your JWT token (obtained from Auth0 or the frontend after login)
- Test each protected endpoint directly from the browser
For example, to test post creation:
- Expand
POST /api/posts/create - Click Try it out
- Enter
{"message": "Hello from Swagger!"}as the request body - Execute and verify a
201 Createdresponse
Via curl:
# Public endpoint – no token required
curl -X GET http://localhost:4040/api/posts
# Public endpoint – get global stream
curl -X GET http://localhost:4040/api/stream
# Protected endpoint – create a post
curl -X POST http://localhost:4040/api/posts/create \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"message": "Test post from curl"}'
# Protected endpoint – get current user profile (/api/me equivalent)
curl -X GET http://localhost:4040/api/users/me \
-H "Authorization: Bearer <JWT>"- Open the frontend at
http://localhost:3000 - Click Login — you are redirected to Auth0
- Authenticate with your credentials
- You are redirected back with a valid JWT stored in localStorage
- Create a post using the form — it should appear in the public feed
- Log out and verify the feed is still publicly readable without authentication
The React single-page application is built (npm run build) and deployed as static assets. The frontend authenticates users via Auth0 and makes secure, cross-origin HTTP requests to the AWS API Gateway (for serverless components) and the EC2 instance (for the feed).
To comply with the serverless architecture while maintaining the event-driven messaging requirement (RabbitMQ):
- PostsService & UserAuthentication: Deployed as AWS Lambda functions behind a single AWS API Gateway using
aws-serverless-java-container. This allows Spring Boot's@RestControllerand Spring Security (Auth0 JWT validation) to run seamlessly in a serverless environment. - FeedService: Deployed on an AWS EC2 instance. This architectural decision was made because RabbitMQ requires a persistent, long-lived TCP connection (
@RabbitListener) which is fundamentally incompatible with the ephemeral, freeze-thaw lifecycle of AWS Lambda.
- Spring Boot 3.5.13 — Java backend framework
- Maven — Dependency management and build tool
- Spring Data MongoDB — MongoDB persistence
- Spring AMQP / RabbitMQ — Asynchronous event messaging between microservices
- Auth0 — Identity and authorization provider
- Spring Security OAuth2 Resource Server — JWT validation
- Springdoc OpenAPI 2.6.0 — Swagger / OpenAPI documentation
- React 19 — Frontend framework
- Auth0 React SDK — Frontend authentication and token management
- Tailwind CSS 4 — Utility-first CSS styling
- MapStruct 1.5.5 — DTO / entity mapping
- Lombok — Java boilerplate reduction
- Tulio Riaño Sánchez — tulio3101
- Juan Sebastián Puentes Julio - sebasPuentes
This project is licensed under the MIT License — see the LICENSE file for details.
- Auth0 Documentation for the OAuth2/JWT integration guides
- Spring Security OAuth2 documentation for resource server configuration
- Springdoc OpenAPI for Swagger integration with Spring Boot 3










