User Registration
User registration is the entry point for new identities in the MATIH platform. The IAM service supports two registration paths: self-service registration through the AuthController REST API, and enterprise provisioning through the SCIM 2.0 protocol. Both paths converge on the same user entity model and apply identical password policies and email verification requirements.
Registration Flow Overview
The self-service registration flow follows a multi-step process that creates the user account, issues initial tokens, and triggers asynchronous email verification:
Client IAM Service Database Notification Service
| | | |
| POST /api/v1/auth/register | |
|------------------------->| | |
| | Validate request | |
| | Check email uniqueness | |
| |-------------------------->| |
| | Hash password (BCrypt) | |
| | Create User entity | |
| |-------------------------->| |
| | Generate verification token |
| |-------------------------->| |
| | Generate access + refresh tokens |
| | Create session | |
| |-------------------------->| |
| | Send verification email | |
| |----------------------------------------------->| |
| 200 OK (AuthResponse) | | |
|<-------------------------| | |Registration Request
The RegisterRequest DTO defines the fields required for self-service registration:
public class RegisterRequest {
@NotBlank(message = "Email is required")
@Email(message = "Invalid email format")
private String email;
@NotBlank(message = "Password is required")
@Size(min = 8, max = 128, message = "Password must be between 8 and 128 characters")
private String password;
@NotBlank(message = "First name is required")
@Size(max = 100)
private String firstName;
@NotBlank(message = "Last name is required")
@Size(max = 100)
private String lastName;
private String organizationName; // Optional: for tenant creation
private String inviteCode; // Optional: for joining existing tenant
}API Endpoint
POST /api/v1/auth/register
Content-Type: application/jsonRequest body:
{
"email": "jane.doe@acme.com",
"password": "SecureP@ssw0rd!",
"firstName": "Jane",
"lastName": "Doe",
"organizationName": "Acme Corporation"
}Success response (200):
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"tokenType": "Bearer",
"expiresIn": 900,
"user": {
"id": 42,
"email": "jane.doe@acme.com",
"firstName": "Jane",
"lastName": "Doe",
"emailVerified": false,
"mfaEnabled": false,
"roles": ["USER"]
}
}Error responses:
| Status | Condition | Body |
|---|---|---|
| 400 | Validation failure | { "code": "VALIDATION_ERROR", "errors": [...] } |
| 400 | Email already registered | { "code": "RESOURCE_DUPLICATE", "message": "Email already exists" } |
| 429 | Rate limit exceeded | { "code": "RATE_LIMITED", "retryAfter": 60 } |
Password Policy Enforcement
Before persisting the user, the PasswordPolicyService validates the password against the active policy. Password policies are configurable per tenant:
| Rule | Default | Description |
|---|---|---|
| Minimum length | 8 | Minimum number of characters |
| Maximum length | 128 | Maximum number of characters |
| Require uppercase | true | At least one uppercase letter |
| Require lowercase | true | At least one lowercase letter |
| Require digit | true | At least one numeric digit |
| Require special character | true | At least one of !@#$%^&*()_+-= |
| Prevent common passwords | true | Checked against a dictionary of 100,000 common passwords |
| History check | 5 | Cannot reuse the last N passwords |
| Maximum age (days) | 90 | Password must be changed within this period |
The password is hashed using BCrypt with a work factor of 12 before storage. The raw password is never logged or persisted.
// Password hashing in AuthenticationService
String hashedPassword = passwordEncoder.encode(request.getPassword());
user.setPassword(hashedPassword);Email Verification
After registration, the system generates a time-limited verification token and sends it to the user's email address. The user must verify their email before accessing certain platform features.
Verification Token
| Property | Value |
|---|---|
| Token format | 6-digit numeric code |
| Token lifetime | 24 hours |
| Storage | email_verification_tokens table |
| Delivery | Email via Notification Service |
Verify Email Endpoint
POST /api/v1/auth/verify-email
Content-Type: application/json{
"email": "jane.doe@acme.com",
"code": "482916"
}Success response (200): Empty body
Error responses:
| Status | Condition |
|---|---|
| 400 | Invalid or expired verification code |
| 404 | User not found |
Resend Verification
If the user does not receive the verification email, they can request a new code:
POST /api/v1/auth/resend-verification
Content-Type: application/json{
"email": "jane.doe@acme.com"
}This endpoint is rate-limited to prevent abuse. A maximum of 3 resend requests are allowed within a 15-minute window.
SCIM Provisioning
For enterprise customers integrating MATIH with their identity provider (Okta, Azure AD, OneLogin), the IAM service implements the SCIM 2.0 protocol for automated user lifecycle management.
SCIM Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /scim/v2/Users | List users with filtering and pagination |
GET | /scim/v2/Users/{id} | Get a single user |
POST | /scim/v2/Users | Create a new user |
PUT | /scim/v2/Users/{id} | Full update of a user |
PATCH | /scim/v2/Users/{id} | Partial update (e.g., deactivate) |
DELETE | /scim/v2/Users/{id} | Delete a user |
SCIM User Schema
The ScimUserService maps between the SCIM User schema and the MATIH User entity:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jane.doe@acme.com",
"name": {
"givenName": "Jane",
"familyName": "Doe"
},
"emails": [
{
"value": "jane.doe@acme.com",
"type": "work",
"primary": true
}
],
"active": true,
"externalId": "okta-12345"
}SCIM Filtering
The SCIM implementation supports the standard filter syntax for user queries:
GET /scim/v2/Users?filter=userName eq "jane.doe@acme.com"
GET /scim/v2/Users?filter=active eq true&startIndex=1&count=25SCIM Authentication
SCIM endpoints are authenticated using a bearer token issued specifically for SCIM clients. This token carries the scim:manage scope and is bound to the tenant that provisioned the SCIM integration.
Invite-Based Registration
When a user is invited to join an existing tenant, the registration flow includes an invite code that links the new user to the correct tenant and assigns initial roles:
{
"email": "bob@acme.com",
"password": "SecureP@ssw0rd!",
"firstName": "Bob",
"lastName": "Smith",
"inviteCode": "INV-abc123def456"
}The invite code is validated against the access_requests table. If valid, the user is created within the inviting tenant's context and assigned the roles specified in the invitation.
Account Lockout
The AccountLockoutService protects against registration abuse and brute-force attacks:
| Parameter | Default | Description |
|---|---|---|
| Max registration attempts per IP | 10 per hour | Prevents mass account creation from a single source |
| Max verification attempts per email | 5 per hour | Prevents verification code brute-forcing |
| Lockout duration | 30 minutes | Time before a locked account can retry |
When an account is locked, subsequent registration or verification attempts return a 423 Locked response with a Retry-After header.
Keycloak User Synchronization
For deployments that use Keycloak as the primary identity provider, the KeycloakUserSyncService synchronizes user records between Keycloak and the MATIH IAM database:
Keycloak IAM Service
| |
| User created/updated |
| (webhook event) |
|------------------------>|
| | Upsert user in IAM DB
| | Map Keycloak roles to MATIH roles
| | Update permission cache
| |The KeycloakSyncController exposes endpoints for triggering manual synchronization:
POST /api/v1/keycloak/sync # Full sync
POST /api/v1/keycloak/sync/{userId} # Single user syncData Model Summary
The registration flow creates or updates the following entities:
User
|-- UserRole (default: USER role)
|-- EmailVerificationToken
|-- UserSession (initial session)
|-- RefreshToken (initial refresh token)
|-- PasswordHistory (initial entry)
|-- LoginHistory (registration event)Next Steps
After understanding the registration flow, proceed to:
- Login and Authentication Flows -- how registered users authenticate
- Multi-Factor Authentication -- adding MFA to user accounts
- API Reference -- complete endpoint specifications