Starcounter
HomeDownloadDocsCommunity
2.3.1
2.3.1
  • Starcounter Documentation
  • Getting Started
  • Starcounter
    • Collapsing the Stack
      • Complexity and Scalability Tradeoff
      • The Future of Micro-Services
      • 10 Benefits of Collapsing the Stack
    • Integrated Database and Web Server
  • Hello World - Tutorial
    • Create a Database Class
    • Create a Real Time UI
    • First Interactive UI
    • Computed Properties
    • Expense Tracker
    • Cancel and Delete
    • The Next Step
  • Guides
    • Database
      • Database Classes
      • Data manipulation
      • Object Identity and Object References
      • Querying with SQL
      • Data Types
      • Relations
      • Inheritance
      • Sharing data
      • Database Configuration
      • Comparing Database Objects
      • Referential Integrity and Constraints
    • SQL
      • Identifiers
      • Path Expressions
      • Data operators
      • Joins
      • Aggregates
      • Comparisons and Logical Operators
      • Sorting
      • Fetch
      • Offset Key
      • Indexes
      • Literals
      • Query Plan Hints
      • Reserved words
      • Query for Database Classes
      • SQL Isolation Between Applications
    • Transactions
      • Short-Running Transactions
      • Long running transactions
      • Using Transactions
      • Running Background Jobs
      • Commit Hooks
    • Typed JSON
      • JSON-by-example
      • Code-Behind
      • Data Bindings
      • Callback Methods
      • Responding with JSON
      • Accepting JSON in Requests
      • Primitive Arrays and Single Value Types
      • Typed JSON Internals
    • Blendable Web Apps
      • Starcounter MVVM
      • Palindrom
      • Client-Side Stack
      • Sessions
      • HTML Views
      • App Shell
      • Web Components
      • View Attaching
      • View Composing
      • HTML Compositions
      • HTML Views Blending Guidelines
      • Avoiding CSS conflicts
      • Debugging
    • Network
      • HTTP
      • Internal Self Calls
      • Middleware
      • Anonymous or Substitute Handlers
      • URL Aliases and Redirects
      • Network Gateway
      • Static File Server
      • External HTTP Calls
      • WebSocket
      • Avoiding URI conflicts
      • TCP Sockets
      • UDP Sockets
    • Publishing Apps
    • Working with Starcounter
      • Release Channels
      • Starting and Stopping Apps
      • Administrator Web UI
      • Star CLI
      • StarAdmin CLI
      • StarDump CLI
      • Working in Visual Studio
      • Error Log
      • Using HTTPS on NGINX
      • Using HTTPS on IIS
      • Run Starcounter in Production
      • Weaver
      • Investigating App Crashes
      • Configuration Structure
      • Database Refactoring
      • Using Unload/Reload to Modify Database Schema
      • Kernel Questions and Answers
      • Log Files
  • Cookbook
    • Attach an HTTP Request to an Existing Long-Running Transaction
    • Cookie-Based Authentication
    • Timestamp on Object Creation
    • Creating Strongly Typed JSON Collections
    • Migrating From 2.2 to 2.3+
    • Multiple Pages
    • Icons
    • Proposed Project Structure
    • Acceptance Testing with Selenium
    • Requesting a User to Authenticate
    • How to delete unused tables and columns
Powered by GitBook
On this page
  • Internals of Sign In App
  • Form for Authentication Input
  • HTTP Handler that Sets the Cookie
  • Middleware that Reads the Cookie
  1. Cookbook

Cookie-Based Authentication

PreviousAttach an HTTP Request to an Existing Long-Running TransactionNextTimestamp on Object Creation

Last updated 7 years ago

In Starcounter you have as many sessions as there are browser windows or tabs opened with your app. The session object stores the state of a view-model for that particular window or tab. Each session is assigned a new, unique identifier. Session is not aware of concepts like "authentication" or "a returning user".

This is different from persistent user sessions known from other frameworks such as or . These frameworks use the term "session" when they mean remembering of returning users. That is the basis for cookie-based authentication.

How do you implement cookie-based authentication with Starcounter? You have to code it on your own using our HTTP low level API. Or if you want to keep it simple - run your app alongside another app that does just that in middleware.

is a prefab app that authenticates a user using a username and a password. It generates an auth token and stores it in a cookie for use in future sessions.

Internals of Sign In App

Let's take a deeper look at how Sign In app works. Essentially, this can be divided into three parts:

  • Form for authentication input

  • HTTP handler that sets the cookie

  • Middleware that reads the cookie

Form for Authentication Input

Sign In has a view-model that can be mapped to any app. It is a typical HTML form that asks for authentication input (username & password).

Unlike typical Puppet-based view-models, the form is not sent using WebSocket. The form result is sent using XmlHttpRequest to a HTTP handler, because that's the only way to set a cookie.

This is how the form gets submitted to force using HTTP:

var password = Sha1.hash(this.password);
var url = this.url + this.username + "/" + password + "/" + this.rememberMe;
this.set("password", "");
document.querySelector("palindrom-client").network.changeState(url);

HTTP Handler that Sets the Cookie

When the user submits the form, a relevant HTTP handler tries to authenticate the user. In case of successful authentication, an auth token is generated and stored in the database:

var systemUser = Db.SQL<SystemUser>("SELECT o FROM Simplified.Ring3.SystemUser o WHERE o.Username = ?", Username).FirstOrDefault();

if (systemUser == null)
{
    return null;
}

GeneratePasswordHash(Username.ToLower(), Password, systemUser.PasswordSalt, out hashedPassword);

if (systemUser.Password != hashedPassword)
{
    return null;
}

SystemUserSession userSession = null;

Db.Transact(() =>
{
    var token = new SystemUserTokenKey();

    token.Created = token.LastUsed = DateTime.UtcNow;
    token.Token = CreateAuthToken(systemUser.Username);
    token.User = systemUser;

    userSession = AssureSystemUserSession(token);
});

Auth token is now sent to the user as a cookie in the HTTP response. Future HTTP requests from that user will include the auth token cookie:

var cookie = new Cookie()
{
    Name = AuthCookieName
};

if (Session != null && Session.Token != null)
{
    cookie.Value = Session.Token.Token;
}

if (Session == null)
{
    cookie.Expires = DateTime.Today;
}
else if (RememberMe)
{
    cookie.Expires = DateTime.Now.AddDays(rememberMeDays);
}
else
{
    cookie.Expires = DateTime.Now.AddDays(1);
}

Handle.AddOutgoingCookie(cookie.Name, cookie.GetFullValueString());

Middleware that Reads the Cookie

Sign In app registers a request middleware. The middleware checks if the request contains a valid auth token cookie. In that case, we can immediately authenticate the user without asking for the credentials.

If the auth token is correct, the middleware creates a Session object and identifies the user. Any other app that handles this request will now see the user.

Application.Current.Use((Request request) =>
{
    Cookie cookie = GetSignInCookie();

    if (cookie != null)
    {
        Session.Current = Session.Current ?? new Session(SessionOptions.PatchVersioning);

        var session = SystemUser.SignInSystemUser(cookie.Value);

        if (session != null)
        {
            RefreshAuthCookie(session);
        }
    }

    return null;
});

With this middleware, any app that handles this request will see that the session already exists. In case of our sample apps, the User Admin app shares the data model with the Sign In app. A simple lookup in the SystemUserSession table will get the relevant SystemUser object.

var query = "SELECT o FROM Simplified.Ring5.SystemUserSession o WHERE o.SessionIdString = ?";
var userSession = Db.SQL<SystemUserSession>(query, Session.Current.SessionId).FirstOrDefault();

return userSession?.Token?.User;
ASP.NET Core
PHP
Sign In