From ba371e37bd5650e8a0397b5fc3973a16cdd3aea2 Mon Sep 17 00:00:00 2001
From: O M
- Every /v1 route except GET /v1/health checks
- OM_API_SECRET. Send it as Authorization: Bearer … or
- X-API-Key. The console HTML does not. Treat the API as an internal service.
- Details are on Security.
+ Machine clients send OM_API_SECRET as Authorization: Bearer … or
+ X-API-Key. A console session cookie is the other accepted credential.
+ GET /v1/health, GET /v1/auth/session, and
+ POST /v1/auth/logout are open. Admin management requires the session.
+ Treat the API as an internal service. Details are on Security
+ and Console.
POST /v1/ingest is the HTTP equivalent of an upsert.
om scan does not call the API. That split is why scans work when you only start
- the Postgres container, and why the console API key is irrelevant to the CLI.
+ the Postgres container, and why a console session is irrelevant to the CLI.
OM_PUBLIC_URLhttp://localhost:8080OM_API_PORTOM_API_SECRETchange-me-in-production/v1 route except GET /v1/health. See Security./v1 routes. The console uses a session instead. See Security.OM_GOOGLE_CLIENT_ID / OM_GOOGLE_CLIENT_SECRET{OM_PUBLIC_URL}/auth/google/callback.OM_GITHUB_CLIENT_ID / OM_GITHUB_CLIENT_SECRET{OM_PUBLIC_URL}/auth/github/callback.
+ The console signs people in with Google or GitHub. There is no password and no API-key field.
+ Configure OM_GOOGLE_CLIENT_ID and OM_GOOGLE_CLIENT_SECRET, or the
+ OM_GITHUB_* pair, and register
+ {OM_PUBLIC_URL}/auth/google/callback or
+ {OM_PUBLIC_URL}/auth/github/callback on that app.
+ See Configuration.
+
- The Run CSPM rules button calls POST /v1/rules/run. That route
- requires the API secret. Enter it in the API key field and choose
- Save API key. The page stores it in localStorage.om_api_key and
- sends X-API-Key on /v1 calls. The key is not written into the graph.
- Clearing the field and saving removes it. The HTML page loads without a key. Stats, findings,
- and the graph need the secret. GET /v1/health does not.
+ On an install with no admin, the API log prints a one-time setup link. Open that link and
+ finish sign-in. That account becomes the admin. Restarting the API before anyone uses the
+ link replaces it; use the latest line. An admin can create another setup link from the
+ Admins panel. The link expires after 72 hours. Every signed-in account is an
+ admin, and the last admin cannot be removed.
- Use the value of OM_API_SECRET from the environment the API process actually
- has. Running om rules run on the CLI does the same work without the browser key,
- because the CLI uses Postgres directly.
+ The browser keeps an httpOnly session cookie for 7 days. Collectors and curl
+ still send OM_API_SECRET. That secret cannot create or remove admins.
+
+ The Run CSPM rules button calls POST /v1/rules/run with the
+ session cookie. Running om rules run on the CLI does the same work without a
+ browser session, because the CLI uses Postgres directly.
opensourceom
unless you override POSTGRES_USER, POSTGRES_PASSWORD, and
POSTGRES_DB. The API listens on OM_API_PORT (default 8080) and
- receives OM_API_SECRET from .env. A volume named
+ receives OM_API_SECRET and the optional Google or GitHub client credentials from
+ .env. With no admin yet, docker compose logs api prints a one-time
+ setup link after you configure a provider. A volume named
postgres-data keeps the database across restarts.
diff --git a/src/pages/docs/kubernetes.astro b/src/pages/docs/kubernetes.astro
index 2a6f1e1..0558217 100644
--- a/src/pages/docs/kubernetes.astro
+++ b/src/pages/docs/kubernetes.astro
@@ -82,6 +82,21 @@ helm install om deploy/helm/opensourceom \\
OM_API_SECRET.api.publicURLOM_PUBLIC_URL. Set this to the browser origin before console login works.api.google.clientId / api.google.clientSecretapi.github.clientId / api.github.clientSecretpostgres.enabledtrue
Keep the Service off the public internet, or put your own gateway in front of it. See
- Security for how OM_API_SECRET applies.
+ Security for the API secret and console login. Set
+ api.publicURL to that gateway’s origin when you enable Google or GitHub.
- The console button does the same POST. See Console for the - browser API key. + The console button does the same POST with the signed-in session. See + Console.
@@ -17,15 +17,18 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OM_API_SECRET defaults to change-me-in-production when the variable
- is unset or empty. Every /v1 route except GET /v1/health requires
- Authorization: Bearer <secret> or X-API-Key: <secret>.
- That includes graph reads, findings, the rules list, blast radius, ingest, rules run, and
- Slack export. A missing or wrong secret is 401.
+ is unset or empty. Graph and ingest routes require
+ Authorization: Bearer <secret>, X-API-Key: <secret>, or
+ a console session cookie. That includes graph reads, findings, the rules list, blast radius,
+ ingest, rules run, and Slack export. A missing or wrong credential is 401.
- GET /v1/health does not check the secret, so probes can call it. The console
- HTML at / and /ui/ is also unauthenticated. The page sends the key
- from local storage on API calls. See Console.
+ GET /v1/health, GET /v1/auth/session, and
+ POST /v1/auth/logout do not check the secret.
+ GET /v1/admins, POST /v1/admins/invites, and
+ DELETE /v1/admins/{id} require a console session. The API secret cannot mint
+ admins. The console HTML at /, /login, and /setup/
+ loads without a session so the sign-in page can render. See Console.
Change the secret before anyone else can reach the port. Helm refuses to install until @@ -33,8 +36,22 @@ import DocsLayout from '@/layouts/DocsLayout.astro'; shell as a user with database credentials can scan and export without it.
- The secret is one shared key, not a user login. Do not publish the Service to the internet. - Put it on a private network or behind a gateway you operate. + The secret is the machine credential. People use Google or GitHub. Do not publish the + Service to the internet. Put it on a private network or behind a gateway you operate. +
+ +
+ Google and GitHub are the only human logins. Every account is an admin. The first account
+ is whoever finishes the setup link printed in the API logs, so do not leave that link where
+ other people can open it. Later admins are whoever finishes a link an existing admin creates.
+ Sessions are httpOnly cookies. The cookie is marked Secure when
+ OM_PUBLIC_URL uses https.
+
+ OAuth client secrets are deployment secrets, next to OM_API_SECRET. The API
+ must be able to reach Google or GitHub over HTTPS. An air-gapped console cannot sign anyone
+ in with this build.
The graph view loads vis-network from /ui/vis-network.min.js on the API. It is
- not loaded from a CDN. The API key saved in the console stays in browser local storage and
- is not written into the graph.
+ not loaded from a CDN. The session cookie is httpOnly, so page script cannot read it.
OM_GOOGLE_CLIENT_ID / OM_GOOGLE_CLIENT_SECRET{OM_PUBLIC_URL}/auth/google/callback.{'{OM_PUBLIC_URL}'}/auth/google/callback.OM_GITHUB_CLIENT_ID / OM_GITHUB_CLIENT_SECRET{OM_PUBLIC_URL}/auth/github/callback.{'{OM_PUBLIC_URL}'}/auth/github/callback.OM_GOOGLE_CLIENT_ID and OM_GOOGLE_CLIENT_SECRET, or the
OM_GITHUB_* pair, and register
- {OM_PUBLIC_URL}/auth/google/callback or
- {OM_PUBLIC_URL}/auth/github/callback on that app.
+ {'{OM_PUBLIC_URL}'}/auth/google/callback or
+ {'{OM_PUBLIC_URL}'}/auth/github/callback on that app.
See Configuration.
diff --git a/src/pages/docs/security.astro b/src/pages/docs/security.astro
index 03371fb..6b57040 100644
--- a/src/pages/docs/security.astro
+++ b/src/pages/docs/security.astro
@@ -26,7 +26,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
GET /v1/health, GET /v1/auth/session, and
POST /v1/auth/logout do not check the secret.
GET /v1/admins, POST /v1/admins/invites, and
- DELETE /v1/admins/{id} require a console session. The API secret cannot mint
+ DELETE /v1/admins/{'{id}'} require a console session. The API secret cannot mint
admins. The console HTML at /, /login, and /setup/
loads without a session so the sign-in page can render. See Console.
- Machine clients send OM_API_SECRET as Authorization: Bearer … or
- X-API-Key. A console session cookie is the other accepted credential.
+ Machine clients send that admin's personal API token as Authorization: Bearer … or
+ X-API-Key. A console session cookie is the other accepted credential. The examples
+ below use $OM_API_TOKEN for the value the console showed once.
GET /v1/health, GET /v1/auth/session, and
POST /v1/auth/logout are open. Admin management requires the session.
Treat the API as an internal service. Details are on Security
@@ -35,7 +36,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
GET /v1/health{`{"status":"ok","service":"opensourceom-api"}`}. Does not check the API secret. Helm probes this path.{`{"status":"ok","service":"opensourceom-api"}`}. Does not check a token. Helm probes this path.GET /v1/graph/stats{`curl -s http://localhost:8080/v1/health
-curl -s -H "Authorization: Bearer $OM_API_SECRET" \\
+curl -s -H "Authorization: Bearer $OM_API_TOKEN" \\
http://localhost:8080/v1/graph/stats
-curl -s -H "Authorization: Bearer $OM_API_SECRET" \\
+curl -s -H "Authorization: Bearer $OM_API_TOKEN" \\
-H 'Content-Type: application/json' \\
-d '{"nodes":[],"edges":[]}' \\
http://localhost:8080/v1/ingest`}
@@ -153,9 +154,9 @@ curl -s -H "Authorization: Bearer $OM_API_SECRET" \\
GET /v1/identity/blast-radius returns the identity, reachable
(at most 200 nodes), max_depth (6), and summary. Pass
identity_id or name. A name that matches no identity is 400.
- This route requires the API secret, like the other /v1 reads.
+ This route requires a personal API token or a console session, like the other /v1 reads.
- {`curl -s -X POST -H "Authorization: Bearer $OM_API_SECRET" \\
+ {`curl -s -X POST -H "Authorization: Bearer $OM_API_TOKEN" \\
-H 'Content-Type: application/json' \\
-d '{"webhook":"https://hooks.slack.com/services/..."}' \\
http://localhost:8080/v1/export/slack`}
diff --git a/src/pages/docs/cli.astro b/src/pages/docs/cli.astro
index 5f913f9..92a4675 100644
--- a/src/pages/docs/cli.astro
+++ b/src/pages/docs/cli.astro
@@ -11,7 +11,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OpenSourceOM CLI
The om binary talks to Postgres directly. Scans, rules, queries, and exports do
- not go through the HTTP API, so they do not send OM_API_SECRET. Build it from
+ not go through the HTTP API, so they do not send a personal API token. Build it from
the core repo with go build -o om ./cmd/om, or use a release archive.
diff --git a/src/pages/docs/configuration.astro b/src/pages/docs/configuration.astro
index b15542e..3d924a7 100644
--- a/src/pages/docs/configuration.astro
+++ b/src/pages/docs/configuration.astro
@@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
Configure OpenSourceOM
@@ -45,7 +45,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OM_PUBLIC_URL
http://localhost:8080
- Browser origin for OAuth callbacks and setup links. No trailing path.
+ Browser origin for OAuth callbacks and invite links. No trailing path.
OM_API_PORT
@@ -53,9 +53,14 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
om serve
- OM_API_SECRET
- change-me-in-production
- Machine credential for /v1 routes. The console uses a session instead. See Security.
+ OM_SMTP_HOST / OM_SMTP_PORT / OM_SMTP_FROM
+ empty / 587 / empty
+ Required to email an admin invite. The message contains the link, not a token.
+
+
+ OM_SMTP_USERNAME / OM_SMTP_PASSWORD
+ empty
+ Optional SMTP authentication. Set both when the server requires a login.
OM_GOOGLE_CLIENT_ID / OM_GOOGLE_CLIENT_SECRET
diff --git a/src/pages/docs/console.astro b/src/pages/docs/console.astro
index 1324484..dedfad5 100644
--- a/src/pages/docs/console.astro
+++ b/src/pages/docs/console.astro
@@ -42,15 +42,17 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
See Configuration.
- On an install with no admin, the API log prints a one-time setup link. Open that link and
- finish sign-in. That account becomes the admin. Restarting the API before anyone uses the
- link replaces it; use the latest line. An admin can create another setup link from the
- Admins panel. The link expires after 72 hours. Every signed-in account is an
- admin, and the last admin cannot be removed.
+ The first successful Google or GitHub sign-in becomes the admin. Keep the API port private
+ until that happens. An admin invites the next person by email from the
+ Admins panel. Sending an invite needs SMTP. The invited person opens the
+ link and signs in with the Google or GitHub account for that address. The invite expires
+ after 72 hours. Every signed-in account is an admin, and the last admin cannot be removed.
- The browser keeps an httpOnly session cookie for 7 days. Collectors and curl
- still send OM_API_SECRET. That secret cannot create or remove admins.
+ The browser keeps an httpOnly session cookie for 7 days. Creating an admin also creates a
+ personal API token. The console shows it once. Scripts send that token as
+ Authorization: Bearer or X-API-Key. The token cannot invite or
+ remove admins. Rotate it from the same panel when you need a new one.
Run CSPM rules from the browser
diff --git a/src/pages/docs/docker.astro b/src/pages/docs/docker.astro
index 3a7638d..9c9c165 100644
--- a/src/pages/docs/docker.astro
+++ b/src/pages/docs/docker.astro
@@ -21,9 +21,9 @@ docker compose ps`}
Postgres listens on host port 5432 with user, password, and database opensourceom
unless you override POSTGRES_USER, POSTGRES_PASSWORD, and
POSTGRES_DB. The API listens on OM_API_PORT (default 8080) and
- receives OM_API_SECRET and the optional Google or GitHub client credentials from
- .env. With no admin yet, docker compose logs api prints a one-time
- setup link after you configure a provider. A volume named
+ receives the optional Google or GitHub client credentials and SMTP settings from
+ .env. The first Google or GitHub sign-in becomes the admin. Keep port 8080
+ private until that happens. A volume named
postgres-data keeps the database across restarts.
diff --git a/src/pages/docs/exports.astro b/src/pages/docs/exports.astro
index 73d8d0c..a6a1a4d 100644
--- a/src/pages/docs/exports.astro
+++ b/src/pages/docs/exports.astro
@@ -67,7 +67,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
The API posts the same digest:
- {`curl -s -X POST -H "Authorization: Bearer $OM_API_SECRET" \\
+ {`curl -s -X POST -H "Authorization: Bearer $OM_API_TOKEN" \\
-H 'Content-Type: application/json' \\
-d '{"webhook":"https://hooks.slack.com/services/..."}' \\
http://localhost:8080/v1/export/slack`}
diff --git a/src/pages/docs/index.astro b/src/pages/docs/index.astro
index 1c47e8f..a737507 100644
--- a/src/pages/docs/index.astro
+++ b/src/pages/docs/index.astro
@@ -78,7 +78,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
Architecture — components and data flow
Docker Compose — local Postgres and API
Kubernetes — Helm chart
- Security — API secret, read-only collectors, vulnerability reports
+ Security — personal API tokens, read-only collectors, vulnerability reports
Open source scope — what stays in Core versus planned commercial work
diff --git a/src/pages/docs/kubernetes.astro b/src/pages/docs/kubernetes.astro
index 0558217..5e1aa22 100644
--- a/src/pages/docs/kubernetes.astro
+++ b/src/pages/docs/kubernetes.astro
@@ -23,14 +23,13 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
Install
- api.secret and postgres.password are required. The image repository
+ postgres.password is required. The image repository
defaults to ghcr.io/opensourceom/core. An empty image.tag falls
back to the chart appVersion (0.3.0). Set the tag when you are not
running that release.
{`docker build -t ghcr.io/opensourceom/core:0.3.0 .
helm install om deploy/helm/opensourceom \\
- --set api.secret='change-me' \\
--set postgres.password='change-me' \\
--set image.tag=0.3.0`}
@@ -78,9 +77,9 @@ helm install om deploy/helm/opensourceom \\
Written to OM_ENV.
- api.secret
- empty, required
- OM_API_SECRET.
+ api.smtp.host / api.smtp.port / api.smtp.from
+ empty / 587 / empty
+ SMTP for admin invites. Setting the host requires from. A password stays in the chart Secret.
api.publicURL
@@ -159,7 +158,7 @@ helm install om deploy/helm/opensourceom \\
Keep the Service off the public internet, or put your own gateway in front of it. See
- Security for the API secret and console login. Set
+ Security for personal API tokens and console login. Set
api.publicURL to that gateway’s origin when you enable Google or GitHub.
diff --git a/src/pages/docs/rules.astro b/src/pages/docs/rules.astro
index dbdd870..0145b51 100644
--- a/src/pages/docs/rules.astro
+++ b/src/pages/docs/rules.astro
@@ -94,10 +94,11 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
HTTP
- {`curl -s http://localhost:8080/v1/rules
-curl -s -X POST -H "Authorization: Bearer $OM_API_SECRET" \\
+ {`curl -s -H "Authorization: Bearer $OM_API_TOKEN" \\
+ http://localhost:8080/v1/rules
+curl -s -X POST -H "Authorization: Bearer $OM_API_TOKEN" \\
http://localhost:8080/v1/rules/run
-curl -s -X POST -H "Authorization: Bearer $OM_API_SECRET" \\
+curl -s -X POST -H "Authorization: Bearer $OM_API_TOKEN" \\
'http://localhost:8080/v1/rules/run?id=cspm-internet-workload'`}
The console button does the same POST with the signed-in session. See
diff --git a/src/pages/docs/security.astro b/src/pages/docs/security.astro
index 6b57040..bfdbe48 100644
--- a/src/pages/docs/security.astro
+++ b/src/pages/docs/security.astro
@@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OpenSourceOM security model
@@ -14,44 +14,47 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
IAM relationships, and findings. Protect Postgres and the API the way you protect that data.
- API secret
+ Personal API tokens
- OM_API_SECRET defaults to change-me-in-production when the variable
- is unset or empty. Graph and ingest routes require
- Authorization: Bearer <secret>, X-API-Key: <secret>, or
+ Each admin has a personal API token. The console shows the raw value once, after the account
+ is created or after a rotation. Graph and ingest routes require
+ Authorization: Bearer <token>, X-API-Key: <token>, or
a console session cookie. That includes graph reads, findings, the rules list, blast radius,
- ingest, rules run, and Slack export. A missing or wrong credential is 401.
+ ingest, rules run, and Slack export. A missing or wrong credential is 401. There is no shared
+ secret and no open mode.
GET /v1/health, GET /v1/auth/session, and
- POST /v1/auth/logout do not check the secret.
- GET /v1/admins, POST /v1/admins/invites, and
- DELETE /v1/admins/{'{id}'} require a console session. The API secret cannot mint
- admins. The console HTML at /, /login, and /setup/
- loads without a session so the sign-in page can render. See Console.
+ POST /v1/auth/logout do not check a token.
+ GET /v1/admins, POST /v1/admins/invites,
+ POST /v1/admins/token, and
+ DELETE /v1/admins/{'{id}'} require a console session. A personal token cannot
+ mint or remove admins. The console HTML at /, /login, and
+ /invite/ loads without a session so the sign-in page can render. See
+ Console.
- Change the secret before anyone else can reach the port. Helm refuses to install until
- api.secret is set. The CLI never sends this header. Anyone who can open a local
- shell as a user with database credentials can scan and export without it.
+ Keep the API port private until the first admin exists. Whoever can open it first can become
+ that admin. The CLI never sends this header. Anyone who can open a local shell as a user
+ with database credentials can scan and export without a token.
- The secret is the machine credential. People use Google or GitHub. Do not publish the
- Service to the internet. Put it on a private network or behind a gateway you operate.
+ People use Google or GitHub. Scripts use a personal token. Do not publish the Service to
+ the internet. Put it on a private network or behind a gateway you operate.
Console admins
- Google and GitHub are the only human logins. Every account is an admin. The first account
- is whoever finishes the setup link printed in the API logs, so do not leave that link where
- other people can open it. Later admins are whoever finishes a link an existing admin creates.
+ Google and GitHub are the only human logins. Every account is an admin. The first successful
+ sign-in becomes the admin. Later admins open an email invite and sign in with the Google or
+ GitHub account for the invited address. A verified email from the provider must match.
Sessions are httpOnly cookies. The cookie is marked Secure when
OM_PUBLIC_URL uses https.
- OAuth client secrets are deployment secrets, next to OM_API_SECRET. The API
- must be able to reach Google or GitHub over HTTPS. An air-gapped console cannot sign anyone
- in with this build.
+ OAuth client secrets and the SMTP password are deployment secrets. The API must be able to
+ reach Google or GitHub over HTTPS, and your mail server when you invite another admin. An
+ air-gapped console cannot sign anyone in with this build.
Collectors
From 200459b4ea6b6fd92669cf5d9ef11c3476cd8af1 Mon Sep 17 00:00:00 2001
From: O M
Date: Wed, 14 Oct 2026 13:31:31 -0400
Subject: [PATCH 4/4] Document email and password console login, with optional
Google and GitHub.
Co-authored-by: Cursor
---
src/pages/docs/configuration.astro | 9 ++++++--
src/pages/docs/console.astro | 31 ++++++++++++++-----------
src/pages/docs/docker.astro | 7 +++---
src/pages/docs/kubernetes.astro | 9 ++++++--
src/pages/docs/security.astro | 37 ++++++++++++++++--------------
5 files changed, 56 insertions(+), 37 deletions(-)
diff --git a/src/pages/docs/configuration.astro b/src/pages/docs/configuration.astro
index 3d924a7..a872ace 100644
--- a/src/pages/docs/configuration.astro
+++ b/src/pages/docs/configuration.astro
@@ -45,17 +45,22 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OM_PUBLIC_URL
http://localhost:8080
- Browser origin for OAuth callbacks and invite links. No trailing path.
+ Browser origin for the console and optional OAuth callbacks. No trailing path.
OM_API_PORT
8080
om serve
+
+ OM_ADMIN_EMAIL
+ empty
+ When set, only this address can become the first admin.
+
OM_SMTP_HOST / OM_SMTP_PORT / OM_SMTP_FROM
empty / 587 / empty
- Required to email an admin invite. The message contains the link, not a token.
+ Optional. When set, adding an admin also emails the temporary password.
OM_SMTP_USERNAME / OM_SMTP_PASSWORD
diff --git a/src/pages/docs/console.astro b/src/pages/docs/console.astro
index dedfad5..6c16fbb 100644
--- a/src/pages/docs/console.astro
+++ b/src/pages/docs/console.astro
@@ -34,25 +34,30 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
Sign in
- The console signs people in with Google or GitHub. There is no password and no API-key field.
- Configure OM_GOOGLE_CLIENT_ID and OM_GOOGLE_CLIENT_SECRET, or the
- OM_GITHUB_* pair, and register
- {'{OM_PUBLIC_URL}'}/auth/google/callback or
- {'{OM_PUBLIC_URL}'}/auth/github/callback on that app.
- See Configuration.
+ The console signs people in with an email and password. There is no API-key field.
+ While no admin exists, the page is a setup form. Keep the API port private until you
+ finish it, or run om admin create --email you@example.com on the machine
+ first. Set OM_ADMIN_EMAIL when that first address should be fixed ahead of
+ time. See Configuration.
+
+
+ An admin adds the next person from the Admins panel. The temporary
+ password is shown once. If SMTP is configured, it is emailed too. That person chooses
+ their own password at the next sign-in. Every signed-in account is an admin, and the last
+ admin cannot be removed.
- The first successful Google or GitHub sign-in becomes the admin. Keep the API port private
- until that happens. An admin invites the next person by email from the
- Admins panel. Sending an invite needs SMTP. The invited person opens the
- link and signs in with the Google or GitHub account for that address. The invite expires
- after 72 hours. Every signed-in account is an admin, and the last admin cannot be removed.
+ Google and GitHub buttons appear only when that provider is configured. Register
+ {'{OM_PUBLIC_URL}'}/auth/google/callback or
+ {'{OM_PUBLIC_URL}'}/auth/github/callback. A verified email from the provider
+ must already be an admin. The Security panel turns on optional
+ authenticator-app two-factor authentication.
The browser keeps an httpOnly session cookie for 7 days. Creating an admin also creates a
personal API token. The console shows it once. Scripts send that token as
- Authorization: Bearer or X-API-Key. The token cannot invite or
- remove admins. Rotate it from the same panel when you need a new one.
+ Authorization: Bearer or X-API-Key. The token cannot add or
+ remove admins. Rotate it from the Admins panel when you need a new one.
Run CSPM rules from the browser
diff --git a/src/pages/docs/docker.astro b/src/pages/docs/docker.astro
index 9c9c165..9bf0586 100644
--- a/src/pages/docs/docker.astro
+++ b/src/pages/docs/docker.astro
@@ -21,9 +21,10 @@ docker compose ps`}
Postgres listens on host port 5432 with user, password, and database opensourceom
unless you override POSTGRES_USER, POSTGRES_PASSWORD, and
POSTGRES_DB. The API listens on OM_API_PORT (default 8080) and
- receives the optional Google or GitHub client credentials and SMTP settings from
- .env. The first Google or GitHub sign-in becomes the admin. Keep port 8080
- private until that happens. A volume named
+ receives OM_ADMIN_EMAIL and the optional Google, GitHub, and SMTP settings from
+ .env. Open the console and create the admin, or run
+ om admin create --email on the host first. Keep port 8080 private until an
+ admin exists. A volume named
postgres-data keeps the database across restarts.
diff --git a/src/pages/docs/kubernetes.astro b/src/pages/docs/kubernetes.astro
index 5e1aa22..93e46c0 100644
--- a/src/pages/docs/kubernetes.astro
+++ b/src/pages/docs/kubernetes.astro
@@ -79,12 +79,17 @@ helm install om deploy/helm/opensourceom \\
api.smtp.host / api.smtp.port / api.smtp.from
empty / 587 / empty
- SMTP for admin invites. Setting the host requires from. A password stays in the chart Secret.
+ Optional SMTP for temporary admin passwords. Setting the host requires from. A password stays in the chart Secret.
api.publicURL
empty
- OM_PUBLIC_URL. Set this to the browser origin before console login works.
+ OM_PUBLIC_URL. Set this to the browser origin before optional Google or GitHub login works.
+
+
+ api.adminEmail
+ empty
+ OM_ADMIN_EMAIL. When set, only this address can become the first admin.
api.google.clientId / api.google.clientSecret
diff --git a/src/pages/docs/security.astro b/src/pages/docs/security.astro
index bfdbe48..7e3bad1 100644
--- a/src/pages/docs/security.astro
+++ b/src/pages/docs/security.astro
@@ -6,7 +6,7 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
OpenSourceOM security model
@@ -24,37 +24,40 @@ import DocsLayout from '@/layouts/DocsLayout.astro';
secret and no open mode.
- GET /v1/health, GET /v1/auth/session, and
- POST /v1/auth/logout do not check a token.
- GET /v1/admins, POST /v1/admins/invites,
+ GET /v1/health, GET /v1/auth/session,
+ POST /v1/auth/logout, POST /v1/auth/setup,
+ POST /v1/auth/login, and POST /v1/auth/totp do not require a session.
+ GET /v1/admins, POST /v1/admins,
POST /v1/admins/token, and
DELETE /v1/admins/{'{id}'} require a console session. A personal token cannot
- mint or remove admins. The console HTML at /, /login, and
- /invite/ loads without a session so the sign-in page can render. See
- Console.
+ add or remove admins. The console HTML at / and /login loads
+ without a session so the sign-in page can render. See Console.
Keep the API port private until the first admin exists. Whoever can open it first can become
- that admin. The CLI never sends this header. Anyone who can open a local shell as a user
- with database credentials can scan and export without a token.
+ that admin. Create the account with om admin create before you publish the
+ port when you can. The CLI never sends this header. Anyone who can open a local shell as a
+ user with database credentials can scan and export without a token.
- People use Google or GitHub. Scripts use a personal token. Do not publish the Service to
- the internet. Put it on a private network or behind a gateway you operate.
+ People use an email and password. Scripts use a personal token. Do not publish the Service
+ to the internet. Put it on a private network or behind a gateway you operate.
Console admins
- Google and GitHub are the only human logins. Every account is an admin. The first successful
- sign-in becomes the admin. Later admins open an email invite and sign in with the Google or
- GitHub account for the invited address. A verified email from the provider must match.
+ People sign in with an email and password. Every account is an admin. The first account is
+ created from the setup form, or with om admin create before the port is
+ reachable. OM_ADMIN_EMAIL pins that first address when you set it. Later admins
+ receive a temporary password and choose their own at the next sign-in. Passwords are stored
+ as Argon2id hashes. Optional authenticator-app two-factor authentication is per admin.
Sessions are httpOnly cookies. The cookie is marked Secure when
OM_PUBLIC_URL uses https.
- OAuth client secrets and the SMTP password are deployment secrets. The API must be able to
- reach Google or GitHub over HTTPS, and your mail server when you invite another admin. An
- air-gapped console cannot sign anyone in with this build.
+ Google and GitHub are optional. A verified provider email must match an existing admin.
+ OAuth client secrets and the SMTP password are deployment secrets. Password login works
+ without them, including on an air-gapped console.
Collectors