Skip to content

Latest commit

 

History

History
690 lines (464 loc) · 14.6 KB

File metadata and controls

690 lines (464 loc) · 14.6 KB

Spring Authentication API

Base URL

/v1

Technology Stack

  • Framework: Spring Boot 3.2.2
  • Language: Java 21
  • Database: PostgreSQL (with H2 for development)
  • Security: Spring Security with Argon2id hashing
  • Validation: Jakarta Validation
  • Email: Spring Mail
  • JSON Processing: Jackson

API Endpoints

User Authentication

1. User Registration

Endpoint: POST /v1/users/register

Register a new user account.

Request Body: UsersRegistrationDTO

{
  "usersType": "USER_NORMAL | USER_SELL | USER_ADMIN | USER_MODERATOR | USER_DEVELOPER",
  "fullName": "John Doe",
  "email": "john.doe@example.com",
  "password": "securepassword123"
}

Validation Rules:

  • usersType: Required, non-blank
  • fullName: Required, 3-100 characters
  • email: Required, valid email format, 3-95 characters
  • password: Required, 8-100 characters

Response:

Success (200 OK):

{
  "username": "john.42",
  "email": "john.doe@example.com",
  "continue": "proceed"
}

Error - Email Taken:

e[msg:taken]

Process:

  1. Validates that email is not already registered
  2. Generates a unique username from full name (format: firstname.randomNumber)
  3. Hashes password using Argon2id
  4. Generates 5-digit verification code
  5. Creates user record in database
  6. Sends verification email asynchronously
  7. Returns username and email for verification step

2. User Login

Endpoint: POST /v1/users/login

Authenticate an existing user.

Request Body: UsersLoginDTO

{
  "email": "john.doe@example.com",
  "password": "securepassword123"
}

Validation Rules:

  • email: Required, valid email format, 3-95 characters
  • password: Required, 8-100 characters

Response:

Success (200 OK):

{
  "username": "john.42",
  "email": "john.doe@example.com",
  "roles": "USER_NORMAL",
  "enabled": "true"
}

Invalid Credentials:

{
  "username": "",
  "email": "",
  "roles": "",
  "enabled": ""
}

Process:

  1. Validates user credentials using email and password
  2. Compares password hash using Argon2id
  3. Returns user details if authenticated, empty strings if not

3. Email Verification

Endpoint: POST /v1/users/verify

Verify user email with verification code.

Request Body: VerificationDTO

{
  "email": "john.doe@example.com",
  "password": "securepassword123",
  "verificationCode": 12345
}

Validation Rules:

  • email: Required, valid email format, 3-95 characters
  • password: Required, 8-100 characters
  • verificationCode: Required, Integer

Response:

{
  "status": "continue" | "verified" | "error"
}

Status Meanings:

  • continue: Verification successful, user is now enabled
  • verified: User was already verified
  • error: Invalid credentials or verification code

Process:

  1. Validates user credentials
  2. Checks if user is already verified
  3. If not verified, compares verification code
  4. If code matches, enables user account asynchronously
  5. Returns appropriate status

User Management

4. List All Users

Endpoint: GET /v1/users

Retrieve a paginated list of all users.

Query Parameters:

Parameter Type Default Description
pageNum Integer 0 Page number (0-based)
pageSize Integer 10 Number of items per page
sort String "id" Sort specification (format: field,direction or field1,direction1;field2,direction2)

Examples:

GET /v1/users?pageNum=0&pageSize=10&sort=id,asc
GET /v1/users?pageNum=0&pageSize=10&sort=id,asc;email,desc

Response: List<UsersEntity>

[
  {
    "id": 1,
    "username": "john.42",
    "fullName": "John Doe",
    "email": "john.doe@example.com",
    "password": "$argon2id$...",
    "verificationCode": 12345,
    "roles": "USER_NORMAL",
    "userExpired": false,
    "userCredentialsExpired": false,
    "userLocked": false,
    "userEnabled": true,
    "lastUpdatedDate": "2024-02-15T10:30:00",
    "createdDate": "2024-02-15T10:00:00"
  }
]

Statistics (WIP)

5. Record Statistics

Endpoint: POST /v1/stats/stat

Status: Not Implemented (TODO)

Request Body: StatsDTO

{}

Response: Throws UnsupportedOperationException


Data Models

UsersEntity

Table: speedro_users

Field Type Constraints Description
id Long Primary Key, Auto-generated Unique identifier
username String Unique, Not Null, Max 100 chars System-generated username
fullName String Not Null, Max 100 chars User's full name
email String Unique, Not Null, Max 95 chars User's email address
password String Not Null Argon2id hashed password
verificationCode Integer Not Null 5-digit verification code
roles String Not Null User role (USER_ADMIN, USER_MODERATOR, etc.)
userExpired Boolean Default: false Account expiration status
userCredentialsExpired Boolean Default: false Credentials expiration status
userLocked Boolean Default: false Account lock status
userEnabled Boolean Default: false Account enabled status
lastUpdatedDate LocalDateTime Auto-updated Last modification timestamp
createdDate LocalDateTime Auto-generated Creation timestamp

UsersType (Enum)

USER_ADMIN       // Administrator access
USER_MODERATOR   // Moderator access
USER_DEVELOPER   // Developer access
USER_SELL        // Seller/merchant access
USER_NORMAL      // Regular user access

ServiceEntity (Stats)

Table: speedro_stats

Field Type Constraints Description
id Long Primary Key, Auto-generated Unique identifier
userId Long Foreign Key Reference to user
stats String (LOB) Not Null, Unique JSON or text statistics data
lastUpdatedDate LocalDateTime Auto-updated Last modification timestamp
createdDate LocalDateTime Auto-generated Creation timestamp

Service Layer

UsersServices

Core user management service.

Methods:

createUsers(...)

Creates a new user and sends verification email.

Parameters:

  • usersEntityRepository: Repository instance
  • fullName: User's full name
  • username: Generated username
  • email: User's email
  • password: Hashed password
  • verificationCode: 5-digit code
  • userRole: Role type

findUserByUsernameOrEmail(username, email)

Retrieves user by username or email.

Returns: UsersEntity or null

validateUser(username, email, password)

Validates user credentials.

Returns: Optional<UsersEntity>

Process:

  1. Finds user by username or email
  2. Compares password using Argon2id hashing
  3. Returns user if valid, empty Optional otherwise

userExists(email)

Checks if user exists by email.

Returns: CompletableFuture<Boolean>

generateUsername(fullName)

Generates unique username from full name.

Format: firstname.randomNumber (e.g., "john.42")

Process:

  1. Extracts first name from full name
  2. Escapes special characters
  3. Appends random number (0-99)
  4. Checks uniqueness against database
  5. If exists, appends additional random suffix

verificationCode(random)

Generates random 5-digit verification code.

Returns: Integer (0-99999)

userRoleManager(role)

Maps role string to enum value.

Mappings:

  • "seller"USER_SELL
  • Any other → USER_NORMAL

UsersRegistrationService

Handles user registration logic.

Method: register(UsersRegistrationDTO)

Process:

  1. Checks if email exists (async)
  2. Generates username
  3. Hashes password with Argon2id
  4. Generates verification code
  5. Creates user record (async)
  6. Sends verification email (async)

UsersLoginService

Handles user authentication logic.

Method: login(UsersLoginDTO)

Process:

  1. Validates credentials
  2. Returns user details as JSON if valid
  3. Returns empty values if invalid

VerificationService

Handles email verification logic.

Method: verifyUser(VerificationDTO)

Process:

  1. Validates user credentials
  2. Checks if already verified
  3. Compares verification code
  4. Enables account if code matches (async)

Core Services

JsonResponseService

Creates JSON responses from key-value pairs.

Method: createJson(T[][] json)

Example:

String json = jsonResponseService.createJson(new String[][] {
    { "username", "john.42" },
    { "email", "john@example.com" }
});

Output:

{
  "username": "john.42",
  "email": "john@example.com"
}

MailSenderService

Sends emails using Spring Mail.

Method: sendSimpleMessage(to, subject, text)

Configuration:

  • From: ry.samaeian@gmail.com
  • Runs asynchronously

StringEscapeService

Escapes special characters in strings.

Escapes:

  • \\\
  • \t\\t
  • \b\\b
  • \n\\n
  • \r\\r
  • \f\\f
  • '\\'
  • "\\"

Method: escape(String s) (static)


Security Services

DataHashing

Password hashing using Password4j library.

Supported Hash Types:

  • ARGON2ID (recommended)
  • BCRYPT
  • PBKDF2
  • SCRYPT

Methods:

hashData(data, hashTypes, salt, pepper)

Hashes data with specified algorithm.

Parameters:

  • data: String to hash
  • hashTypes: Hash algorithm enum
  • salt: Optional salt
  • pepper: Optional pepper

Returns: Hashed string

compareHash(data, hashedData, hashTypes, salt, pepper)

Verifies data against hash.

Returns: Boolean (true if matches)


DataEncryption

Base64 encoding/decoding utility.

Methods:

encode(byte[] data)

Encodes bytes to Base64 string.

decode(String data)

Decodes Base64 string to bytes.


SecurityConfiguration

Spring Security configuration.

Features:

  • CSRF disabled for API usage
  • Method-level security enabled

Configuration:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) {
    return httpSecurity
        .csrf().disable()
        .build();
}

Database Repository

UsersEntityRepository

Methods:

findByUsernameOrEmail(username, email)

Finds user by username or email.

Returns: Optional<UsersEntity>

existsByEmail(email)

Checks if email exists.

Returns: Boolean

existsByUsername(username)

Checks if username exists.

Returns: Boolean

verifyUser(userEnabled, email)

Updates user's enabled status.

Parameters:

  • userEnabled: Boolean enabled status
  • email: User's email

Error Codes

Validation Errors

Format: d[field]e[error_type]

Error Code Meaning
d[email]e[msg:blank] Email is required
d[email]e[invalid] Invalid email format
d[email]e[msg:char_limit] Email length must be 3-95 characters
d[password]e[msg:blank] Password is required
d[password]e[msg:char_limit] Password length must be 8-100 characters
d[f_name]e[msg:blank] Full name is required
d[f_name]e[msg:char_limit] Full name length must be 3-100 characters
d[u_type]e[msg:blank] User type is required

Service Errors

Error Code Meaning
e[msg:taken] Email is already registered

Usage Examples

Register a New User

curl -X POST http://localhost:8080/v1/users/register \
  -H "Content-Type: application/json" \
  -d '{
    "usersType": "USER_NORMAL",
    "fullName": "Jane Smith",
    "email": "jane.smith@example.com",
    "password": "SecurePass123"
  }'

Login

curl -X POST http://localhost:8080/v1/users/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane.smith@example.com",
    "password": "SecurePass123"
  }'

Verify Email

curl -X POST http://localhost:8080/v1/users/verify \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane.smith@example.com",
    "password": "SecurePass123",
    "verificationCode": 54321
  }'

List Users

curl "http://localhost:8080/v1/users?pageNum=0&pageSize=10&sort=id,asc"

Dependencies

See build.gradle for complete dependency list. Key dependencies:

  • Spring Boot Starter Web
  • Spring Boot Starter Data JPA
  • Spring Boot Starter Security
  • Spring Boot Starter Mail
  • Spring Boot Starter Validation
  • PostgreSQL Driver
  • H2 Database (development)
  • Password4j (Argon2id)
  • Lombok
  • Jackson

Build & Run

# Build
./gradlew build

# Run
./gradlew bootRun

# Test
./gradlew test

Notes

  • All email operations are asynchronous using @Async
  • Password hashing uses Argon2id with 16-character salt and 4-character pepper
  • Verification codes are 5-digit integers (0-99999)
  • CSRF is disabled for API usage
  • Usernames are automatically generated and unique
  • User accounts are disabled by default until verified