Skip to main content
The Auth service handles user authentication, registration, and token management for the QeetMart platform. It issues JWT access tokens and refresh tokens.

Overview

Built with Spring Boot 3.3.8 and Spring Security, the auth service manages user credentials, authentication flows, session management, and audit logging.
The Auth service runs on port 4001 by default and uses PostgreSQL for data persistence.

Technology stack

  • Framework: Spring Boot 3.3.8
  • Language: Java 17
  • Database: PostgreSQL
  • Security: Spring Security + JWT (jjwt 0.12.6)
  • Key dependencies:
    • Spring Data JPA
    • Spring Security
    • Spring Boot Actuator
    • Micrometer Prometheus
    • Lombok

Configuration

Environment variables

SERVER_PORT
number
default:"4001"
Server port
SPRING_PROFILES_ACTIVE
string
default:"dev"
Active Spring profile (dev, prod)

Database configuration

DB_HOST
string
default:"localhost"
PostgreSQL host
DB_PORT
number
default:"5001"
PostgreSQL port
DB_NAME
string
default:"qeetmart_auth"
Database name
DB_USERNAME
string
default:"postgres"
Database username
DB_PASSWORD
string
required
Database password

JWT configuration

JWT_SECRET
string
required
JWT signing secret (minimum 32 bytes recommended)
JWT_ISSUER_URI
string
default:"http://localhost:4001"
JWT issuer URI
JWT_ACCESS_TOKEN_EXPIRATION
string
default:"15m"
Access token expiration (e.g., 15m, 1h)
JWT_REFRESH_TOKEN_EXPIRATION
string
default:"7d"
Refresh token expiration (e.g., 7d, 30d)

Security configuration

SECURITY_LOGIN_MAX_ATTEMPTS
number
default:"5"
Maximum failed login attempts before account lock
SECURITY_LOGIN_LOCK_DURATION_MINUTES
number
default:"15"
Account lock duration in minutes
SECURITY_LOGIN_REQUIRE_EMAIL_VERIFIED
boolean
default:"false"
Require email verification for login
SECURITY_LOGIN_SINGLE_SESSION_ENABLED
boolean
default:"false"
Allow only one active session per user

API endpoints

Register

curl -X POST http://localhost:4001/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "SecurePass123!"
  }'

Login

curl -X POST http://localhost:4001/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "SecurePass123!",
    "deviceId": "mobile-device-123"
  }'

Refresh token

curl -X POST http://localhost:4001/auth/refresh-token \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'

Get current user

curl http://localhost:4001/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Change password

curl -X POST http://localhost:4001/auth/change-password \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "oldPassword": "OldPass123!",
    "newPassword": "NewSecurePass456!"
  }'

Logout

curl -X POST http://localhost:4001/auth/logout \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'

Logout all devices

curl -X POST http://localhost:4001/auth/logout-all \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Data models

UserCredential entity

@Entity
@Table(name = "user_credentials")
public class UserCredential {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true, length = 255)
    private String email;

    @Column(name = "password_hash", nullable = false, length = 255)
    private String passwordHash;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private Role role; // CUSTOMER, ADMIN

    @Enumerated(EnumType.STRING)
    @Column(name = "account_status", nullable = false, length = 20)
    private AccountStatus accountStatus; // ACTIVE, LOCKED, SUSPENDED

    @Column(name = "email_verified", nullable = false)
    private boolean emailVerified;

    @Column(name = "failed_login_attempts", nullable = false)
    private int failedLoginAttempts;

    @Column(name = "lock_until")
    private Instant lockUntil;

    @Column(name = "last_login_at")
    private Instant lastLoginAt;

    @Column(name = "created_at", nullable = false, updatable = false)
    private Instant createdAt;

    @Column(name = "updated_at", nullable = false)
    private Instant updatedAt;
}

RefreshToken entity

The service stores refresh tokens in the database for session management and revocation.

Health check

curl http://localhost:4001/actuator/health

Metrics

Prometheus metrics are available at /actuator/prometheus.

Running the service

cd auth-service
mvn spring-boot:run

Security features

  • Password hashing: BCrypt with configurable strength
  • Account lockout: Automatic locking after failed login attempts
  • Token rotation: New refresh token issued on each refresh
  • Audit logging: All authentication events logged
  • Session management: Device-based session tracking
The JWT_SECRET must be kept secure and should be at least 32 bytes. Use the same secret across API Gateway and all services that verify tokens.

Dependencies

  • PostgreSQL: For user credentials and refresh tokens
  • No external service dependencies

Source code

Location: ~/workspace/source/micros/auth-service/ Key files:
  • src/main/java/com/qeetmart/auth/api/controller/AuthController.java - REST endpoints
  • src/main/java/com/qeetmart/auth/application/service/AuthApplicationService.java - Business logic
  • src/main/java/com/qeetmart/auth/domain/entity/UserCredential.java - User entity
  • src/main/resources/application.yml - Configuration

Build docs developers (and LLMs) love