Skip to main content

Authentication Flow

Introduction

Damsy ERP authenticates users with a classic session-based login: the user selects a company, submits credentials, the application validates against SQL Server via GetLoginUser, and on success populates ASP.NET session state before redirecting to the dashboard.

There is no JWT or OAuth flow for standard module access. The session keys written at login become the authorization context for all subsequent requests.

Purpose

This page documents the complete authentication sequence — from the login form through password encryption, stored procedure validation, session initialization, and redirect — so you can extend login behavior or debug sign-in failures safely.

When to Use

Use this reference when you:

  • Debug "invalid username or password" issues
  • Add fields returned from GetLoginUser to session
  • Implement account lockout or password policy changes
  • Trace why a user reaches dashboard but lacks module tiles

How It Works

Sequence diagram

Key components

ComponentLocationRole
LoginControllerDamsyERP.UI/Controllers/LoginController.csGET/POST login, session fill, redirect
Login_DALDAL/Login_DAL.csCalls [dbo].[GetLoginUser]
HashCryptographyUTILITIESEncrypts password before SP call
GetLoginUserSQL ServerValidates credentials; returns user + module access
Common.GetCompanyShared helperPopulates company dropdown on login form
LoginAttemptTrackerUI helperRate-limits failed attempts

GET /Login/Index

  1. If Session["CompID"] is already set → redirect to ~/Dashboard/Index
  2. Otherwise call BuildLoginView():
    • Load companies via Common.GetCompany
    • Insert placeholder "Select Company" (CompID = 0)
    • Run UpdateSoftwareVersion() (writes Session["Version"])
    • Return UserLogin view

/Login/UserLogin redirects to /Login/Index for legacy bookmarks.

POST /Login/Index

  1. Anti-forgery: [ValidateAntiForgeryToken] on POST
  2. Lockout check: LoginAttemptTracker.IsLockedOut — returns friendly message if too many failures
  3. Set Login_BO.User.IsActive = true
  4. Login_DAL.GetLoginUser with Login ID, encrypted password, CompID
  5. Load default payroll period via PayrollReportService.GetStartForMonth
  6. Load SMTP settings via Login_DAL.MailConfigure[dbo].[GetEmailConfigration]
  7. Success criterion: objuser.UserName is not null or empty

Password handling

Inside Login_DAL.GetLoginUser:

HashCryptography encryptPassword = new HashCryptography();
objUser.Password = encryptPassword.Encrypt(objUser.Password);
// passed to SP as @userpassword

The stored procedure compares against the encrypted value stored in the database. Do not send plaintext passwords to SQL.

Session keys set on success

After successful authentication, Session.Clear() runs first, then:

Session keySource
dtVerifyUserFull BO.User object (includes module bool flags)
UserName, UserIDDisplay name and UserAccountsID
CompID, CompNameSelected company
Role, RoleIdRole name and ID (note: RoleId casing)
StartMonth, StartYearDefault payroll period
BranchCodeUser branch
CDKEY, EFUSERNAME, EFPASSWORDE-invoice credentials
ZAPIPATHServer location / ZAPI base
GenerateIRNUri, CancelIrnUri, PrintIRNUriIRN API endpoints
PrintEWayBillDetailed, PrintEWayBillSummary, EWayBillDeliveryChallanE-Way bill URLs
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PSWDMail configuration

Redirect: return Redirect("~/Dashboard/Index");

Failure path

  • LoginAttemptTracker.RecordFailure
  • Reload company list
  • Model error: "The user name or password provided is incorrect"
  • Return UserLogin view (does not reveal whether login ID or password failed)

Developer Notes

  • FormsAuthentication.SignOut is called on logout, but day-to-day module gating uses session keys, not roles claims.
  • Software version check: Login also updates SoftwareVersions table when app version exceeds DB version.
  • Module flags come from SP columns mapped in Login_DAL (e.g. ZstockUser.ZSTOCK, AttendancePuncgingUser.AttPunch).
  • Fine-grained menu permissions use GetDataUserPermissions separately — not at login time for every menu item.
Do not add ModuleAccess session key

Access control uses dtVerifyUser boolean properties and per-menu permission SPs. There is no Session["ModuleAccess"] key in this application.

Examples

Minimal successful login (blank DB seed)

FieldValue
CompanyDamsy Technologies
Login IDadmin
PasswordAdmin@123

Checking authentication in a new controller action

if (string.IsNullOrEmpty(Convert.ToString(Session["CompID"])))
return RedirectToAction("UserLogin", "Login", new { Area = "" });

Reading module access after login

var user = Session["dtVerifyUser"] as User;
if (user?.Payroll == true) { /* show payroll features */ }

Important Notes

Session fixation

Session.Clear() before populating keys on successful login reduces stale session data risk. Preserve this pattern if extending login.

CompID is required

Login POST must include a valid company (CompID >= 1). The BO validates [Range(1, Int32.MaxValue)] on Compid.

Common Mistakes

MistakeSymptom
Comparing plaintext password in SQLLogin always fails
Using RoleID session key (wrong casing)Null role in permission checks — use RoleId
Skipping CompID in SP callUser authenticates against wrong company
Expecting menu items without DB permissions seedLogin works; menus empty or pages unauthorized
Storing password in sessionNot done by design — only user metadata and flags

Next Steps

  1. Read Session Management for keys added later in the session lifecycle.
  2. Read Module Routing to navigate from dashboard into modules.