User Registration
Production - POST /api/v1/auth/register
Self-service registration allows new users to create accounts on the MATIH platform. The registration flow creates a user in the default tenant, assigns the default user role, sends a verification email, and returns authentication tokens.
6.2.5Registration Flow
Client AuthController AuthenticationService
| | |
|--- POST /auth/register -->| |
| |--- register() ---------->|
| | |--- Check email uniqueness
| | |--- Validate password length
| | |--- Create User entity
| | |--- Assign "user" role
| | |--- Send verification email
| | |--- Generate tokens
|<-- 200 (AuthResponse) ----|<-- AuthResponse ---------|Request
curl -X POST http://localhost:8081/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "newuser@example.com",
"password": "MySecureP@ss123",
"firstName": "Alex",
"lastName": "Johnson"
}'Request Schema
| Field | Type | Required | Validation | Description |
|---|---|---|---|---|
email | String | Yes | @NotBlank, @Email, max 255 | User email address |
password | String | Yes | @NotBlank, 8-128 chars | Account password |
firstName | String | No | Max 100 chars | User first name |
lastName | String | No | Max 100 chars | User last name |
Response (200 OK)
{
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
"tokenType": "Bearer",
"expiresIn": 900,
"user": {
"id": 42,
"email": "newuser@example.com",
"firstName": "Alex",
"lastName": "Johnson",
"displayName": "Alex Johnson",
"tenantId": "00000000-0000-0000-0000-000000000001",
"roles": ["ROLE_USER"],
"emailVerified": false
}
}Note that emailVerified is false immediately after registration. The user must complete email verification separately.
6.2.6Implementation Details
AuthenticationService.register()
@Transactional
public AuthResponse register(RegisterRequest request, String userAgent, String ipAddress) {
// 1. Check if email already exists in default tenant
if (userRepository.existsByTenantIdAndEmail(DEFAULT_TENANT_ID, request.getEmail())) {
throw new BusinessException("An account with this email already exists");
}
// 2. Validate password strength
if (request.getPassword() == null || request.getPassword().length() < 8) {
throw new BusinessException("Password must be at least 8 characters");
}
// 3. Create the user entity
User user = User.builder()
.tenantId(DEFAULT_TENANT_ID)
.email(request.getEmail())
.passwordHash(passwordEncoder.encode(request.getPassword()))
.firstName(request.getFirstName())
.lastName(request.getLastName())
.displayName(request.getFirstName() + " " + request.getLastName())
.enabled(true)
.mfaEnabled(false)
.build();
// 4. Assign default "user" role
roleRepository.findByTenantIdAndName(DEFAULT_TENANT_ID, "user")
.ifPresent(role -> user.getRoles().add(role));
User savedUser = userRepository.save(user);
// 5. Send verification email
sendVerificationEmail(savedUser);
// 6. Generate tokens and return
UserDetails userDetails = userDetailsService.loadUserByUsername(savedUser.getEmail());
String accessToken = jwtTokenProvider.generateAccessToken(userDetails);
String refreshToken = jwtTokenProvider.generateRefreshToken(savedUser.getEmail());
saveRefreshToken(savedUser, refreshToken, userAgent, ipAddress);
return AuthResponse.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.tokenType("Bearer")
.expiresIn(securityProperties.getJwt().getAccessTokenExpiration() / 1000)
.user(buildUserInfo(savedUser))
.build();
}Key Behaviors
- Default Tenant: Self-registration creates users in the default tenant (
00000000-0000-0000-0000-000000000001). Admin-created users use the tenant specified in theX-Tenant-IDheader viaUserController.createUser(). - Password Hashing: Passwords are hashed using Spring Security's
PasswordEncoder(BCrypt) before storage. The plain-text password is never persisted. - Display Name: Automatically constructed from
firstName + " " + lastName. If both are null, the@PrePersisthook falls back to the email address. - Role Assignment: The default
userrole is looked up from the database. If it does not exist (e.g., in a fresh database), the user is created without any roles. - Immediate Token Issuance: Unlike some systems that require email verification before login, MATIH issues tokens immediately after registration. The
emailVerifiedflag in the token response allows the frontend to prompt for verification.
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
BUSINESS_RULE_VIOLATION | 400 | Email already exists or password too short |
VALIDATION_ERROR | 400 | Missing required fields or invalid email format |
Admin User Creation
Administrators can create users via the UserController endpoint, which offers more control:
curl -X POST http://localhost:8081/api/v1/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin-token>" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"email": "team.member@company.com",
"password": "InitialP@ss123",
"firstName": "Team",
"lastName": "Member",
"displayName": "Team Member",
"phoneNumber": "+1234567890",
"roleIds": [1, 3]
}'This endpoint requires ADMIN or PLATFORM_ADMIN role and allows specifying the target tenant and initial role assignments.