();
foreach (var client in config.Clients)
{
+ if (await openIddictManager.FindByClientIdAsync(client.Id) is not null)
+ {
+ continue;
+ }
+
var clientApp = new OpenIddictApplicationDescriptor()
{
ClientId = client.Id,
From c6d23a2763c35fb5d3ea6ffef68e634cb96d5792 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Feb 2026 23:05:14 +0000
Subject: [PATCH 3/4] docs: Document SQLite persistence configuration and
limitations
Co-authored-by: jthomperoo <6690498+jthomperoo@users.noreply.github.com>
---
ARCHITECTURE.md | 9 ++-
.../docs/configuration.md | 76 +++++++++++++++++++
.../docs/runtime-management.md | 2 +-
3 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 5694956..06ea13f 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -12,10 +12,11 @@ The documentation uses [MkDocs](https://www.mkdocs.org/) and [Material for
MkDocs](https://squidfunk.github.io/mkdocs-material/). This documentation is both provided on readthedocs and built
in to the application itself.
-The application reads the configuration on start up and then populates an in-memory database with users and OpenID
-connect clients. Additionally, users and clients can be created at runtime through the web interface at `/users` and
-`/clients` respectively. Note that there is no persistence between application restarts, as the in-memory database is
-wiped and a new one is used - any users or clients created at runtime will be lost upon restart.
+The application reads the configuration on start up and then populates the database with users and OpenID connect
+clients. By default, an in-memory database is used and all data is lost on restart — any users or clients created at
+runtime through the web interface will not survive a restart. Optionally, a SQLite database file can be configured to
+persist data between restarts; see the [Database configuration](DevOidcToolkit.Documentation/docs/configuration.md)
+for details.
The frontend is styled using basic styling, using the [Sakura CSS library](https://github.com/oxalorg/sakura).
diff --git a/DevOidcToolkit.Documentation/docs/configuration.md b/DevOidcToolkit.Documentation/docs/configuration.md
index d996995..cb06473 100644
--- a/DevOidcToolkit.Documentation/docs/configuration.md
+++ b/DevOidcToolkit.Documentation/docs/configuration.md
@@ -59,6 +59,12 @@ This is a list of all of the environment variables that can be used to configure
| https://fake-issuer.example.com |
None (derived from request URL) |
+
+ | DevOidcToolkit__Database__SqliteFile |
+ The path to the SQLite database file. When set, data is persisted to this file and survives restarts. When not set, an in-memory database is used and all data is lost on restart. |
+ /data/dev-oidc-toolkit.db |
+ None (in-memory) |
+
| DevOidcToolkit__Logging__MinimumLevel |
The minimum log level, possible values are Trace, Debug, Information, Warning, Error, Critical. |
@@ -204,6 +210,13 @@ details](#example-json-configuration)).
https://fake-issuer.example.com |
None |
+
+ | Database |
+ object |
+ The database configuration, see Database for more information. |
+ See Database for more information. |
+ None (in-memory) |
+
| Https |
object |
@@ -352,6 +365,38 @@ details](#example-json-configuration)).
+#### Database
+
+The database configuration controls how data is stored. By default, an in-memory database is used and all data
+(including users and clients created at runtime) is lost when the application stops. Set `SqliteFile` to a file path to
+use a SQLite database instead, which persists data between restarts.
+
+!!! note "Limitations"
+ The SQLite database schema is created automatically on first run using `EnsureCreated`. There are no migrations
+ supported — if the schema changes in a future version of dev-oidc-toolkit you may need to delete and recreate the
+ database file.
+
+
+
+
+ | Property |
+ Type |
+ Description |
+ Example |
+ Default Value |
+
+
+
+
+ | SqliteFile |
+ string |
+ Path to the SQLite database file. When set, all data is persisted to this file. When omitted, an in-memory database is used and data is lost on restart. |
+ /data/dev-oidc-toolkit.db |
+ None (in-memory) |
+
+
+
+
#### Users
@@ -435,6 +480,8 @@ details](#example-json-configuration)).
### Example JSON configuration
+In-memory database (default, no persistence):
+
```json
{
"DevOidcToolkit": {
@@ -459,3 +506,32 @@ details](#example-json-configuration)).
}
}
```
+
+SQLite database (data persists across restarts):
+
+```json
+{
+ "DevOidcToolkit": {
+ "Port": 8080,
+ "Database": {
+ "SqliteFile": "/data/dev-oidc-toolkit.db"
+ },
+ "Users": [
+ {
+ "Email": "sudo@localhost",
+ "FirstName": "Test",
+ "LastName": "User"
+ }
+ ],
+ "Clients": [
+ {
+ "Id": "test",
+ "Secret": "ThisIsNotARealSecret",
+ "RedirectUris": [
+ "http://localhost:3000/callback"
+ ]
+ }
+ ]
+ }
+}
+```
diff --git a/DevOidcToolkit.Documentation/docs/runtime-management.md b/DevOidcToolkit.Documentation/docs/runtime-management.md
index 0a297f7..d08ed2a 100644
--- a/DevOidcToolkit.Documentation/docs/runtime-management.md
+++ b/DevOidcToolkit.Documentation/docs/runtime-management.md
@@ -56,6 +56,6 @@ URIs are validated on submission to ensure they are properly formatted.
## Important Notes
-- **No Persistence**: Users and clients created at runtime exist only in the in-memory database. They will be lost when the application restarts.
+- **Persistence**: By default, users and clients created at runtime exist only in the in-memory database and will be lost when the application restarts. To persist runtime changes, configure a [SQLite database](configuration.md#database).
- **Configuration + Runtime**: You can use both configuration-based users/clients and runtime-created ones simultaneously.
- **Role Management**: Roles created at runtime persist for the lifetime of the application and can be assigned to multiple users.
From ef9fc3804113f874f44b040d236dbe8d019c802f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 24 Feb 2026 23:08:07 +0000
Subject: [PATCH 4/4] docs: Update CHANGELOG for SQLite persistence feature
Co-authored-by: jthomperoo <6690498+jthomperoo@users.noreply.github.com>
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3aa0dd0..931928c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+- Add optional SQLite persistence via `Database.SqliteFile` config option; defaults to in-memory when not set (see [#20](https://github.com/BusinessSimulations/dev-oidc-toolkit/issues/20))
## [0.5.0]
- Add configurable user roles through `DevOidcToolkit__Users__INDEX__Roles__INDEX` (see [#17](https://github.com/BusinessSimulations/dev-oidc-toolkit/pull/17))
- Add runtime user registration at `/users` page (see [#15](https://github.com/BusinessSimulations/dev-oidc-toolkit/issues/15))