-
Notifications
You must be signed in to change notification settings - Fork 7
feat: add automatic database schema initialization and readme #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d0d4e0e
feat: add automatic database schema initialization
matthewhou19 f50bd69
Update docker-compose.yml
matthewhou19 638dc7d
Update apigateway/src/main/resources/schema.sql
matthewhou19 c66915f
Update apigateway/src/main/resources/application.yaml
matthewhou19 d41e378
fix: standardize database name and refactor endpoint to RESTful conve…
matthewhou19 d363b7d
Update docker-compose.yml
matthewhou19 3c61b48
Update apigateway/src/main/java/vaultweb/apigateway/controller/Gatewa…
matthewhou19 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,196 @@ | ||
| # Auth-API-Gateway | ||
|
|
||
| A modern reactive Spring Boot API Gateway that provides JWT-based authentication and authorization for microservices. Built with Spring Cloud Gateway and WebFlux for high-performance, non-blocking operations. | ||
|
|
||
| ## Key Features | ||
|
|
||
| - **JWT Authentication** - Stateless authentication with access and refresh tokens | ||
| - **User Management** - Registration, login, and profile management | ||
| - **Reactive Architecture** - Built on Spring WebFlux for non-blocking I/O | ||
| - **Global Exception Handling** - Structured error responses across all endpoints | ||
| - **Secure Password Storage** - BCrypt hashing with 12 rounds | ||
| - **Token Refresh Mechanism** - 7-day refresh tokens for seamless user experience | ||
|
|
||
| ## Tech Stack | ||
|
|
||
| - **Java 21** - LTS version | ||
| - **Spring Boot 3.5.7** - Framework | ||
| - **Spring Cloud Gateway** - Reactive gateway | ||
| - **Spring Security** - Authentication & authorization | ||
| - **PostgreSQL + R2DBC** - Reactive database access | ||
| - **JJWT 0.12.5** - JWT token handling | ||
| - **Maven** - Build tool | ||
|
|
||
| ## Quick Start | ||
|
|
||
| 1. **Clone the repository** | ||
| ```bash | ||
| git clone https://github.com/matthewhou19/auth-api-gateway.git | ||
| cd auth-api-gateway | ||
| ``` | ||
|
|
||
| 2. **Start PostgreSQL database** | ||
|
|
||
| **Option A: Using Docker (Recommended)** | ||
| ```bash | ||
| docker compose up -d | ||
| ``` | ||
|
|
||
| **Option B: Use existing PostgreSQL** | ||
|
|
||
| Make sure PostgreSQL is running on `localhost:5432` with: | ||
| - Database: `auth_gateway_db` | ||
| - Username: `postgres` | ||
| - Password: `password` | ||
|
|
||
| 3. **Run the application** | ||
| ```bash | ||
| cd apigateway | ||
| ./mvnw spring-boot:run | ||
| ``` | ||
|
|
||
| **Note:** Database tables (`users`, `refresh_tokens`) are created automatically on startup from `schema.sql`. No manual database setup required! | ||
|
|
||
| 4. **Access the API** | ||
| - Base URL: `http://localhost:8080` | ||
| - All endpoints are prefixed with `/auth` | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| ### Public Endpoints (No authentication required) | ||
|
|
||
| | Method | Endpoint | Description | | ||
| |--------|----------|-------------| | ||
| | POST | `/auth/register` | Register a new user | | ||
| | POST | `/auth/login` | Login with email/username and password | | ||
| | GET | `/auth/refresh/{token}` | Refresh access token using refresh token | | ||
|
|
||
|
matthewhou19 marked this conversation as resolved.
|
||
| ### Protected Endpoints (Requires JWT) | ||
|
|
||
| | Method | Endpoint | Description | | ||
| |--------|----------|-------------| | ||
| | GET | `/auth/me` | Get authenticated user details | | ||
| | DELETE | `/auth/logout` | Logout and invalidate refresh token | | ||
|
|
||
| ### Example: Register a User | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:8080/auth/register \ | ||
| -H "Content-Type: application/json" \ | ||
| -d "{\"email\": \"user@example.com\", \"username\": \"johndoe\", \"name\": \"John Doe\", \"password\": \"SecurePass123@\"}" | ||
| ``` | ||
|
|
||
| **Note**: Using double quotes and escaped JSON for better shell compatibility. Password uses `@` instead of `!` to avoid shell history expansion issues in some terminals. | ||
|
|
||
| ### Example: Login | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:8080/auth/login \ | ||
| -H "Content-Type: application/json" \ | ||
| -d "{\"emailUsername\": \"user@example.com\", \"password\": \"SecurePass123@\"}" | ||
| ``` | ||
|
|
||
| Response: | ||
| ```json | ||
| { | ||
| "accessToken": "eyJhbGciOiJIUzI1NiJ9...", | ||
| "refreshToken": "base64-encoded-token" | ||
| } | ||
| ``` | ||
|
|
||
| ### Example: Access Protected Endpoint | ||
|
|
||
| ```bash | ||
| curl -X GET http://localhost:8080/auth/me \ | ||
| -H "Authorization: Bearer YOUR_ACCESS_TOKEN" | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Default Settings | ||
|
|
||
| The application uses the following default database settings (matching the `docker-compose.yml`): | ||
|
|
||
| ```yaml | ||
| spring: | ||
| r2dbc: | ||
| url: r2dbc:postgresql://localhost:5432/auth_gateway_db | ||
| username: postgres | ||
| password: password | ||
| ``` | ||
|
|
||
| ### Custom Configuration | ||
|
|
||
| For production or custom setups, modify `apigateway/src/main/resources/application.yaml`: | ||
|
|
||
| **Custom Database:** | ||
| ```yaml | ||
| spring: | ||
| r2dbc: | ||
| url: r2dbc:postgresql://your-host:5432/your-database | ||
| username: your-username | ||
| password: your-password | ||
| ``` | ||
|
|
||
| **JWT Secret (CRITICAL for Production!):** | ||
| ```yaml | ||
| jwt: | ||
| secret: your-secure-secret-key-minimum-32-characters-long | ||
| ``` | ||
|
|
||
| ⚠️ **Security Warning**: The default JWT secret is for development only. MUST be changed for production! | ||
|
|
||
| ## Database Schema | ||
|
|
||
| The application automatically creates the required database tables on startup: | ||
|
|
||
| **Tables:** | ||
| - `users` - Stores user account information (id, name, username, email, password) | ||
| - `refresh_tokens` - Manages refresh token lifecycle (id, user_id, token, expiry_date, created_at) | ||
|
|
||
| **Schema Definition:** | ||
| - Table definitions are in `apigateway/src/main/resources/schema.sql` | ||
| - Tables are created automatically via Spring's SQL initialization feature | ||
| - Uses `CREATE TABLE IF NOT EXISTS` to prevent errors on restart | ||
| - Includes indexes on `refresh_tokens` for optimal performance | ||
|
|
||
| **Configuration:** | ||
| ```yaml | ||
| spring: | ||
| sql: | ||
| init: | ||
| mode: never # Use 'always' only in dev/test profiles; handle prod schema via migrations | ||
| platform: postgresql | ||
| ``` | ||
|
|
||
| **Note:** For production environments, use proper database migration tools like Flyway or Liquibase instead of SQL initialization mode. | ||
|
matthewhou19 marked this conversation as resolved.
|
||
|
|
||
| ## Password Requirements | ||
|
|
||
| - Minimum 8 characters | ||
| - At least one uppercase letter | ||
| - At least one lowercase letter | ||
| - At least one digit | ||
| - At least one special character | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| apigateway/ | ||
| ├── src/main/java/vaultweb/apigateway/ | ||
| │ ├── config/ # Security & JWT configuration | ||
| │ ├── controller/ # REST API endpoints | ||
| │ ├── service/ # Business logic | ||
| │ ├── model/ # Database entities | ||
| │ ├── repositories/ # Data access layer | ||
| │ ├── dto/ # Request/Response objects | ||
| │ ├── exceptions/ # Exception handling | ||
| │ └── util/ # Utility classes | ||
| └── src/main/resources/ | ||
| ├── application.yaml # Application configuration | ||
| └── schema.sql # Database schema (auto-applied on startup) | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| [Add your license here] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| -- Users table | ||
| CREATE TABLE IF NOT EXISTS users ( | ||
| id SERIAL PRIMARY KEY, | ||
| name VARCHAR(255) NOT NULL, | ||
| username VARCHAR(255) UNIQUE NOT NULL, | ||
| email VARCHAR(255) UNIQUE NOT NULL, | ||
| password VARCHAR(255) NOT NULL | ||
| ); | ||
|
|
||
| -- Refresh tokens table | ||
| CREATE TABLE IF NOT EXISTS refresh_tokens ( | ||
| id BIGSERIAL PRIMARY KEY, | ||
| user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, | ||
| token VARCHAR(500) NOT NULL, | ||
| expiry_date TIMESTAMP NOT NULL, | ||
| created_at TIMESTAMP NOT NULL | ||
| ); | ||
|
|
||
| -- Create index on user_id for better query performance | ||
| CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user_id ON refresh_tokens(user_id); | ||
|
|
||
| -- Create index on token for faster lookups | ||
| CREATE INDEX IF NOT EXISTS idx_refresh_tokens_token ON refresh_tokens(token); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| services: | ||
| postgres: | ||
| image: postgres:16-alpine | ||
| container_name: auth-gateway-db | ||
| # NOTE: These credentials are intended for local development only. | ||
| # For any shared or production-like environment, override POSTGRES_USER, | ||
| # POSTGRES_PASSWORD, and POSTGRES_DB with secure, environment-specific values. | ||
| environment: | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: password | ||
| POSTGRES_DB: auth_gateway_db | ||
|
matthewhou19 marked this conversation as resolved.
|
||
| ports: | ||
| - "5432:5432" | ||
| volumes: | ||
| - postgres_data:/var/lib/postgresql/data | ||
|
|
||
| volumes: | ||
| postgres_data: | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.