Skip to content

User Management

Manage system users, passwords, roles, two-factor authentication, and OIDC single sign-on.


User List

Go to System → Users to see all users with their username, role, and tenant assignment.


Creating a User

  1. Click Create User
  2. Fill in:
  3. Username
  4. Password
  5. Roleviewer, operator, tenant-admin, or super-admin (only super-admins can grant the last two)
  6. Tenant — which tenant this user belongs to
  7. Click Create

The user can immediately log in with the provided credentials.

Users created in the UI are local WatchGrid users. OIDC users are created automatically on first successful SSO login when auto-provisioning is enabled.


Roles

Role Capabilities
super-admin Full access across all tenants — only super-admins can create other super-admins or tenant-admins
tenant-admin Full access to all features within their tenant
operator Day-to-day operations (deploy apps, approve devices, run terminal sessions)
viewer Read-only access to apps and devices

Super-admins in the default tenant can manage all tenants and system-wide settings.


Changing Your Password

  1. Go to System → Users
  2. Click Change My Password
  3. Enter your current password, new password, and confirmation
  4. Click Change Password

For OIDC-backed users, this sets or rotates the local fallback password stored in WatchGrid. SSO login itself remains controlled by your identity provider, and the current password field can be left empty when setting that fallback for the first time from an active SSO session.


Deleting a User

Click the Delete button next to any user in the list. This requires confirmation.


Session Settings

The Session card at the top of System → Users (admin-only) controls how all interactive sessions in this tenant behave.

Setting Default What it does
Session timeout (minutes) 60 New sign-ins receive a JWT that expires after this many minutes. Range: 5–1440. Existing sessions keep their original expiry until they're renewed by a fresh login.
Bind session to IP On When enabled, the client IP at login is embedded in the JWT. Any subsequent request from a different IP is rejected with 401, forcing the user to sign in again. Useful for catching token-theft scenarios; can be disruptive for mobile users handing off between cellular and Wi-Fi.

These values are stored in the system_settings table and read on every auth check (1-minute in-memory cache). They apply to all users in the tenant.

The IP is detected from X-Forwarded-For, X-Real-IP, or RemoteAddr in that order — so behind a reverse proxy you'll see the real client IP, not the proxy's address.

Migration note: tokens minted before this feature have no IP claim. They are grandfathered (skip the IP check) until they expire so that turning IP binding on doesn't immediately sign every active user out.

Tokens issued for the Docker registry (docker login) are deliberately not IP-bound — the docker daemon connects from a different code path than the browser, and binding would break image pushes.


Two-Factor Authentication (2FA)

Watchgrid supports TOTP-based two-factor authentication, compatible with Google Authenticator, Authy, 1Password, and other TOTP apps.

Enabling 2FA

  1. Go to System → Users
  2. Click 2FA Settings
  3. The setup wizard shows a QR code
  4. Scan the QR code with your authenticator app
  5. Enter the 6-digit verification code to confirm
  6. 2FA is now active for your account

Logging In with 2FA

  1. Enter your username and password as usual
  2. A second screen asks for your 6-digit verification code
  3. Enter the code from your authenticator app
  4. You're logged in

OIDC / SSO Login

The login page can show a Login with SSO button backed by an OpenID Connect provider. WatchGrid exchanges the authorization code server-side, reads the user profile from the provider's userinfo endpoint, and then creates the normal WatchGrid session cookie.

Super-admins configure this on its own page at System → SSO. Settings are saved on the server and survive restarts — no environment variables required.

Environment variable fallbacks

All OIDC settings can alternatively be provided via environment variables. These are read as fallbacks when no value is saved in the UI. Useful for automated deployments or infrastructure-as-code setups.

Variable Description
OIDC_ISSUER_URL Provider discovery URL (recommended)
OIDC_CLIENT_ID Application client ID
OIDC_CLIENT_SECRET Application client secret
OIDC_AUTH_URL Authorization endpoint (if no discovery)
OIDC_TOKEN_URL Token endpoint (if no discovery)
OIDC_USERINFO_URL Userinfo endpoint (if no discovery)
OIDC_PROVIDER_NAME Display name, default SSO
OIDC_BUTTON_TEXT Login button label, default Login with SSO
OIDC_SCOPES Default openid profile email
OIDC_USERNAME_CLAIM Default preferred_username
OIDC_DEFAULT_TENANT_ID Tenant for auto-provisioned users, default tenant-default
OIDC_DEFAULT_ROLE Role for auto-provisioned users, default tenant-admin
OIDC_AUTO_PROVISION Default true
OIDC_AUTO_LINK_USERS Default true

Provider Setup: Microsoft Entra ID (Office 365)

  1. Go to portal.azure.comMicrosoft Entra IDApp registrationsNew registration
  2. Fill in:
  3. Name: Watchgrid (or any name you like)
  4. Supported account types: Accounts in this organizational directory only
  5. Redirect URI: select Web and enter https://your-watchgrid-domain/api/auth/oidc/callback
  6. Click Register
  7. Note the Application (client) ID and Directory (tenant) ID from the Overview page
  8. Go to Certificates & secretsNew client secret → choose an expiry → click Add
  9. Copy the secret Value immediately (it is only shown once)

Then configure Watchgrid in System → Users → Single Sign-On:

Field Value
Enabled On
Issuer URL https://login.microsoftonline.com/{Directory tenant ID}/v2.0
Client ID Application (client) ID from Azure
Client Secret Secret value from step 6
Scopes openid profile email
Username claim preferred_username (maps to the user's UPN / email)
Button text Login with Microsoft (or anything you like)

The login page will show the button immediately after saving.

Behavior

  • If the SSO user matches an existing WatchGrid username and auto-linking is enabled, WatchGrid links that user to the OIDC subject and reuses the existing role and tenant access.
  • If the SSO user is new and auto-provisioning is enabled, WatchGrid creates the user automatically with the configured default tenant and role.
  • In System → Users, the user list shows each account's auth source as local or oidc.

Reverse Proxy / HTTPS

If Watchgrid runs behind a reverse proxy that does not forward X-Forwarded-Proto, the OIDC redirect_uri may be built with http:// instead of https://, causing most providers to reject the callback. Set the WATCHGRID_EXTERNAL_URL environment variable to fix this:

WATCHGRID_EXTERNAL_URL=https://yourdomain.com

This overrides auto-detection and ensures the correct scheme and host are used in the redirect URI.


First-Time Onboarding

When a user logs in for the first time (or after being created by an admin), they may see an onboarding wizard that guides them through:

  • Setting a new password
  • Configuring initial preferences
  • Optional 2FA setup

This ensures every user has a secure, personalized account from the start.

Security Notes

OIDC Issuer URL Validation

The OIDC issuer URL is validated before Watchgrid fetches the discovery document. The URL must use HTTPS, and the hostname must not resolve to a loopback, private, or link-local address. This prevents server-side request forgery (SSRF) via a misconfigured or malicious issuer URL.

JWT Secret Strength

JWT_SECRET must be at least 32 characters (256 bits). The server will refuse to start with a shorter secret. Generate a secure secret with:

openssl rand -hex 32

GDPR — Data-Subject-Access Requests

Two super-admin-only endpoints implement the GDPR Article 15 (right of access) and Article 17 (right to erasure) obligations for user accounts:

Export (Article 15)

curl -fsS -b session.cookie \
     -H "X-CSRF-Token: $(grep watchgrid_csrf session.cookie | awk '{print $NF}')" \
     "https://watchgrid.example.com/api/users/alice/export" \
     > gdpr-export-alice-$(date +%Y%m%d).json

The response bundles every row across users, admin_audit_log, device_security_log, ssh_certificates, license_audit_log, and device_profile_runs that references the given username. The password hash and 2FA secret in the user section are redacted.

Purge (Article 17)

curl -fsS -X DELETE -b session.cookie \
     -H "X-CSRF-Token: $(grep watchgrid_csrf session.cookie | awk '{print $NF}')" \
     "https://watchgrid.example.com/api/users/alice?purge=true"

The purge runs inside a transaction and:

  1. Writes a user_gdpr_purge entry to the audit log before deleting, so the action survives its own cascade.
  2. Deletes rows in ssh_certificates, admin_audit_log, license_audit_log, and device_profile_runs that reference the user.
  3. Redacts device_security_log.details — the log row is kept because it pertains to the device, but any JSON value equal to the purged username is replaced with "<purged>".
  4. Deletes the users row itself.

A regular DELETE /api/users/alice (without ?purge=true) keeps its existing behaviour of removing the login while leaving historic references intact — prefer this for "off-boarding" flows and reserve the purge=true variant for genuine data-subject-erasure requests.

Retention notes for regulated customers

The Audit Log Retention sweeper will eventually delete the residual device_security_log rows that survived the purge; run the sweeper (or a manual archive-to-object-storage job) within your regulatory deadline. Document the GDPR purge evidence in your DPIA — the server-side user_gdpr_purge audit entry is the authoritative record.