Identity Domain
Manages authentication and user identity for the ticketing platform. Covers two user types — Admins (staff with portal access) and Customers (end users who buy tickets). Issues HS256 JWTs stored in a token table. Tokens are revoked on logout.
Handles:
- Login — admin and customer, returns JWT pair
- Token refresh — reissue access + refresh tokens
- Logout — revoke current token
- Token validation — verify token integrity
- Customer registration — self-service signup
- Password reset — email-based for both user types
- Admin profile — view and update own profile, change password
- Admin management — SYSADMIN creates, updates, disables admins
- Customer profile — view and update own profile, change password
- Customer management — paginated list for admin staff
Architecture
graph LR
AdminFrontend["Admin Portal"]
CustomerApp["Customer App"]
CoreAPI["CoreAPI (Identity)"]
DB["Ticketing DB\n(admin, customer, token)"]
Email["Email Service"]
AdminFrontend -->|POST /auth/login?userType=admin| CoreAPI
CustomerApp -->|POST /auth/login?userType=customer| CoreAPI
CoreAPI --> DB
CoreAPI -->|reset password email| Email
Data Model
erDiagram
Admin {
uint adminId
string username
string fullName
string role
string email
string contactNo
bool isDisabled
}
Customer {
string custId
string email
string identificationNo
string fullName
string contactNo
bool isDisabled
}
Token {
uint tokenId
string userId
string userType
string accessToken
string refreshToken
string ipAddress
string userAgent
}
CustomerLog {
uint custLogId
string custId
string type
string title
string message
string date
}
AuditLog {
uint auditLogId
string userId
string authorityLevel
string logType
string logAction
}
Admin ||--o{ Token : "has tokens"
Customer ||--o{ Token : "has tokens"
Customer ||--o{ CustomerLog : "has logs"
Roles
| Role | Scope | Capabilities |
|---|---|---|
SYSADMIN |
Platform | Full access including admin management |
ADMIN |
Platform | Manage tickets, orders, customers |
MEMBER |
Platform | Read-only admin access |
CUSTOMER |
End user | Manage own profile and orders |
Authentication
Tokens are HS256 JWTs. Pass in Authorization: Bearer <token> for protected routes.
The userId claim inside the token is the admin's username or customer's custId.
Endpoints
Auth (/auth)
POST /auth/login
Login for admin or customer.
Request
{
"username": "admin@example.com",
"password": "s3cur3p@ss",
"userType": "admin"
}
userType defaults to "admin" if omitted. For customers, pass "customer".
Response 200
{
"success": true,
"data": {
"accessToken": "<HS256 JWT>",
"refreshToken": "<HS256 JWT>",
"role": "ADMIN",
"userId": "admin@example.com",
"fullName": "Ahmad Admin"
}
}
| Status | Meaning |
|---|---|
400 |
Missing fields or invalid user type |
401 |
Wrong credentials |
POST /auth/refresh-token
Refresh the token pair. Pass the current refresh token in Authorization: Bearer <refresh_token>.
Response 200 — same shape as login.
GET /auth/logout
Revoke the current access token. Requires Authorization: Bearer <access_token>.
Response 200
{ "success": true, "data": { "success": true } }
GET /auth/validate
Validate token integrity. Requires Authorization: Bearer <access_token>.
Response 200
{ "success": true, "data": { "valid": true } }
POST /auth/customer/create
Self-registration — creates a new customer account.
Request
{
"email": "user@example.com",
"password": "s3cur3p@ss",
"identificationNo": "900101-14-1234",
"fullName": "Ahmad Bin Ali",
"contactNo": "+60123456789"
}
Response 201
{
"success": true,
"data": {
"custId": "CUST-001",
"email": "user@example.com",
"fullName": "Ahmad Bin Ali",
"identificationNo": "900101-14-1234",
"isDisabled": false,
"createdAt": "2026-06-01T10:00:00Z"
}
}
| Status | Meaning |
|---|---|
409 |
Email already registered |
POST /auth/customer/reset-password
Trigger a password reset email for a customer.
Request
{ "email": "user@example.com" }
Response 200 — always returns success (security measure — no email existence disclosure).
POST /auth/admin/reset-password
Trigger a password reset email for an admin.
Request
{ "email": "admin@example.com" }
Response 200 — always returns success.
Admin Profile (/api/admin)
All require auth + role ADMIN, MEMBER, or SYSADMIN.
GET /api/admin/profile
Get the authenticated admin's own profile.
Response 200
{
"success": true,
"data": {
"admin": {
"adminId": 1,
"username": "jsmith",
"fullName": "John Smith",
"email": "jsmith@example.com",
"contactNo": "+60123456789",
"role": "ADMIN"
}
}
}
PUT /api/admin/profile
Update own profile fields.
Request
{
"fullName": "John Smith Jr.",
"email": "jsmith2@example.com",
"contactNo": "+60123456788"
}
PUT /api/admin/password
Change own password.
Request
{
"currentPassword": "old_pass",
"newPassword": "new_pass"
}
Admin Management (/api/admin/management)
All require SYSADMIN role.
GET /api/admin/management
List all admin accounts.
POST /api/admin/management
Create a new admin account.
Request
{
"username": "newadmin",
"password": "s3cur3p@ss",
"fullName": "New Admin",
"email": "newadmin@example.com",
"contactNo": "+60123456780",
"role": "MEMBER"
}
| Status | Meaning |
|---|---|
409 |
Username already exists |
PUT /api/admin/management
Update an admin account (by admin ID in body).
DELETE /api/admin/management
Delete an admin (by admin ID in body).
Customer Profile (/api/customer)
GET /api/customer/profile
Get customer profile by ?custId=<id>. Public — no auth required.
PUT /api/customer/profile
Update own customer profile. Requires CUSTOMER role.
Request
{
"fullName": "Ahmad Bin Ali Updated",
"contactNo": "+60123456789"
}
PUT /api/customer/password
Change own password. Requires CUSTOMER role.
Request
{
"currentPassword": "old_pass",
"newPassword": "new_pass"
}
GET /api/customer/management
Paginated customer list. Requires ADMIN, SYSADMIN, or MEMBER role.
Query params: page, limit, query