Authentication Service with AWS Cognito
Author(s)
- Sanket Mal
- Ashik Ikbal
Last Updated Date
2025-12-17
Feature Overview
The Authentication Service provides comprehensive user authentication and authorization for the RKAuto Van Tracker platform using AWS Cognito as the identity provider. This service manages three distinct user types: Customers, Technicians, and Admins, each with role-based access control and specific workflows.
Key Features
- Multi-Role Authentication: Separate authentication flows for Customers, Technicians, and Admins
- AWS Cognito Integration: Leverages AWS Cognito User Pools for secure authentication
- User Lifecycle Management: Complete user registration, verification, activation, and profile management
- Password Management: Forgot password, reset password, change password functionality
- Token-Based Authentication: JWT-based access/refresh tokens with secure cookie storage
- Database Synchronization: Real-time sync between Cognito and PostgreSQL database
- Audit Trail: Login history tracking for security and compliance
- Profile Management: User profile CRUD operations with role-specific data
User Types & Workflows
- Customer: Self-registration → Email verification → Login → Access customer portal
- Technician: Admin creation → First-time activation → Profile setup → Login → Field operations
- Admin: Pre-configured accounts → Login → Administrative operations
Requirements
Functional Requirements
| ID | Requirement | Priority |
|---|---|---|
| FR-1 | Customer self-registration with email verification | High |
| FR-2 | Admin-initiated technician account creation | High |
| FR-3 | First-time technician activation with password setup | High |
| FR-4 | Role-based authentication (Customer/Technician/Admin) | High |
| FR-5 | Email-based OTP verification for signup | High |
| FR-6 | Forgot password with email verification | High |
| FR-7 | Admin password reset for any user | Medium |
| FR-8 | Change password for authenticated users | Medium |
| FR-9 | Token refresh mechanism | High |
| FR-10 | User profile retrieval and updates | Medium |
| FR-11 | Paginated user listing (Admin only) | Low |
| FR-12 | Logout with token invalidation | Medium |
| FR-13 | Login history tracking | Low |
Non-Functional Requirements
| ID | Requirement | Target |
|---|---|---|
| NFR-1 | API response time | < 500ms (95th percentile) |
| NFR-2 | Concurrent user sessions | Support 10,000+ concurrent users |
| NFR-3 | Password strength | Min 8 chars, uppercase, lowercase, number, special char |
| NFR-4 | Token expiry | Access: 1 hour, Refresh: 30 days |
| NFR-5 | Database transaction | ACID compliance for user creation |
| NFR-6 | Audit logging | 100% login attempts logged |
Security Requirements
- Passwords must meet AWS Cognito complexity requirements
- JWT tokens stored as HTTP-only, Secure cookies
- Phone numbers must be in E.164 format
- Rate limiting on authentication endpoints
- Email verification mandatory for customer signup
- Admin operations require Admin role authorization
System Architecture
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Client │──────▶│ AuthController │──────▶│ CognitoAuth │
│ (Web/Mobile)│ │ (API Gateway) │ │ Service │
└─────────────┘ └──────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ AuthDal │ │ AWS Cognito │
│ (Database Layer) │ │ User Pool │
└──────────────────┘ └─────────────────┘
│ │
▼ │
┌──────────────────┐ │
│ PostgreSQL │◀──────────────┘
│ Database │ (Sync EntityId)
└──────────────────┘
Component Responsibilities
- AuthController: HTTP endpoint handling, request validation, cookie management
- CognitoAuthService: Business logic, Cognito API integration, error handling
- AuthDal: Database operations, transaction management
- AWS Cognito: User authentication, token generation, user pool management
- PostgreSQL: User data persistence, relationship management, audit logs
Database Schema (PostgreSQL)
Core Tables
userdetails - Central user table synced with AWS Cognito
CREATE TABLE IF NOT EXISTS userdetails (
userid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
email varchar(255) NOT NULL UNIQUE,
firstname varchar(100) NOT NULL,
lastname varchar(100) NOT NULL,
phonenumber varchar(20),
usertype varchar(20) NOT NULL,
entityid uuid,
status varchar(20) NOT NULL DEFAULT 'Active',
profileimageurl text,
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
createdby uuid,
updatedby uuid
);
customermaster - Customer profile and business details
CREATE TABLE IF NOT EXISTS customermaster (
customerid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
customercode varchar(50) UNIQUE,
gender varchar(10),
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
createdby uuid,
updatedby uuid
);
customeraddress - Customer address with geolocation
CREATE TABLE IF NOT EXISTS customeraddress (
customeraddressid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
customerid uuid NOT NULL,
city varchar(100),
state varchar(100),
country varchar(100),
pincode varchar(10),
latitude double precision,
longitude double precision,
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
CONSTRAINT fk_customeraddress_customerid
FOREIGN KEY (customerid) REFERENCES customermaster(customerid) ON DELETE CASCADE
);
technicianmaster - Technician profile and assignment
CREATE TABLE IF NOT EXISTS technicianmaster (
technicianid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
techniciancode varchar(50) UNIQUE,
joiningdate date NOT NULL,
employeetype varchar(20) DEFAULT 'FullTime',
emergencycontactname varchar(100),
emergencycontactphone varchar(20),
skills text[],
specialization varchar(100),
currentvanid uuid,
currentvannumber varchar(100),
isavailable boolean DEFAULT true,
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
createdby uuid,
updatedby uuid,
CONSTRAINT fk_technicianmaster_createdby
FOREIGN KEY (createdby) REFERENCES userdetails(userid) ON DELETE SET NULL,
CONSTRAINT fk_technicianmaster_updatedby
FOREIGN KEY (updatedby) REFERENCES userdetails(userid) ON DELETE SET NULL,
CONSTRAINT fk_technicianmaster_currentvanid
FOREIGN KEY (currentvanid) REFERENCES vanmaster(vanid) ON DELETE SET NULL
);
technicianaddress - Technician address with geolocation
CREATE TABLE IF NOT EXISTS technicianaddress (
technicianaddressid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
technicianid uuid NOT NULL,
city varchar(100),
state varchar(100),
country varchar(100),
pincode varchar(10),
latitude double precision,
longitude double precision,
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
CONSTRAINT fk_technicianaddress_technicianid
FOREIGN KEY (technicianid) REFERENCES technicianmaster(technicianid) ON DELETE CASCADE
);
vanmaster - Service van details
CREATE TABLE IF NOT EXISTS vanmaster (
vanid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
vannumber varchar(50) NOT NULL UNIQUE,
registrationnumber varchar(50) NOT NULL UNIQUE,
userid uuid NOT NULL,
vin varchar(17) NOT NULL UNIQUE,
make varchar(50),
model varchar(50),
year int,
trim varchar(50),
bodytype varchar(50),
status varchar(20) DEFAULT 'Active',
createdat timestamp NOT NULL DEFAULT now(),
updatedat timestamp NOT NULL DEFAULT now(),
CONSTRAINT fk_vanmaster_userid FOREIGN KEY (userid) REFERENCES userdetails(userid) ON DELETE CASCADE
);
adminmaster - Admin user profiles and roles
CREATE TABLE IF NOT EXISTS adminmaster (
adminid uuid PRIMARY KEY,
email varchar(100) NOT NULL UNIQUE,
phone varchar(20),
createdat timestamp DEFAULT now(),
updatedat timestamp DEFAULT now(),
name varchar(100)
);
scope - Permission scopes for fine-grained access control
CREATE TABLE IF NOT EXISTS scope (
scopeid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
scopename varchar(100) NOT NULL UNIQUE,
accesstype int NOT NULL,
displayname varchar(100) NOT NULL,
groupname varchar(100) NOT NULL,
groupsortorder int,
scopesortorder int,
description varchar(255)
);
loginhistory - Audit trail for all login attempts
CREATE TABLE IF NOT EXISTS loginhistory (
loginid uuid PRIMARY KEY DEFAULT gen_random_uuid(),
userid uuid NOT NULL,
attempttime timestamp DEFAULT now(),
logintime timestamp,
logouttime timestamp,
issuccess boolean NOT NULL,
ipaddress varchar(45),
devicetype text,
useragent text,
failurereason text,
CONSTRAINT fk_loginhistory_userid
FOREIGN KEY (userid) REFERENCES userdetails(userid) ON DELETE CASCADE
);
AWS Cognito Configuration
User Pool Settings
- User Pool Name:
User pool - zaonlg - Sign-in options: Email
- MFA: Optional (configurable per user)
- Password Policy:
- Minimum length: 8 characters
- Require uppercase letters
- Require lowercase letters
- Require numbers
- Require special characters
User Groups
| Group Name | Description | Permissions |
|---|---|---|
customer | End customers requesting services | Customer-specific APIs |
technician | Field technicians performing services | Technician-specific APIs |
admin | System administrators | Full access to all APIs |
Custom Attributes
| Attribute Name | Type | Description |
|---|---|---|
custom:EntityId | String (UUID) | Links Cognito user to database entity (CustomerMaster/TechnicianMaster) |
App Client Configuration
- Authentication Flows:
USER_PASSWORD_AUTHenabled - Token Expiration:
- Access Token: 1 hour
- ID Token: 1 hour
- Refresh Token: 30 days
- Secret Hash: Enabled (for enhanced security)
AWS SSM Parameter Store Structure
Configuration values stored in AWS Systems Manager Parameter Store:
/rkauto/vantracker/auth/
├── UserPoolId # AWS Cognito User Pool ID
├── UserPoolClientId # App Client ID
├── UserPoolClientSecret # App Client Secret (SecureString)
├── JwtIssuer # JWT token issuer URL
└── JwtAudience # JWT token audience
Environment Variables (.env.local/staging):
AWS_ACCESS_KEY_ID=A*****
AWS_SECRET_ACCESS_KEY=w*****
AWS__Region=ap-south-1
AWS__UserPoolId=ap-south-1_*****
AWS__UserPoolClientId=2*****
AWS__UserPoolClientSecret=g*****
AWS__Authority=https://cognito-idp.ap-south-1.amazonaws.com/ap-south-1_*****
Role-to-Scope Mapping Example (SSM Parameter) :
Name : /rkauto/cognito/role-scopes
{
"customer": [
"booking.create",
"booking.read",
"payment.create",
"profile.read",
"profile.write"
],
"technician": [
"booking.read",
"booking.update",
"gps.publish",
"job.complete",
"photo.upload"
],
"admin": [
"technician.create",
"technician.update",
"booking.*",
"fleet.*",
"report.*",
"system.admin"
]
}
Enumerations
public enum UserType
{
Admin = 1,
Technician = 2,
Customer = 3
}
public enum UserStatus
{
Inactive = 1,
Active = 2,
Disabled = 3
}
public enum EmployeeType
{
FullTime,
PartTime,
Contract
}
C# Request/Response Models
1. Customer Signup
public record SignUpRequest
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public required string Email { get; init; }
[Required(ErrorMessage = "Password is required")]
[MinLength(8, ErrorMessage = "Password must be at least 8 characters")]
public required string Password { get; init; }
[Required(ErrorMessage = "Phone number is required")]
[Phone(ErrorMessage = "Invalid phone number format")]
public required string PhoneNumber { get; init; }
[Required(ErrorMessage = "First name is required")]
public required string GivenName { get; init; }
[Required(ErrorMessage = "Last name is required")]
public required string FamilyName { get; init; }
[JsonIgnore]
public string? CustomerCode { get; init; }
}
public record SignUpResponse
{
public bool Success { get; init; }
public string Message { get; init; } = string.Empty;
}
2. Confirm Customer Signup
public record ConfirmSignUpRequest
{
[Required(ErrorMessage = "Username is required")]
public required string Username { get; init; }
[Required(ErrorMessage = "Confirmation code is required")]
public required string ConfirmationCode { get; init; }
}
public record SignInResponse
{
public bool Success { get; init; }
public bool RequiresNewPassword { get; init; }
public string? Message { get; init; }
public bool RequiresMfa { get; init; }
public string? AccessToken { get; init; }
public int ExpiresIn { get; init; }
public string? IdToken { get; init; }
[JsonIgnore]
public string? RefreshToken { get; init; }
[JsonIgnore]
public string? Session { get; init; }
}
3. Customer Signin
public record SignInRequest
{
[Required(ErrorMessage = "Username is required")]
public required string Username { get; init; }
[Required(ErrorMessage = "Password is required")]
public required string Password { get; init; }
}
// Returns SignInResponse (defined above)
4. Technician Create (Admin Only)
public record TechnicianRequest
{
[JsonIgnore]
public Guid? TechnicianId { get; init; }
[JsonIgnore]
public string? TechnicianCode { get; init; }
[EmailAddress(ErrorMessage = "Invalid email format")]
public required string Email { get; init; }
[Required(ErrorMessage = "Phone number is required")]
[RegularExpression(
@"^\+1[2-9]\d{9}$",
ErrorMessage = "Phone number must be a valid US number in +1 format (e.g. +14155552671)."
)]
public required string PhoneNumber { get; init; }
[Required(ErrorMessage = "First Name is required")]
[MaxLength(50)]
public required string FirstName { get; init; }
[Required(ErrorMessage = "Last Name is required")]
[MaxLength(50)]
public required string LastName { get; init; }
[Required(ErrorMessage = "Joining Date is required")]
public required DateTime JoiningDate { get; init; }
public string? Specialization { get; init; }
public List<string>? Skills { get; init; }
public EmployeeType EmployeeType { get; init; } = EmployeeType.FullTime;
public string? EmergencyContactName { get; init; }
public string? EmergencyContactPhone { get; init; }
}
// Returns CommonResponse
5. Activate Technician (First Time)
The first-time activation flow for a Technician is as follows:
-
Receive Temporary Password:
The Technician receives a temporary password (provided by the Admin during account creation). -
Initial Sign-In:
The Technician signs in using their email and the temporary password. -
New Password Challenge:
The authentication response will indicateRequiresNewPassword = true, meaning the Technician must set a new password. -
Set New Password:
The Technician submits a request to the "Respond to New Password Challenge" endpoint with their new password and session information. -
Automatic Login:
Upon successfully setting the new password, the Technician is automatically logged in and receives their authentication tokens.
API Endpoints Involved:
/api/auth/technician/signin(POST) — Initial sign-in with temporary password/api/auth/respond-new-password(POST) — Set new password and complete activation
6. Update Technician Profile
public record UpdateTechnicianRequest
{
[RegularExpression(
@"^\+1[2-9]\d{9}$",
ErrorMessage = "Phone number must be a valid US number in +1 format (e.g. +14155552671)."
)]
public string? PhoneNumber { get; set; }
[MaxLength(50)]
public string? FirstName { get; set; }
[MaxLength(50)]
public string? LastName { get; set; }
public DateTime? JoiningDate { get; set; }
public string? Specialization { get; set; }
public List<string>? Skills { get; set; }
[RegularExpression("^(FullTime|PartTime|Contract)$",
ErrorMessage = "EmployeeType must be FullTime, PartTime, or Contract")]
public string? EmployeeType { get; set; }
public string? EmergencyContactName { get; set; }
public string? EmergencyContactPhone { get; set; }
public string? ProfileImageUrl { get; set; }
}
// Returns CommonResponse
7. Get Technician List (Admin, Paginated)
public class TechnicianFilter
{
public string? SearchKeyword { get; set; } // Global search across all fields
public string? Status { get; set; } // Active, Inactive, All
public string? SearchTerm { get; set; } // Search by name, email, technician code
public bool? IsAvailable { get; set; }
public string? Specialization { get; set; } // Filter by specialization
public string? EmployeeType { get; set; } // FullTime, PartTime, Contract
public List<string>? Skills { get; set; } // Filter by specific skills
public Guid? CurrentVanId { get; set; } // Filter by assigned van
public bool? HasVanAssigned { get; set; } // Filter technicians with/without van
public DateTime? JoiningDateFrom { get; set; }
public DateTime? JoiningDateTo { get; set; }
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
}
8. Get Customer Profile (Own)
public record CustomerDetails
{
// User identification
public Guid UserId { get; init; }
// Customer identification
public Guid CustomerId { get; init; }
public string CustomerCode { get; init; } = string.Empty;
// User information
public string Email { get; init; } = string.Empty;
public string FirstName { get; init; } = string.Empty;
public string LastName { get; init; } = string.Empty;
public string PhoneNumber { get; init; } = string.Empty;
public Gender? Gender { get; init; }
public UserType UserType { get; init; }
public Guid? EntityId { get; init; }
// Status tracking
public UserStatus Status { get; init; } = UserStatus.Active;
// Profile
public string? ProfileImageUrl { get; init; }
public List<CustomerAddress> Addresses { get; init; } = new();
// Audit fields
public DateTime CreatedAt { get; init; }
public DateTime UpdatedAt { get; init; }
public Guid? CreatedBy { get; init; }
public Guid? UpdatedBy { get; init; }
}
public record CustomerAddress
{
public Guid CustomerAddressId { get; init; }
public string City { get; init; } = string.Empty;
public string State { get; init; } = string.Empty;
public string Country { get; init; } = string.Empty;
public string Pincode { get; init; } = string.Empty;
public double? Latitude { get; init; }
public double? Longitude { get; init; }
}
9. Get Technician Profile (Own)
public record TechnicianDetails
{
public Guid TechnicianId { get; set; }
public string? TechnicianCode { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? Email { get; set; }
public string? PhoneNumber { get; set; }
public DateTime? JoiningDate { get; set; }
public string? EmployeeType { get; set; }
public string? EmergencyContactName { get; set; }
public string? EmergencyContactPhone { get; set; }
public List<string>? Skills { get; set; }
public string? Specialization { get; set; }
public Guid? UserId { get; set; }
public string? ProfileImageUrl { get; set; }
public DateTime? UpdatedAt { get; set; }
}
public class TechnicianAddress
{
public Guid TechnicianAddressId { get; set; }
public string City { get; set; } = string.Empty;
public string State { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
public string Pincode { get; set; } = string.Empty;
public double? Latitude { get; set; }
public double? Longitude { get; set; }
}
10. Get Customer List (Admin, Paginated)
public class CustomerFilter
{
public string? SearchKeyword { get; set; } // Global search across all fields
public string? Status { get; set; } // Active, Inactive, All
public string? SearchTerm { get; set; } // Search by name, email, customer code
public string? Gender { get; set; } // Filter by gender
public string? City { get; set; } // Filter by city
public string? State { get; set; } // Filter by state
public string? Country { get; set; } // Filter by country
public string? Pincode { get; set; } // Filter by pincode
public DateTime? CreatedFrom { get; set; }
public DateTime? CreatedTo { get; set; }
public int RowsPerPage { get; set; } = 10;
public int PageNumber { get; set; } = 1;
}
11. Technician Signin
// Uses same SignInRequest as Customer Signin
// Uses same SigninResponse as Customer Signin
12. Admin Signin
// Uses same SignInRequest as Customer Signin
// Uses same SigninResponse as Customer Signin
13. Respond to New Password Challenge
public record NewPasswordRequest
{
public required string Username { get; init; }
public required string NewPassword { get; init; }
}
// Uses same SigninResponse as Customer Signin
14. Refresh Token
public class RefreshTokenRequest
{
[Required(ErrorMessage = "Refresh token is required")]
public required string RefreshToken { get; set; }
}
public class RefreshTokenResponse
{
public string AccessToken { get; set; } = string.Empty;
public string IdToken { get; set; } = string.Empty;
public int ExpiresIn { get; set; }
}
15. Change Password
public record PasswordChangeRequest
{
public required string OldPassword {get; init;}
public required string NewPassword {get; init;}
public required string ConfirmPassword {get; init;}
}
public class ChangePasswordResponse
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
}
16. Forgot Password (Send Email)
public record ForgotPasswordRequest
{
public required string Email { get; init; }
}
public record ForgotPasswordResponse
{
public bool Success { get; init; }
public string? Message { get; init; }
}
17. Confirm Forgot Password
public record ForgotPasswordConfirmRequest
{
public required string Email { get; init; }
public required string ConfirmationCode { get; init; }
public required string NewPassword { get; init; }
}
// Uses commonresponse as response
18. Admin Reset Password
public class AdminResetPasswordRequest
{
public required string UserName { get; set; }
}
public class AdminResetPasswordResponse
{
public bool Success { get; set; }
public string Message { get; set; } = string.Empty;
}
19. Logout
Description:
Signs out the user, invalidates tokens, and clears all authentication cookies.
Request:
No request body required. The access token is retrieved from the current HTTP context.
Response:
- 200 OK: Logout successful.
- 401 Unauthorized: No access token available or user not authorized.
- 400 Bad Request: User ID not found, invalid parameter, password reset required, resource not found, or user not confirmed.
- 403 Forbidden: Request blocked by security policy.
- 429 Too Many Requests: Rate limit exceeded.
- 500 Internal Server Error: Error during logout.
Common Response Models
public record CommonResponse
{
public int Status { get; init; }
public string? Message { get; init; }
}
public record ResponseWithData<T> : CommonResponse
{
public T? Data { get; init; }
}
public record PaginatedResponse<T> : CommonResponse
{
public List<T> Data { get; init; } = [];
public int TotalCount { get; init; }
}
public class ServerPaginatedData<T>
{
public List<T> Data { get; set; } = [];
public int TotalNumber { get; set; }
public bool HasPreviousPage { get; set; }
public bool HasNextPage { get; set; }
public int TotalPages { get; set; }
public int PageNumber { get; set; }
public int RowsPerPage { get; set; }
}
API Endpoints Overview
Customer Authentication Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 1 | /api/auth/signup | POST | No | Customer self-registration | SignUpRequest | SignUpResponse |
| 2 | /api/auth/confirm-signup | POST | No | Verify customer email with OTP | ConfirmSignUpRequest | SignInResponse |
| 3 | /api/auth/customer-login | POST | No | Customer login | LogInRequest | SignInResponse |
| 6 | /api/auth/customer/{customerid} | GET | Yes (Customer) | Get own customer profile | None | GetCustomerProfileResponse |
Technician Management Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
| --- | ------------------------------------- | ------ | ---------------- | -------------------------------- | -------------------------- | ---------------------------------------- | --- |
| 4 | /api/technician/create | POST | Yes (Admin) | Admin creates technician account | TechnicianRequest | CommonResponse | |
| 7 | /api/technician/update | PUT | Yes (Technician) | Update technician profile | UpdateTechnicianRequest | CommonResponse |
| 8 | /api/technician/list | GET | Yes (Admin) | Get all technicians (paginated) | TechnicianFilter (Query) | ServerPaginatedData<TechnicianDetails> |
| 9 | /api/auth/technician/{technicianid} | GET | Yes (Technician) | Get own technician profile | None | GetTechnicianProfileResponse |
| 10 | /api/auth/technician-login | POST | No | Technician login | LogInRequest | SignInResponse |
Admin Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 11 | /api/auth/admin-login | POST | No | Admin login | LogInRequest | SignInResponse |
| 12 | /api/customer/list | GET | Yes (Admin) | Get all customers (paginated) | CustomerFilter (Query) | ServerPaginatedData<CustomerDetails> |
| 18 | /api/auth/admin-reset-password | POST | Yes (Admin) | Admin force reset user password | AdminResetPasswordRequest | AdminResetPasswordResponse |
Password Management Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 13 | /api/auth/respond-new-password | POST | No | Respond to new password challenge | NewPasswordRequest | SignInResponse |
| 15 | /api/auth/change-password | POST | Yes | Change password (authenticated) | PasswordChangeRequest | ChangePasswordResponse |
| 16 | /api/auth/forgot-password | POST | No | Request password reset (send email) | ForgotPasswordRequest | ForgotPasswordResponse |
| 17 | /api/auth/confirm-forgot-password | POST | No | Confirm password reset with OTP | ConfirmForgotPasswordRequest | ConfirmForgotPasswordResponse |
Token Management Endpoints
| No | Endpoint | Method | Auth Required | Description | Request Model | Response Model |
|---|---|---|---|---|---|---|
| 14 | /api/auth/refresh-token | POST | No | Refresh access token | RefreshTokenRequest | RefreshTokenResponse |
| 19 | /api/auth/logout | POST | Yes | User logout (invalidate tokens) | LogoutRequest | LogoutResponse |
HTTP Status Codes
| Status Code | Description | When Used |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | User/resource created successfully |
| 400 | Bad Request | Invalid input, validation failure |
| 401 | Unauthorized | Invalid credentials, missing auth |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | User/resource not found |
| 409 | Conflict | User already exists |
| 423 | Locked | MFA required, new password required |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
Development Tasks & Estimates
Phase 1: Core Authentication (2 weeks)
| Task | Estimated Hours | Priority |
|---|---|---|
| Customer Signup API | 8h | High |
| Confirm Customer Signup API | 4h | High |
| Customer Signin API | 6h | High |
| Refresh Token API | 4h | High |
| Logout API | 3h | Medium |
Phase 2: Technician Management (2 weeks)
| Task | Estimated Hours | Priority |
|---|---|---|
| Create Technician API (Admin) | 8h | High |
| Activate Technician API | 6h | High |
| Technician Signin API | 4h | High |
| Update Technician Profile API | 6h | Medium |
| Get Technician List API | 6h | Medium |
| Get Technician Profile API | 4h | Medium |
Phase 3: Admin & Password Management (1.5 weeks)
| Task | Estimated Hours | Priority |
|---|---|---|
| Admin Signin API | 4h | High |
| Get Customer List API | 6h | Medium |
| Forgot Password API | 5h | High |
| Confirm Forgot Password API | 5h | High |
| Change Password API | 4h | Medium |
| Admin Reset Password API | 5h | Medium |
| Respond New Password API | 4h | High |
Phase 4: Additional Features (1 week)
| Task | Estimated Hours | Priority |
|---|---|---|
| Get Customer Profile API | 4h | Medium |
| Login History Tracking | 6h | Low |
| Database Transaction Handling | 8h | High |
| Unit Tests | 16h | High |
| Integration Tests | 12h | Medium |
| API Documentation (Swagger) | 4h | Medium |
Total Estimated Time: 6.5 weeks (260 hours)
Notes
Key Implementation Considerations
-
EntityId Strategy:
- EntityId is generated upfront during user creation
- Used as foreign key in both
userdetails.entityidand entity-specific tables (customermaster.customerid,technicianmaster.technicianid) - Ensures referential integrity between Cognito and database
-
Transaction Management:
- Use
TransactionScopefor multi-table operations (e.g., creating user + customer) - Rollback database changes if Cognito operations fail
- Log errors but continue if database sync fails after successful Cognito operations
- Use
-
Error Handling:
- Cognito-specific exceptions mapped to appropriate HTTP status codes
- Detailed error messages for validation failures
- Generic error messages for security-sensitive operations (login failures)
-
Security Best Practices:
- Passwords never logged or returned in responses
- Temporary passwords only returned once during technician creation
- JWT tokens stored as HTTP-only, Secure cookies
- Secret hash computed for all Cognito operations when client secret is configured
-
Testing Recommendations:
- Mock Cognito client for unit tests
- Use test user pool for integration tests
- Test transaction rollback scenarios
- Verify JWT token expiration and refresh logic
-
Future Enhancements:
- MFA implementation for high-security operations
- Social login integration (Google, Facebook)
- Email templates customization
- Advanced audit logging with IP tracking
- Rate limiting and brute-force protection