Skip to content

Linux + SQLite

Run oidc-exchange on one Linux host with SQLite for persistent storage. This deployment uses one binary, a configuration file, and a database file. It needs no external database service.

Optionally, store refresh token sessions in Lightning Memory-Mapped Database (LMDB). This adds a local session store without a network service.

A runnable example is in examples/linux-sqlite/.

  • You want a single server with no external database dependencies.
  • You expect low to moderate traffic, such as hundreds of requests per second.
  • You want to keep persistent data in one directory for backups.
  • You want the option to store sessions in LMDB on the same server.
┌──────────────┐
│ nginx │
│ (TLS term) │
└──────┬───────┘
│
┌──────┴───────┐
│oidc-exchange │
└──┬───────┬───┘
│ │
┌────────┴──┐ ┌─┴──────────┐
│ SQLite │ │ LMDB │
│ (users) │ │ (sessions) │
└────────────┘ └─────────────┘
optional

Without LMDB, SQLite handles both users and sessions.

  • A Linux server with oidc-exchange binary (see build instructions).
  • A writable directory for the SQLite database file.
  • (Optional) A writable directory for the LMDB environment.
Terminal window
sudo mkdir -p /var/lib/oidc-exchange/data
sudo mkdir -p /etc/oidc-exchange
sudo chown -R oidc-exchange:oidc-exchange /var/lib/oidc-exchange

If using LMDB for sessions:

Terminal window
sudo mkdir -p /var/lib/oidc-exchange/lmdb
sudo chown oidc-exchange:oidc-exchange /var/lib/oidc-exchange/lmdb
Terminal window
openssl genpkey -algorithm ed25519 -out /etc/oidc-exchange/signing-key.pem
chmod 600 /etc/oidc-exchange/signing-key.pem

Create /etc/oidc-exchange/config/production.toml:

[server]
host = "127.0.0.1"
port = 8080
issuer = "https://auth.example.com"
[key_manager]
adapter = "local"
[key_manager.local]
private_key_path = "/etc/oidc-exchange/signing-key.pem"
algorithm = "EdDSA"
kid = "prod-1"
[repository]
adapter = "sqlite"
[repository.sqlite]
path = "/var/lib/oidc-exchange/data/oidc-exchange.db"
[audit]
adapter = "stdout"
durability = "observe"
[telemetry]
enabled = true
exporter = "stdout"
[providers.google]
adapter = "oidc"
issuer = "https://accounts.google.com"
client_id = "${GOOGLE_CLIENT_ID}"
client_secret = "${GOOGLE_CLIENT_SECRET}"
scopes = ["openid", "email", "profile"]
# Origins Google's discovery document may name beyond the issuer's origin:
endpoint_origins = ["https://oauth2.googleapis.com", "https://www.googleapis.com"]

endpoint_origins pins which origins a provider’s discovery document is allowed to name; each entry must be a bare https://host[:port], and an unpinned origin logs a warning when discovered (see Identity Providers).

SQLite enables write-ahead logging (WAL) and foreign key checks automatically. The database file and tables are created on first startup.

LMDB is a local key-value database designed for frequent reads. oidc-exchange looks up a session on each token refresh. LMDB reads session data through files mapped into memory.

[server]
host = "127.0.0.1"
port = 8080
issuer = "https://auth.example.com"
[key_manager]
adapter = "local"
[key_manager.local]
private_key_path = "/etc/oidc-exchange/signing-key.pem"
algorithm = "EdDSA"
kid = "prod-1"
# Users in SQLite
[repository]
adapter = "sqlite"
[repository.sqlite]
path = "/var/lib/oidc-exchange/data/oidc-exchange.db"
# Sessions in LMDB
[session_repository]
adapter = "lmdb"
[session_repository.lmdb]
path = "/var/lib/oidc-exchange/lmdb"
max_size_mb = 256
[audit]
adapter = "stdout"
durability = "observe"
[telemetry]
enabled = true
exporter = "stdout"
[providers.google]
adapter = "oidc"
issuer = "https://accounts.google.com"
client_id = "${GOOGLE_CLIENT_ID}"
client_secret = "${GOOGLE_CLIENT_SECRET}"
scopes = ["openid", "email", "profile"]

The max_size_mb setting limits the LMDB memory map size. At roughly 500 bytes per session, 256 MB holds about 500,000 sessions. LMDB reserves this space and allocates it as needed.

Terminal window
cat > /etc/oidc-exchange/env <<'EOF'
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
EOF
chmod 600 /etc/oidc-exchange/env
/etc/systemd/system/oidc-exchange.service
[Unit]
Description=oidc-exchange token service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=oidc-exchange
Group=oidc-exchange
ExecStart=/usr/local/bin/oidc-exchange
WorkingDirectory=/etc/oidc-exchange
Restart=on-failure
RestartSec=5
EnvironmentFile=/etc/oidc-exchange/env
Environment=OIDC_EXCHANGE_ENV=production
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/etc/oidc-exchange
ReadWritePaths=/var/lib/oidc-exchange
PrivateTmp=true
[Install]
WantedBy=multi-user.target

Set ReadWritePaths=/var/lib/oidc-exchange to give the service write access to the SQLite and LMDB data directories.

Terminal window
sudo cp target/release/oidc-exchange /usr/local/bin/
sudo useradd --system --no-create-home oidc-exchange
sudo systemctl daemon-reload
sudo systemctl enable --now oidc-exchange

See the generic Linux server guide for the nginx configuration.

The service stores its database files in /var/lib/oidc-exchange/. Back up SQLite with:

Terminal window
# SQLite: use the .backup command for a consistent snapshot
sqlite3 /var/lib/oidc-exchange/data/oidc-exchange.db ".backup /tmp/oidc-exchange-backup.db"

To back up LMDB, stop the service and copy /var/lib/oidc-exchange/lmdb/.

LMDB sessions expire. Losing session data requires users to sign in again.

  • Single-server only: SQLite and LMDB do not support concurrent access from multiple processes on different hosts. For multi-server deployments, use PostgreSQL or DynamoDB.
  • Write throughput: SQLite with WAL handles hundreds of writes per second. If you need thousands, consider PostgreSQL.
  • Scaling across hosts: Each host would have its own SQLite or LMDB database. Use a shared database to run instances across hosts.