AboutBlogContact
Backend EngineeringMay 8, 2000 7 min read 155Updated: June 22, 2026

Session State and User Authentication with ASP Classic (2000)

AunimedaAunimeda
📋 Table of Contents

In 2000, if you were building a web application for a corporate environment running Windows servers, you used Active Server Pages. Microsoft's IIS + ASP was the enterprise stack: Windows NT 4 or Windows 2000 Server, IIS 5, SQL Server 7 or 2000, and ASP scripting in VBScript.

PHP ran on Unix and required Apache. Perl required knowing Unix. ASP ran on Windows, was managed via familiar Windows tools, integrated with Active Directory, and used VBScript - a language that IT departments already knew from Office macro automation. For businesses already invested in Microsoft infrastructure, ASP was the obvious path.

Building a login system with session state was the first real web application task. Here is the complete implementation from 2000.


The Session Object: ASP's Built-in State Management

ASP's Session object was a server-side dictionary per user, keyed by a cookie (ASPSESSIONID) set automatically by IIS. No manual cookie management required - IIS handled the session cookie, and your code wrote to and read from Session like a dictionary.

<%
' login.asp - Classic ASP login page with SQL Server authentication
' VBScript, IIS 5, SQL Server 2000, circa 2000

Option Explicit

Dim strError
strError = ""

If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
    
    Dim strUsername, strPassword
    strUsername = Trim(Request.Form("username"))
    strPassword = Trim(Request.Form("password"))
    
    ' Basic input validation
    If strUsername = "" Or strPassword = "" Then
        strError = "Username and password are required."
    Else
        ' Authenticate against database
        Dim bAuthenticated
        bAuthenticated = AuthenticateUser(strUsername, strPassword)
        
        If bAuthenticated Then
            ' Store user identity in session
            Session("IsLoggedIn") = True
            Session("Username")   = strUsername
            Session("LoginTime")  = Now()
            
            ' Redirect to protected area
            Response.Redirect "dashboard.asp"
            Response.End
        Else
            strError = "Invalid username or password."
        End If
    End If
End If
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <title>Login</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#FFFFFF">
<h2>Member Login</h2>
<% If strError <> "" Then %>
  <p><font color="red"><b><%= Server.HTMLEncode(strError) %></b></font></p>
<% End If %>
<form method="POST" action="login.asp">
  <table border="0" cellpadding="4">
    <tr>
      <td>Username:</td>
      <td><input type="text" name="username" size="25"></td>
    </tr>
    <tr>
      <td>Password:</td>
      <td><input type="password" name="password" size="25"></td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" value="Log In"></td>
    </tr>
  </table>
</form>
</body>
</html>

Database Authentication with ADODB

<%
' Included as a function in login.asp or a separate include file

Function AuthenticateUser(strUsername, strPassword)
    AuthenticateUser = False
    
    Dim oConn, oRS
    Dim strSQL
    
    ' Create ADODB Connection object - the COM-based database interface
    Set oConn = Server.CreateObject("ADODB.Connection")
    
    ' DSN-less connection string to SQL Server 2000
    oConn.Open "Provider=SQLOLEDB;" & _
               "Data Source=SQLSERVER01;" & _
               "Initial Catalog=MyAppDB;" & _
               "User ID=webapp_user;" & _
               "Password=webapp_pass;"
    
    ' WARNING: In 2000, many developers concatenated strings directly.
    ' This was vulnerable to SQL injection. The correct approach even then:
    ' use parameterized queries via ADODB Command object (shown below).
    
    Set oRS = Server.CreateObject("ADODB.Recordset")
    
    ' Parameterized query - the correct 2000-era approach
    Dim oCmd
    Set oCmd = Server.CreateObject("ADODB.Command")
    Set oCmd.ActiveConnection = oConn
    
    oCmd.CommandText = "SELECT UserID, Username, PasswordHash, IsActive " & _
                       "FROM Users WHERE Username = ?"
    oCmd.CommandType = 1   ' adCmdText
    
    ' Append parameter - prevents SQL injection
    oCmd.Parameters.Append oCmd.CreateParameter("@username", 200, 1, 50, strUsername)
    ' 200 = adVarChar, 1 = adParamInput, 50 = max length
    
    Set oRS = oCmd.Execute()
    
    If Not oRS.EOF Then
        Dim storedHash
        storedHash = oRS("PasswordHash")
        
        ' Compare password hash - MD5 was standard in 2000
        ' (bcrypt didn't become common for web apps until ~2007-2010)
        If MD5Hash(strPassword) = storedHash Then
            If CBool(oRS("IsActive")) Then
                AuthenticateUser = True
                ' Log the login event
                Call LogLoginAttempt(CStr(oRS("UserID")), True)
            End If
        Else
            Call LogLoginAttempt(CStr(oRS("UserID")), False)
        End If
    End If
    
    oRS.Close
    oConn.Close
    Set oRS   = Nothing
    Set oCmd  = Nothing
    Set oConn = Nothing
    
End Function
%>

Protecting Pages with Session Checks

Every protected page included a session check at the top - ASP #include directives let you share this logic:

<%
' auth_check.asp - included at the top of every protected page
' Usage: <!-- #include file="auth_check.asp" -->

If Not CBool(Session("IsLoggedIn")) Then
    Response.Redirect "login.asp?return=" & Server.URLEncode(Request.ServerVariables("URL"))
    Response.End
End If

' Session timeout check - 30 minutes of inactivity
Dim dtLoginTime
dtLoginTime = Session("LoginTime")

If IsDate(dtLoginTime) Then
    If DateDiff("n", dtLoginTime, Now()) > 30 Then
        ' Session expired - clear it and redirect
        Session.Abandon
        Response.Redirect "login.asp?msg=timeout"
        Response.End
    End If
End If

' Update last activity time
Session("LoginTime") = Now()
%>

A protected page:

<%
' dashboard.asp - member-only page
Option Explicit
%>
<!-- #include file="auth_check.asp" -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>Dashboard</title></head>
<body>
<h1>Welcome, <%= Server.HTMLEncode(Session("Username")) %>!</h1>
<p>You are logged in. <a href="logout.asp">Log out</a></p>
</body>
</html>

Logout:

<%
' logout.asp
Session.Abandon   ' Clears all session variables and invalidates the session cookie
Response.Redirect "login.asp"
Response.End
%>

The SQL Server Table Structure

-- SQL Server 2000 schema
-- Run in Query Analyzer

CREATE TABLE Users (
    UserID       INT IDENTITY(1,1) PRIMARY KEY,
    Username     VARCHAR(50)  NOT NULL UNIQUE,
    PasswordHash VARCHAR(32)  NOT NULL,   -- MD5 hex string, 32 characters
    Email        VARCHAR(100) NOT NULL,
    IsActive     BIT          NOT NULL DEFAULT 1,
    CreatedDate  DATETIME     NOT NULL DEFAULT GETDATE(),
    LastLogin    DATETIME     NULL
)
GO

-- Index on Username for fast lookups
CREATE UNIQUE INDEX IX_Users_Username ON Users (Username)
GO

-- Login audit log
CREATE TABLE LoginLog (
    LogID      INT IDENTITY(1,1) PRIMARY KEY,
    UserID     INT      NOT NULL,
    LoginDate  DATETIME NOT NULL DEFAULT GETDATE(),
    IPAddress  VARCHAR(15) NOT NULL,
    Success    BIT      NOT NULL
)
GO

Inserting a user with a hashed password from ASP:

<%
' register.asp - create a new user account

' Hash password before storing - never store plaintext
' MD5 via CAPICOM or custom implementation
' Many teams used a third-party MD5.asp component from ASPFaq.com

' Common pattern in 2000: download a free "MD5.asp" include file
' <!-- #include file="md5.asp" -->

Dim strHashedPassword
strHashedPassword = MD5(Request.Form("password"))

Dim oConn, oCmd
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open strConnectionString

Set oCmd = Server.CreateObject("ADODB.Command")
Set oCmd.ActiveConnection = oConn
oCmd.CommandText = "INSERT INTO Users (Username, PasswordHash, Email) VALUES (?, ?, ?)"
oCmd.Parameters.Append oCmd.CreateParameter("@u",     200, 1, 50,  strUsername)
oCmd.Parameters.Append oCmd.CreateParameter("@ph",    200, 1, 32,  strHashedPassword)
oCmd.Parameters.Append oCmd.CreateParameter("@email", 200, 1, 100, strEmail)
oCmd.Execute

oConn.Close
Set oCmd  = Nothing
Set oConn = Nothing
%>

What Made ASP Classic Distinct in 2000

COM integration. ASP could instantiate any COM object registered on the server: Server.CreateObject("MSWC.AdRotator"), Server.CreateObject("MSWC.BrowserType"), custom VB6 DLLs. This let developers write performance-critical logic in compiled Visual Basic and call it from ASP scripts.

The Application object. While Session was per-user, Application was shared across all users:

<%
' application.asp - called from Global.asa Application_OnStart
' Shared state: connection string, site configuration, cached data

Application.Lock
Application("ConnectionString") = "Provider=SQLOLEDB;Data Source=..."
Application("SiteVersion")      = "2.1.4"
Application("StartTime")        = Now()
Application.Unlock
%>

Global.asa. The application event file, analogous to a modern framework's bootstrap:

' Global.asa - placed in the web root
' Fires on application start/end and session start/end

<SCRIPT LANGUAGE="VBScript" RUNAT="Server">
Sub Application_OnStart
    Application("TotalVisits") = 0
End Sub

Sub Session_OnStart
    Application.Lock
    Application("TotalVisits") = Application("TotalVisits") + 1
    Application.Unlock
    
    Session.Timeout = 30   ' 30 minutes session timeout
End Sub

Sub Session_OnEnd
    ' Clean up per-session resources
End Sub
</SCRIPT>

The Transition: ASP to ASP.NET

In 2000-2001, Microsoft was building ASP.NET, released in January 2002. The architectural shift was significant: from interpreted VBScript to compiled C# or VB.NET, from manual session/form management to the Web Forms model with server-side controls, from ADODB.Recordset to ADO.NET datasets.

Classic ASP developers who invested time in understanding the Session/Application/Request/Response object model found the transition to ASP.NET natural - the same abstractions existed, better implemented. Classic ASP continued running on IIS for years after ASP.NET's release; many production applications ran on it until Windows Server 2008 era, when hosting companies began deprecating it.

The patterns - session-based authentication, parameterized database queries, server-side rendering with template inclusion - are still the patterns of modern web development. The technology changed; the architecture did not.


Aunimeda builds production-grade backend systems - APIs, microservices, real-time applications, and system integrations.

Contact us for backend engineering services. See also: Custom Software Development, Web Development

Read Also

How to Implement JWT Authentication in Node.js + Express (2015)aunimeda
Backend Engineering

How to Implement JWT Authentication in Node.js + Express (2015)

JWT became the standard for stateless API authentication in 2015 as mobile apps replaced session cookies. This guide covers the exact implementation: token generation, middleware, refresh tokens, and the security mistakes we made and fixed.

Node.js: Ryan Dahl's 45-Minute Talk That Rewrote Backend Development (2009)aunimeda
Backend Engineering

Node.js: Ryan Dahl's 45-Minute Talk That Rewrote Backend Development (2009)

On November 8, 2009, Ryan Dahl presented Node.js at JSConf EU in Berlin. He showed JavaScript running on the server with non-blocking I/O. The audience sat in silence, then gave a standing ovation. Within three years, Node.js had more packages than any other programming language ecosystem. This is what he built and why it worked.

Google Chrome and V8: The Day JavaScript Got Fast (2008)aunimeda
Backend Engineering

Google Chrome and V8: The Day JavaScript Got Fast (2008)

On September 2, 2008, Google released Chrome 0.2 with the V8 JavaScript engine. V8 compiled JavaScript directly to native machine code. Benchmarks showed it 10-50x faster than IE7. Within eighteen months, every browser had raced to match it. JavaScript performance went from a constant limitation to a solved problem.

Need IT development for your business?

We build websites, mobile apps and AI solutions. Free consultation.

Get Consultation All articles