diff --git a/web/users_sqlite/HTTPSessionManagerDB.gd b/web/users_sqlite/HTTPSessionManagerDB.gd
new file mode 100644
index 0000000..4c446ba
--- /dev/null
+++ b/web/users_sqlite/HTTPSessionManagerDB.gd
@@ -0,0 +1,10 @@
+extends HTTPSessionManagerDB
+
+func _ready() -> void:
+ DatabaseManager.connect("initialized", self, "on_databases_initialized", [], CONNECT_ONESHOT)
+ # You could also connect to the migration signal, and write migrations if you need them
+
+func on_databases_initialized() -> void:
+ # Load sessions after the databases are initialized
+ # This happens on the Main node.
+ call_deferred("load_sessions")
diff --git a/web/users_sqlite/Main.gd b/web/users_sqlite/Main.gd
new file mode 100644
index 0000000..68088ed
--- /dev/null
+++ b/web/users_sqlite/Main.gd
@@ -0,0 +1,35 @@
+
+extends Node
+
+export(String) var database_location : String = "user://database.sqlite"
+
+func _ready() -> void:
+ var d : Directory = Directory.new()
+ var bd : String = database_location.get_base_dir()
+ var loc : String = d.get_filesystem_abspath_for(bd).append_path(database_location.get_file())
+
+ var file : File = File.new()
+ if !file.file_exists(loc):
+ PLogger.log_message("Database file doesn't exists, will run migrations!")
+ call_deferred("migrate")
+ else:
+ call_deferred("db_initialized")
+
+ var db : SQLite3Database = SQLite3Database.new()
+ db.connection_string = loc
+ DatabaseManager.add_database(db)
+
+
+func migrate() -> void:
+ PLogger.log_message("Running migrations!")
+ DatabaseManager.connect("migration", self, "_migration")
+ DatabaseManager.migrate(true, false, 0)
+
+ call_deferred("db_initialized")
+
+func db_initialized() -> void:
+ DatabaseManager.initialized()
+
+func _migration(clear: bool, should_seed: bool, pseed: int) -> void:
+ #create admin account
+ pass
diff --git a/web/users_sqlite/Main.tscn b/web/users_sqlite/Main.tscn
new file mode 100644
index 0000000..5fdfd76
--- /dev/null
+++ b/web/users_sqlite/Main.tscn
@@ -0,0 +1,74 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://WebServerSimple.gd" type="Script" id=1]
+[ext_resource path="res://WebRoot.gd" type="Script" id=2]
+[ext_resource path="res://HTTPSessionManagerDB.gd" type="Script" id=3]
+[ext_resource path="res://Main.gd" type="Script" id=4]
+
+[sub_resource type="SessionSetupWebServerMiddleware" id=3]
+
+[sub_resource type="UserSessionSetupWebServerMiddleware" id=4]
+
+[sub_resource type="CSRFTokenWebServerMiddleware" id=5]
+ignored_urls = PoolStringArray( "/user/login", "/user/register" )
+
+[node name="Main" type="Node"]
+script = ExtResource( 4 )
+
+[node name="UserManagerDB" type="UserManagerDB" parent="."]
+
+[node name="WebServerSimple" type="WebServerSimple" parent="."]
+script = ExtResource( 1 )
+
+[node name="WebRoot" type="WebRoot" parent="WebServerSimple"]
+www_root_path = "res://www/"
+middlewares = [ SubResource( 3 ), SubResource( 4 ), SubResource( 5 ) ]
+script = ExtResource( 2 )
+menu_str = "
+index
+login
+register
+settings
+logout
+
+
+"
+
+[node name="StaticWebPage" type="StaticWebPage" parent="WebServerSimple/WebRoot"]
+uri_segment = "/"
+data = "
+You can go and log in on the users page here: Login
+
+Note that in this demo sessions and users are saved in an SQLite database here: \"user://database.sqlite\"
+
+There are no users by default.
+
+"
+
+[node name="UserWebPage" type="UserWebPage" parent="WebServerSimple/WebRoot"]
+uri_segment = "user"
+logged_out_render_type = 1
+logged_out_redirect_url = "/user/login"
+
+[node name="UserLoginWebPage" type="UserLoginWebPage" parent="WebServerSimple/WebRoot/UserWebPage"]
+uri_segment = "login"
+logged_in_render_type = 1
+logged_in_redirect_url = "/"
+
+[node name="UserRegisterWebPage" type="UserRegisterWebPage" parent="WebServerSimple/WebRoot/UserWebPage"]
+uri_segment = "register"
+logged_in_render_type = 1
+logged_in_redirect_url = "/"
+
+[node name="UserLogoutWebPage" type="UserLogoutWebPage" parent="WebServerSimple/WebRoot/UserWebPage"]
+uri_segment = "logout"
+logged_out_render_type = 1
+logged_out_redirect_url = "/"
+
+[node name="UserSettingsWebPage" type="UserSettingsWebPage" parent="WebServerSimple/WebRoot/UserWebPage"]
+uri_segment = "settings"
+logged_out_render_type = 1
+logged_out_redirect_url = "/user/login"
+
+[node name="HTTPSessionManagerDB" type="HTTPSessionManagerDB" parent="WebServerSimple"]
+script = ExtResource( 3 )
diff --git a/web/users_sqlite/WebRoot.gd b/web/users_sqlite/WebRoot.gd
new file mode 100644
index 0000000..8697445
--- /dev/null
+++ b/web/users_sqlite/WebRoot.gd
@@ -0,0 +1,18 @@
+extends WebRoot
+
+export(String, MULTILINE) var menu_str : String
+
+func _render_main_menu(request: WebServerRequest) -> void:
+ # You can render the menu differently for logged in users for example
+ # The middlewares will run before routing (in order they are in the middlewares property)
+ request.body += menu_str
+
+ # The UserSessionSetupWebServerMiddleware makes this available here:
+ # If you want to do this manually, you can do it via request.session + the UserDB singleton
+ # I recommend looking at the middleware code on the engine c++ side to see an example
+ var user : User = request.get_meta("user")
+
+ if user:
+ request.body += "You are logged in as : " + user.user_name + ".
"
+ else:
+ request.body += "You are not logged in.
"
diff --git a/web/users_sqlite/WebServerSimple.gd b/web/users_sqlite/WebServerSimple.gd
new file mode 100644
index 0000000..9c7d7e9
--- /dev/null
+++ b/web/users_sqlite/WebServerSimple.gd
@@ -0,0 +1,16 @@
+extends WebServerSimple
+
+
+# Declare member variables here. Examples:
+# var a: int = 2
+# var b: String = "text"
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ start()
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+#func _process(delta: float) -> void:
+# pass
diff --git a/web/users_sqlite/default_env.tres b/web/users_sqlite/default_env.tres
new file mode 100644
index 0000000..4f08e8f
--- /dev/null
+++ b/web/users_sqlite/default_env.tres
@@ -0,0 +1,7 @@
+[gd_resource type="Environment3D" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )
diff --git a/web/users_sqlite/icon.png b/web/users_sqlite/icon.png
new file mode 100644
index 0000000..87f1f75
Binary files /dev/null and b/web/users_sqlite/icon.png differ
diff --git a/web/users_sqlite/icon.png.import b/web/users_sqlite/icon.png.import
new file mode 100644
index 0000000..a4c02e6
--- /dev/null
+++ b/web/users_sqlite/icon.png.import
@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.png"
+dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0
diff --git a/web/users_sqlite/project.pandemonium b/web/users_sqlite/project.pandemonium
new file mode 100644
index 0000000..6ae35c5
--- /dev/null
+++ b/web/users_sqlite/project.pandemonium
@@ -0,0 +1,25 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=4
+
+[application]
+
+config/name="Users Static"
+run/main_scene="res://Main.tscn"
+config/icon="res://icon.png"
+
+[physics]
+
+common/enable_pause_aware_picking=true
+
+[rendering]
+
+vram_compression/import_etc=true
+vram_compression/import_etc2=false
+environment/default_environment="res://default_env.tres"