IAM - Sign-in¶
- Status: Draft
- Prefix:
IAM - Related: User types, Register, Tech stack
Purpose¶
A person signs in to BizOS with an email and password, keeps a session, and can see who they are. This is the first slice of the IAM epic. Password reset, invitations, the role matrix, region scope, and the audit viewer come later.
Users and permissions¶
Any active user may sign in and read their own profile. A locked user may not sign in. Sign-in does not change a person's role. Workspace roles are super_admin, admin, tenant_owner, and user. Self-registration creates a user. Local development seeds one account for each role.
Requirements¶
| ID | Priority | Requirement |
|---|---|---|
| IAM-01 | Must | Sign-in accepts email and password and returns the current user plus a session token. |
| IAM-07 | Must | An email with no @ and domain suffix is rejected before a password check. |
| IAM-02 | Must | An unknown email is rejected whether or not the password matches. The screen says the account is not in the system. The failure count does not change, and the remaining-attempt warning is not shown. A user whose status is locked returns the generic unauthorized rejection without a remaining-attempt count. |
| IAM-13 | Must | Each failed sign-in tells the person how many attempts remain. |
| IAM-14 | Must | The fifth consecutive failure locks that email for 15 minutes. During the lock, the correct password still does not sign in, and the screen says the account is locked for 15 minutes. |
| IAM-15 | Must | A successful sign-in clears the failure count. After the lock expires, the next failure starts a new set of 5 attempts. |
| IAM-03 | Must | The session lasts 12 hours and is sent as an HttpOnly cookie and as a bearer token. |
| IAM-09 | Must | Remember me extends that session to 30 days. Logout still ends it immediately. |
| IAM-04 | Must | The current-user call returns the signed-in user, or rejects when the session is missing or expired. |
| IAM-05 | Must | Logout deletes that session and returns a success message. |
| IAM-06 | Must | Passwords are stored as a scrypt hash. The API never returns the hash. |
| IAM-08 | Must | An admin sign-in opens the workspace. Logout returns to the sign-in screen with the confirmation Signed out successfully. |
| IAM-11 | Must | A sign-in as super_admin, tenant_owner, or user opens the workspace. The menu for each role is the customer portal menu. |
| IAM-10 | Should | The sign-in screen accepts the seeded admin account credentials via the standard form without Remember me. |
| IAM-12 | Should | The sign-in screen accepts the seeded super admin, tenant owner, and user accounts credentials via the standard form without Remember me. |
| IAM-16 | Should | The sign-in and register screens, and the change-password and user screens, show the "Change theme" theme menu at the top right. The choice is synchronized across both portals in real-time. |
| IAM-17 | Must | Unified sign-in: Customer Portal /sign-in is the sole sign-in screen. When an authenticated user has role super_admin or admin, they are redirected to Admin Portal in the corresponding environment (local :4201, test admin-test.<root-domain>, staging admin-staging.<root-domain>, or production admin.<root-domain>). |
| IAM-18 | Must | Session tokens use signed JSON Web Tokens (JWT) containing sub, email, role, and expiry claims. |
| IAM-19 | Must | Both Customer Portal and Admin Portal redirect unauthenticated users to the Customer Portal sign-in screen in the corresponding environment (local :4200, test customer-test.<root-domain>, staging staging.<root-domain>, or production customer.<root-domain>) with a return redirect parameter. |
| IAM-20 | Must | Both Customer Portal and Admin Portal strictly use English for all user-facing interface text, labels, buttons, and error messages. |
Screens¶
The tenant web app has a sign-in screen at /sign-in.
- The person enters an email and password, may tick Remember me (
Remember me), and submits. - A 400 response is shown on the form. An unknown email shows
Account not found.A wrong password for an existing account showsIncorrect email or password. N attempt(s) remaining.The fifth failure, and any attempt while the 15-minute lock holds, shows5 consecutive failed attempts. Account locked for 15 minutes.A user whose status is locked still gets the generic unauthorized message, with no remaining-attempt count. - Every workspace role opens the workspace after sign-in. The menu then follows the role. Logout stays available and returns to the sign-in screen with the confirmation
Signed out successfully. - The screen provides a clean, unified sign-in form matching modern SaaS studio styling without developer shortcut buttons.
- The browser keeps the session in the HttpOnly cookie. The screen does not store the token.
Business rules¶
- Email is trimmed and stored in lower case.
CEO@Example.comandceo@example.comare the same address. - The part after
@must be a domain with a dot, such asexample.com.ceo,ceo@, andceo@exampleare rejected with 400. - Sign-in does not check password strength. A stored password is accepted when it matches, including a short one. Strength is checked when a person registers.
- Without Remember me the session lasts 12 hours. With Remember me it lasts 30 days. The cookie lifetime matches that session. Logout deletes it either way. A rejected sign-in does not create a session.
- An unknown email does not change the failure count. Failed sign-ins for an existing account are counted. Five failures lock that account for 15 minutes. The correct password does not sign in during that lock. A successful sign-in clears the count. After the lock expires, the next failure starts a new set of 5. A user whose status is
lockedis rejected without changing the count. - Logout returns 200 and
{ "message": "Logout successful" }, and clears the session cookie. - Session token is stored only as a SHA-256 hash.
- Until tenant resolution from the subdomain exists, sign-in uses the single local tenant database (
TENANT_DATABASE_URL). - One sign-in screen serves every workspace role. After sign-in the menu follows the role. A stored role of
customeris read asuser. Host names such asadmin.company.comandcompany.comare not chosen yet.
Acceptance criteria¶
- IAM-01: Given an active user, when they post the correct email and password to
/api/auth/login, then the response is the user and a token, and a session cookie is set. - IAM-07: Given an email without a domain after
@, when they sign in, then the response is 400 and no password check runs. - IAM-02: Given an unknown email, when they sign in with any password, then the screen says the account is not in the system, no session is created, and the failure count is unchanged. Given a user whose status is locked, then the response is unauthorized with no remaining-attempt count.
- IAM-13: Given an active user, when they sign in with the wrong password, then the screen shows how many of the 5 attempts remain.
- IAM-14: Given four earlier failures, when they fail a fifth time, then the email is locked for 15 minutes. Given that lock, when they post the correct password, then no session is created and the screen says the account is locked for 15 minutes.
- IAM-15: Given earlier failures, when the correct password is accepted, then the failure count is cleared. Given a lock that has expired, when the next password is wrong, then 4 attempts remain.
- IAM-04: Given a valid token, when they call
/api/auth/me, then the response is their profile. Given no token or an expired session, then the response is unauthorized. - IAM-05: Given a signed-in session, when they post
/api/auth/logout, then the response is 200 withLogout successful, and a later current-user call is unauthorized. - IAM-08: Given the sign-in screen, when an admin submits the correct email and password, then they land on the dashboard. When they log out, the sign-in screen shows
Đăng xuất thành công. - IAM-11: Given the sign-in screen, when a user, a tenant owner, or a super admin submits the correct email and password, then they land on the workspace.
- IAM-09: Given Remember me, when sign-in succeeds, then the session lasts 30 days. Given no Remember me, then it lasts 12 hours. Logout ends either session.
- IAM-10: Given a local development build, when the person uses the admin development sign-in button, then they land on the dashboard without Remember me. A production build does not show that button.
- IAM-12: Given a local development build, when the person uses the Super admin, Tenant owner, or User development sign-in button, then they land on the same workspace without Remember me. A production build does not show those buttons.
- IAM-16: Given the sign-in screen, when the person chooses AstroVista in the theme menu, then the screen switches to AstroVista at once and the choice is saved and synchronized for both portals.
- IAM-17: Given Customer Portal sign-in, when a user with role super_admin or admin signs in, then they are redirected to Admin Portal.
- IAM-18: Given sign-in, when credentials are valid, then the API issues a signed JWT token containing user identity and role.
- IAM-19: Given an unauthenticated visitor to Admin Portal, then they are redirected to Customer Portal sign-in with redirect target URL.
Out of scope¶
- Password reset, invitation, deactivation, and editing users.
- Operator permissions such as
system:monitor, provisioning, and audit export. - Data scope by region or record owner.
- Audit log viewer.
- Choosing the tenant from the request subdomain.
Open questions¶
- Authentication library: Passport inside NestJS, or an external identity provider. This slice uses application sessions in the tenant database.