Skip to main content

Authentication

SolidPing supports multiple authentication methods for user sign-in.

Email/Password​

The default authentication method. Users register with an email and password.

Restricting Registration​

Limit who can register by email pattern:

# Only allow company emails
SP_AUTH_REGISTRATION_EMAIL_PATTERN=@yourcompany\.com$

# Allow multiple domains
SP_AUTH_REGISTRATION_EMAIL_PATTERN=@(yourcompany|partner)\.com$

JWT Configuration​

# Set a strong secret for JWT signing (auto-generated if not set)
SP_AUTH_JWT_SECRET=your-secure-random-secret-at-least-32-chars
Production

Always set SP_AUTH_JWT_SECRET in production. If left unset, a random secret is generated on each restart, invalidating all existing sessions.

Password Hashing​

You can choose the password-hashing algorithm and its cost parameters. The defaults reproduce SolidPing's historical profile exactly, so upgrading the binary changes nothing until you reconfigure it.

Two algorithms ship:

  • argon2id (default) — memory-hard, the modern recommendation.
  • bcrypt — CPU-hard with a tiny constant memory footprint.
# Algorithm: "argon2id" (default) or "bcrypt"
SP_AUTH_PASSWORD_ALGORITHM=argon2id

# argon2id cost parameters
SP_AUTH_PASSWORD_ARGON2_MEMORY=65536 # KiB (default 65536 = 64 MiB)
SP_AUTH_PASSWORD_ARGON2_TIME=3 # iterations (default 3)
SP_AUTH_PASSWORD_ARGON2_THREADS=4 # parallelism (default 4)
SP_AUTH_PASSWORD_ARGON2_KEY_LENGTH=32 # output bytes (default 32)
SP_AUTH_PASSWORD_ARGON2_SALT_LENGTH=16 # salt bytes (default 16)

# bcrypt cost (only used when algorithm is "bcrypt")
SP_AUTH_PASSWORD_BCRYPT_COST=12 # range 10–31 (default 12)

# Re-hash existing passwords on next sign-in (default true)
SP_AUTH_PASSWORD_REHASH_ON_LOGIN=true

Editing from the dashboard​

Super-admins can change all of the above from Server Settings → Password Hashing (/orgs/{org}/server/hashing) instead of editing YAML or environment variables — pick the algorithm, set its cost parameters (recommended-profile preset buttons are provided for argon2id), and toggle re-hash on sign-in. Changes are validated immediately and take effect after a server restart, matching every other credential setting. A field left blank inherits the server default. Values configured via YAML/env are not shown in the form (only stored overrides appear). An out-of-range value is rejected at save, and a malformed stored value can never prevent startup — the policy re-resolve at boot is non-fatal and keeps the prior policy.

Transparent rehash-on-login. Stored hashes are self-identifying, so changing the algorithm or its cost parameters never invalidates existing passwords — old hashes keep verifying. On a user's next successful login, if their stored hash no longer matches the configured policy it is transparently re-hashed and persisted. There is no forced password reset and no background migration: users who never log in keep their old (still-valid) hash. This upgrade is gated by SP_AUTH_PASSWORD_REHASH_ON_LOGIN (default true); set it to false to leave existing hashes untouched so only new passwords (new users, password changes/resets) use the new profile.

Recommended profiles:

AlgorithmParametersMemory/loginNote
argon2id (default)m=65536, t=3, p=464 MiBcurrent; RFC 9106 memory-constrained profile
argon2id (lighter)m=19456, t=2, p=119 MiBOWASP; drops 4-thread CPU contention
argon2id (min)m=9216, t=4, p=19 MiBOWASP floor; still GPU-hostile
bcryptcost=12~4 KiBconstant; not memory-hard (weaker vs GPU/ASIC)
bcrypt and long passwords

The bcrypt algorithm pre-hashes passwords as base64(sha256(password)) before hashing. This sidesteps bcrypt's 72-byte input limit and its truncation at embedded NUL bytes — SolidPing's bcrypt hashes are produced and consumed only by SolidPing, so this is fully self-consistent.

Validation

The server validates the hashing policy at startup and fails fast on a misconfiguration (unknown algorithm; bcrypt cost outside 10–31; argon2id memory below the 8192 KiB floor). Values below the OWASP-recommended floors are allowed but warn-logged. There is never a silent fallback.

Changing an email address​

A user changes their sign-in email from Account > Profile: enter the new address and the current password. A super admin changes anyone's email from Server > Users, with the pencil icon on the user's row, without the user's password.

When an email changes:

  • the new address is marked unverified,
  • every other session of the user is signed out (the session that made the change stays signed in),
  • the previous address gets a notice, when email sending is configured,
  • auth.email_changed is recorded in the audit log of each organization the user belongs to.

An account without a password (it signs in through OAuth, OIDC, SAML or LDAP) cannot change its email in SolidPing. Change it at the identity provider, or ask a super admin. An address already used by another account is refused.

Over the API: PATCH /api/v1/auth/me with {"email": "...", "currentPassword": "..."}, or, as a super admin, PATCH /api/v1/system/users/{uid} with {"email": "..."}.

Email of the first admin​

On the first start of an empty database, SolidPing creates a super admin named admin@solidping.io. Set SP_ADMIN_EMAIL to seed it with your own address instead. It is only read when no organization exists yet. The password is still solidpass and must be changed at first login.

VariableDefaultDescription
SP_ADMIN_EMAILadmin@solidping.ioEmail of the super admin created on the first start

OAuth Providers​

SolidPing supports OAuth2 authentication with major identity providers. Set both _CLIENT_ID and _CLIENT_SECRET to enable each provider.

Google​

SP_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
SP_GOOGLE_CLIENT_SECRET=your-client-secret

Setup:

  1. Go to Google Cloud Console
  2. Create a new OAuth 2.0 Client ID
  3. Set authorized redirect URI to {SP_BASE_URL}/api/v1/auth/google/callback

GitHub​

SP_GITHUB_CLIENT_ID=your-github-client-id
SP_GITHUB_CLIENT_SECRET=your-github-client-secret

Setup:

  1. Go to GitHub Developer Settings
  2. Create a new OAuth App
  3. Set authorization callback URL to {SP_BASE_URL}/api/v1/auth/github/callback

GitLab​

SP_GITLAB_CLIENT_ID=your-gitlab-client-id
SP_GITLAB_CLIENT_SECRET=your-gitlab-client-secret

Setup:

  1. Go to GitLab → Preferences → Applications
  2. Create a new application
  3. Set redirect URI to {SP_BASE_URL}/api/v1/auth/gitlab/callback
  4. Select scopes: read_user, openid

Microsoft​

SP_MICROSOFT_CLIENT_ID=your-microsoft-client-id
SP_MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
SP_MICROSOFT_TENANT_ID=common

SP_MICROSOFT_TENANT_ID selects the Entra (Azure AD) tenant embedded in the authorize/token URLs (https://login.microsoftonline.com/{tenant}/oauth2/v2.0/...). Accepted values: your directory (tenant) GUID, a verified domain (e.g. contoso.onmicrosoft.com), or one of common / organizations / consumers. Leave it unset (or empty) to default to common (multi-tenant). Set it to your tenant for a single-tenant app registration, which rejects common sign-ins. This is also settable from Server Settings → Authentication and takes effect after a server restart.

Setup:

  1. Go to Azure App Registrations
  2. Register a new application
  3. Add redirect URI: {SP_BASE_URL}/api/v1/auth/microsoft/callback
  4. Create a client secret under "Certificates & secrets"
  5. For a single-tenant app, set SP_MICROSOFT_TENANT_ID to your directory (tenant) ID

Slack​

"Sign in with Slack" reuses the same Slack app you configure for notifications.

SP_SLACK_CLIENT_ID=1234567890.1234567890123
SP_SLACK_CLIENT_SECRET=your-client-secret

Setup:

  1. In your Slack app, enable OpenID Connect / "Sign in with Slack"
  2. Add redirect URL: {SP_BASE_URL}/api/v1/auth/slack/callback

Workspace members join their organization automatically​

An organization created from a Slack workspace stays linked to that workspace. Slack only completes the OAuth exchange for a member of the workspace, so SolidPing treats a successful "Sign in with Slack" (or app install) as proof of membership: the user joins the linked organization as a regular user and lands straight in the dashboard, without an admin approving a request first.

The link is matched on the workspace ID Slack returns — never on a workspace name or on the organization named in the login URL — so members of one workspace can never reach another workspace's organization. Everything else still applies: an organization at its member limit, or one whose workspace link was removed, falls back to the normal membership-request flow, and the first person in an empty organization still becomes its admin.

Single- and multi-channel guests of the workspace are admitted as well, as Slack does not expose guest status during sign-in.

Turning it off​

Auto-join can be disabled per organization with the registration.slack_workspace_auto_join parameter. When it is false, workspace members need an invitation, a matching registration.email_pattern, or an approved membership request, exactly as before.

There is no API or dashboard control for this parameter yet — a settings-UI toggle is a follow-up. Today it is written directly in the database, in the organization-scoped parameters table (organization_uid = the organization's uid, key = registration.slack_workspace_auto_join, value = the JSON object {"value": false}):

-- PostgreSQL; on SQLite replace gen_random_uuid() with any unique UID string.
INSERT INTO parameters (uid, organization_uid, key, value)
VALUES (
gen_random_uuid(),
(SELECT uid FROM organizations WHERE slug = 'your-org'),
'registration.slack_workspace_auto_join',
'{"value": false}'
);

The parameter is read on every Slack sign-in, so the change takes effect immediately — no restart. If it holds a value SolidPing cannot read as a boolean ("off", "no", …), auto-join is treated as disabled and a warning naming the organization and the value is logged, so a typo'd switch never silently lets people in.

Discord​

SP_DISCORD_CLIENT_ID=your-discord-client-id
SP_DISCORD_CLIENT_SECRET=your-discord-client-secret

Setup:

  1. Go to the Discord Developer Portal
  2. Create an application and open OAuth2
  3. Add redirect URL: {SP_BASE_URL}/api/v1/auth/discord/callback

After the provider sends you back​

Whatever the provider, the callback never puts your session in the URL. It stores the session server-side under a one-time code and sends the browser to {SP_BASE_URL}/d/auth/complete?code=…. The dashboard trades that code for the session with POST /api/v1/auth/handoff/exchange, then continues to the page you started from.

The code works once and expires after 60 seconds. Only its SHA-256 is stored. So a sign-in URL that ends up in browser history, a proxy log or a screenshot cannot be replayed. If you reverse-proxy SolidPing, nothing needs to change: /d/auth/complete is an ordinary dashboard page.

Member roles​

Every member of an organization holds one of four roles, ordered owner > admin > user > viewer. They are hierarchical: an owner can do everything an admin can, an admin everything a user can, and so on.

RoleWhat it can do
ownerEverything an admin can, plus deleting the organization, renaming it, and granting or revoking ownership
adminFull read/write on the organization's resources, plus member management
userRead/write on monitoring resources — checks, incidents, status pages, notifications
viewerRead everything, change nothing — except their own notification settings and their own API tokens

viewer is genuinely read-only: every state-changing API call is refused with 403 FORBIDDEN, including acknowledging or resolving an incident, which changes what the whole team is paged about. A viewer may still choose where they personally get notified, and mint their own API token — that token inherits their role, so it can automate reading and nothing more.

The rule is enforced from the member's current role, not from the token they are holding: demote someone to viewer and their very next request stops writing, without waiting for a sign-out or a token refresh. It applies to the REST API, personal access tokens and the MCP server alike.

If you want someone to acknowledge incidents, give them user.

Two-Factor Authentication (2FA)​

Users can secure their accounts with TOTP two-factor authentication (compatible with Google Authenticator, Authy, 1Password, etc.). 2FA is enabled per user from account settings — no server configuration is required.

  • Enrollment generates a TOTP secret (shown as a QR code) that the user confirms with a one-time code.
  • On confirmation, SolidPing issues recovery codes to use if the authenticator device is lost.
  • At login, users with 2FA enabled provide a code from their authenticator app (or a recovery code).

Configuration File​

auth:
jwt_secret: your-secure-random-secret
registration_email_pattern: "@yourcompany\\.com$"
password:
algorithm: argon2id # or "bcrypt"
argon2:
memory: 65536 # KiB
time: 3
threads: 4
key_length: 32
salt_length: 16
bcrypt:
cost: 12

google:
client_id: your-google-client-id
client_secret: your-google-client-secret

github:
client_id: your-github-client-id
client_secret: your-github-client-secret

gitlab:
client_id: your-gitlab-client-id
client_secret: your-gitlab-client-secret

microsoft:
client_id: your-microsoft-client-id
client_secret: your-microsoft-client-secret

slack:
client_id: your-slack-client-id
client_secret: your-slack-client-secret

discord:
client_id: your-discord-client-id
client_secret: your-discord-client-secret