Authentication¶
Signing in¶
Access to the VirtualSutra AI console is controlled by your administrator. Contact them to request access or reset your credentials.
OAuth / Single Sign-On¶
The console supports sign-in via your company identity provider. Depending on what your administrator has configured, you will see one or more provider buttons on the sign-in page:
- Google Workspace - sign in with your company Google account
- Microsoft 365 / Entra ID - sign in with your Microsoft work account
- GitHub - sign in with your GitHub organisation account
- SSO / OIDC - any OIDC-compatible provider (Okta, Auth0, Keycloak, etc.), shown with a custom label set by your admin
Click the button for your provider. You will be redirected to your identity provider to authenticate and then returned to the console.
The built-in admin account¶
Every self-hosted deployment (the default paas profile and airgap) has one built-in local account, admin, beside any OAuth / SSO provider. It is created the first time the API starts, as an administrator of the deployment's organisation, with an initial password that must be changed at the first sign-in. The initial credential is not printed in this documentation: VirtualSutra support provides it on request, together with the release (write to support@virtualsutra.com).
Change the initial password immediately after install
Until it is changed, anyone who can reach the console and knows the initial credential can sign in as admin and take the account. Sign in and set your own password as soon as the deployment is up, before you expose the console to anyone else.
First sign-in. Choose Sign in with the built-in admin account on the sign-in page (when no OAuth provider is configured, the console opens the username and password form directly), and sign in as admin with the initial password you received from VirtualSutra support. The console then shows only Set a new password: nothing else works for this account until the password is changed - the API refuses every other request it makes with 403 password_reset_required. The new password:
- must be at least 12 characters long (and at most 72 bytes);
- must not be the initial password, or the current one.
You are asked for the current password again when you change it. After the change you are signed in with the new password, and the initial password no longer works. Every password change or reset ends every other session of the account - including one someone opened with the initial password before you.
Once there is another administrator. When the deployment's organisation has another enabled administrator - for example one who signs in through SSO - the initial password is refused (403 initial_password_disabled): an account still on it can no longer be signed in to, and that administrator is the way in. A password that was already changed is unaffected.
Wrong password. The sign-in form says only that the username or password is wrong, whichever it was. Failed sign-ins are counted in a fixed 15-minute window that starts at the first counted attempt: the sixth attempt from one address (or the 21st for the username, from anywhere) answers "too many attempts", even with the right password, until that window ends. The per-username limit is deliberate: it is what stops a guesser that changes address, and its price is that anyone who can reach the sign-in page can keep the built-in account locked for as long as they keep sending wrong passwords (about two a minute is enough). Sign in through your identity provider meanwhile, or clear the lockout with reset-local-admin (below). The per-address limit counts the address your proxy reports (TRUSTED_PROXY_HOPS on the console, default one proxy). With no address the console can derive (no proxy in front of it, or TRUSTED_PROXY_HOPS=0), every client shares one per-address counter, so five failed sign-ins from anyone hold off everyone for the window.
Forgotten admin password. Someone with access to the API container can put the initial password back, with the forced change set again:
(for example kubectl exec deploy/<release>-api -- python -m api_service reset-local-admin, or docker compose exec api python -m api_service reset-local-admin). Sign in with the initial password you received from VirtualSutra support and set a new one straight away - the same takeover window applies.
Not on SaaS. The hosted (saas) profile does not create the built-in account; there, sign in through your identity provider.
htpasswd is gone. Earlier releases offered username and password sign-in from an htpasswd file. That is removed: htpasswd users can no longer sign in. The HTPASSWD variable and an htpasswd field in Vault are ignored; the Helm chart refuses to render with ui.htpasswd, vault.htpasswdRoles or a ui.waitForVaultSecret.keys that names htpasswd, so drop those before you upgrade. Sign in as admin, then give people access through OAuth / SSO.
Forgotten credentials¶
Contact your administrator. For OAuth deployments, password resets are handled directly by your identity provider. For the built-in admin account, see above.
Session management¶
OAuth sessions are signed JWT cookies encrypted with AUTH_SECRET. They expire automatically. If you are redirected to the sign-in page unexpectedly, sign in again.
A built-in admin session is a cookie signed with HMAC-SHA256 using the console's SESSION_SECRET (at least 32 bytes; the console refuses password sign-in without it) and expires after 8 hours.
Programmatic / API access¶
For CI/CD pipelines or scripts, ask your administrator for an API key. Include it on all requests:
Named API keys with RBAC scopes¶
You can create, name, and revoke your own API keys via the self-service endpoint:
POST /users/me/api-keys
X-API-Key: <your-existing-key>
Content-Type: application/json
{"name": "ci-pipeline", "scopes": ["read", "findings:write"]}
The response includes a raw_key field returned once only - store it securely.
Named keys support granular RBAC scopes (read, write, schedule:write, schedule:read, reports:read, notifications:read, findings:write, remediation:approve, scan:agent, admin, debug). A key with no explicit scope list - an API_KEYS env-var key, or a row predating the column - receives every scope except platform:admin.
Administrators can also create org-level keys via POST /api-keys and view audit logs via GET /api-keys/{key_id}/events.
Service accounts and JWT tokens¶
When your administrator has enabled the External API, you can use service accounts with short-lived JWT bearer tokens instead of static API keys:
# Exchange client credentials for a JWT + refresh token
curl -X POST https://vsutra.yourcompany.com/auth/token \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET"
# Response: {"access_token": "...", "refresh_token": "...", "expires_in": 3600}
# Use the JWT on API calls
curl https://vsutra.yourcompany.com/runs \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Silently renew the JWT using the refresh token (no client_secret needed)
curl -X POST https://vsutra.yourcompany.com/auth/token \
-d "grant_type=refresh_token" \
-d "refresh_token=$REFRESH_TOKEN"
Refresh token rotation: each refresh token exchange issues a new refresh token and revokes the old one. Always store the latest refresh token from the response.
Contact your administrator to create a service account and obtain the client_id and client_secret.