Skip to main content
Version: RK Auto

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

  1. Customer: Self-registration → Email verification → Login → Access customer portal
  2. Technician: Admin creation → First-time activation → Profile setup → Login → Field operations
  3. Admin: Pre-configured accounts → Login → Administrative operations

Requirements

Functional Requirements

IDRequirementPriority
FR-1Customer self-registration with email verificationHigh
FR-2Admin-initiated technician account creationHigh
FR-3First-time technician activation with password setupHigh
FR-4Role-based authentication (Customer/Technician/Admin)High
FR-5Email-based OTP verification for signupHigh
FR-6Forgot password with email verificationHigh
FR-7Admin password reset for any userMedium
FR-8Change password for authenticated usersMedium
FR-9Token refresh mechanismHigh
FR-10User profile retrieval and updatesMedium
FR-11Paginated user listing (Admin only)Low
FR-12Logout with token invalidationMedium
FR-13Login history trackingLow

Non-Functional Requirements

IDRequirementTarget
NFR-1API response time< 500ms (95th percentile)
NFR-2Concurrent user sessionsSupport 10,000+ concurrent users
NFR-3Password strengthMin 8 chars, uppercase, lowercase, number, special char
NFR-4Token expiryAccess: 1 hour, Refresh: 30 days
NFR-5Database transactionACID compliance for user creation
NFR-6Audit logging100% 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

  1. AuthController: HTTP endpoint handling, request validation, cookie management
  2. CognitoAuthService: Business logic, Cognito API integration, error handling
  3. AuthDal: Database operations, transaction management
  4. AWS Cognito: User authentication, token generation, user pool management
  5. 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 NameDescriptionPermissions
customerEnd customers requesting servicesCustomer-specific APIs
technicianField technicians performing servicesTechnician-specific APIs
adminSystem administratorsFull access to all APIs

Custom Attributes

Attribute NameTypeDescription
custom:EntityIdString (UUID)Links Cognito user to database entity (CustomerMaster/TechnicianMaster)

App Client Configuration

  • Authentication Flows: USER_PASSWORD_AUTH enabled
  • 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:

  1. Receive Temporary Password:
    The Technician receives a temporary password (provided by the Admin during account creation).

  2. Initial Sign-In:
    The Technician signs in using their email and the temporary password.

  3. New Password Challenge:
    The authentication response will indicate RequiresNewPassword = true, meaning the Technician must set a new password.

  4. Set New Password:
    The Technician submits a request to the "Respond to New Password Challenge" endpoint with their new password and session information.

  5. 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

NoEndpointMethodAuth RequiredDescriptionRequest ModelResponse Model
1/api/auth/signupPOSTNoCustomer self-registrationSignUpRequestSignUpResponse
2/api/auth/confirm-signupPOSTNoVerify customer email with OTPConfirmSignUpRequestSignInResponse
3/api/auth/customer-loginPOSTNoCustomer loginLogInRequestSignInResponse
6/api/auth/customer/{customerid}GETYes (Customer)Get own customer profileNoneGetCustomerProfileResponse

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

NoEndpointMethodAuth RequiredDescriptionRequest ModelResponse Model
11/api/auth/admin-loginPOSTNoAdmin loginLogInRequestSignInResponse
12/api/customer/listGETYes (Admin)Get all customers (paginated)CustomerFilter (Query)ServerPaginatedData<CustomerDetails>
18/api/auth/admin-reset-passwordPOSTYes (Admin)Admin force reset user passwordAdminResetPasswordRequestAdminResetPasswordResponse

Password Management Endpoints

NoEndpointMethodAuth RequiredDescriptionRequest ModelResponse Model
13/api/auth/respond-new-passwordPOSTNoRespond to new password challengeNewPasswordRequestSignInResponse
15/api/auth/change-passwordPOSTYesChange password (authenticated)PasswordChangeRequestChangePasswordResponse
16/api/auth/forgot-passwordPOSTNoRequest password reset (send email)ForgotPasswordRequestForgotPasswordResponse
17/api/auth/confirm-forgot-passwordPOSTNoConfirm password reset with OTPConfirmForgotPasswordRequestConfirmForgotPasswordResponse

Token Management Endpoints

NoEndpointMethodAuth RequiredDescriptionRequest ModelResponse Model
14/api/auth/refresh-tokenPOSTNoRefresh access tokenRefreshTokenRequestRefreshTokenResponse
19/api/auth/logoutPOSTYesUser logout (invalidate tokens)LogoutRequestLogoutResponse

HTTP Status Codes

Status CodeDescriptionWhen Used
200OKSuccessful request
201CreatedUser/resource created successfully
400Bad RequestInvalid input, validation failure
401UnauthorizedInvalid credentials, missing auth
403ForbiddenInsufficient permissions
404Not FoundUser/resource not found
409ConflictUser already exists
423LockedMFA required, new password required
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error

Development Tasks & Estimates

Phase 1: Core Authentication (2 weeks)

TaskEstimated HoursPriority
Customer Signup API8hHigh
Confirm Customer Signup API4hHigh
Customer Signin API6hHigh
Refresh Token API4hHigh
Logout API3hMedium

Phase 2: Technician Management (2 weeks)

TaskEstimated HoursPriority
Create Technician API (Admin)8hHigh
Activate Technician API6hHigh
Technician Signin API4hHigh
Update Technician Profile API6hMedium
Get Technician List API6hMedium
Get Technician Profile API4hMedium

Phase 3: Admin & Password Management (1.5 weeks)

TaskEstimated HoursPriority
Admin Signin API4hHigh
Get Customer List API6hMedium
Forgot Password API5hHigh
Confirm Forgot Password API5hHigh
Change Password API4hMedium
Admin Reset Password API5hMedium
Respond New Password API4hHigh

Phase 4: Additional Features (1 week)

TaskEstimated HoursPriority
Get Customer Profile API4hMedium
Login History Tracking6hLow
Database Transaction Handling8hHigh
Unit Tests16hHigh
Integration Tests12hMedium
API Documentation (Swagger)4hMedium

Total Estimated Time: 6.5 weeks (260 hours)


Notes

Key Implementation Considerations

  1. EntityId Strategy:

    • EntityId is generated upfront during user creation
    • Used as foreign key in both userdetails.entityid and entity-specific tables (customermaster.customerid, technicianmaster.technicianid)
    • Ensures referential integrity between Cognito and database
  2. Transaction Management:

    • Use TransactionScope for 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
  3. 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)
  4. 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
  5. 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
  6. 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