Authentication & Authorization¶
rimae/scan supports three authentication methods: internal password authentication, LDAP directory integration, and OpenID Connect (OIDC) single sign-on. All three can be enabled simultaneously, and users are auto-provisioned on first login through LDAP or OIDC.
Setup Wizard¶
On first launch, when no users exist in the database, rimae/scan presents a setup wizard at /setup. This creates the initial admin account.
The setup endpoint (POST /api/auth/setup) accepts:
| Field | Constraints |
|---|---|
username |
3 -- 64 characters |
email |
Valid email address |
password |
8 -- 128 characters |
The created user is assigned the admin role and receives a JWT token pair (access + refresh) immediately.
Warning: The setup endpoint is only available when the database contains zero users. It returns
409 Conflictonce any user exists. Complete setup promptly after deployment.
Internal Authentication¶
Internal auth uses Argon2id-hashed passwords stored in the database and JWT tokens for session management.
JWT Tokens¶
rimae/scan issues two tokens on successful login:
| Token | Expiry | Purpose |
|---|---|---|
| Access token | 30 minutes | Passed as Authorization: Bearer <token> on API requests |
| Refresh token | 7 days | Exchanged for a new access token via POST /api/auth/refresh |
Tokens are signed with HS256 using the SECRET_KEY from rimae-scan.conf.
Token Payload¶
The JWT payload includes:
Login Flow¶
- Client sends
POST /api/auth/loginwithusernameandpassword - Server checks
AUTH_MODEsetting to determine which providers to try - If
AUTH_MODEisinternalorall, tries internal password verification - If internal auth fails and LDAP is enabled, attempts LDAP authentication
- On success, returns access token, refresh token, and user info
- The
last_login_attimestamp is updated on the user record
Token Refresh¶
Send the refresh token to POST /api/auth/refresh to receive a new access token. The refresh token must have "type": "refresh" in its payload.
User Roles¶
rimae/scan defines three roles with increasing privilege levels:
read_only¶
- View dashboards, vulnerability matches, assets, CVEs, advisories, and alerts
- Download exports
- Cannot modify any data
analyst¶
- All
read_onlypermissions - Update vulnerability match status (open, in_review, accepted_risk, resolved)
- Bulk-update vulnerability statuses
- Trigger GitHub repository scans
- View audit logs
- Create alerts
admin¶
- All
analystpermissions - Manage users (create, update roles, deactivate)
- Manage all settings (integrations, vuln sources, OS versions, apps, scoring, retention, branding)
- Trigger force actions (correlate, inventory, crawls)
- Toggle maintenance mode
- Configure authentication providers (LDAP, OIDC)
- Approve staged OS version discoveries
Note: Admins cannot remove their own admin role or deactivate their own account. This prevents accidental lockout.
API Key Authentication¶
API keys provide a non-interactive authentication method for scripts, CI pipelines, and integrations.
How API Keys Work¶
- API keys are passed via the
X-API-KeyHTTP header - The raw key is hashed with SHA-256 before storage; rimae/scan never stores the plaintext key
- Each API key is linked to a specific user account and inherits that user's role
- API keys can be individually deactivated without affecting the parent user
Authentication Priority¶
When both a Bearer token and an API key are present on a request, rimae/scan checks:
- Bearer JWT token first
- Falls back to
X-API-Keyif no Bearer token is provided - Returns
401 Unauthorizedif neither succeeds
LDAP Integration¶
rimae/scan integrates with LDAP directories including Active Directory, OpenLDAP, and FreeIPA. LDAP authentication uses a bind-search-bind pattern for secure user verification.
Configuration¶
LDAP is configured through environment variables in rimae-scan.conf or through the Settings UI:
| Setting | Description | Example |
|---|---|---|
LDAP_ENABLED |
Enable LDAP authentication | true |
LDAP_SERVER_URL |
LDAP server URL | ldaps://ldap.example.com:636 |
LDAP_BIND_DN |
Service account DN for searching | cn=rimae-scan,ou=services,dc=example,dc=com |
LDAP_BIND_PASSWORD |
Service account password | (secret) |
LDAP_USER_SEARCH_BASE |
Base DN for user searches | ou=users,dc=example,dc=com |
LDAP_USER_FILTER |
Search filter template | (uid={username}) |
LDAP_GROUP_SEARCH_BASE |
Base DN for group searches | ou=groups,dc=example,dc=com |
LDAP_ADMIN_GROUP_DN |
Group DN for admin role mapping | cn=rimae-scan-admins,ou=groups,... |
LDAP_ANALYST_GROUP_DN |
Group DN for analyst role mapping | cn=rimae-scan-analysts,ou=groups,... |
LDAP_READONLY_GROUP_DN |
Group DN for read-only role mapping | cn=rimae-scan-readers,ou=groups,... |
LDAP_REQUIRE_TLS |
Reject plaintext LDAP connections | true |
LDAP_TLS_VERIFY |
Verify TLS certificates | true |
LDAP_CA_CERT_PATH |
Path to CA certificate for TLS verification | /etc/ssl/certs/ca.pem |
Authentication Flow¶
- Service bind -- rimae/scan binds to the LDAP server using the service account credentials
- User search -- Searches for the user entry using the configured filter (with LDAP injection prevention via
escape_filter_chars) - User bind -- Attempts a simple bind with the user's DN and provided password
- Group resolution -- Checks group membership to determine the rimae/scan role
- Provisioning -- Creates or updates the user in the rimae/scan database with
auth_provider=ldap
Role Mapping¶
Group membership is checked in priority order:
- If the user is a member of
LDAP_ADMIN_GROUP_DN, they receive theadminrole - If the user is a member of
LDAP_ANALYST_GROUP_DN, they receive theanalystrole - If the user is a member of
LDAP_READONLY_GROUP_DN(or no group matches), they receive theread_onlyrole
Active Directory Example¶
LDAP_SERVER_URL=ldaps://dc01.corp.example.com:636
LDAP_BIND_DN=CN=rimae-scan-svc,OU=Service Accounts,DC=corp,DC=example,DC=com
LDAP_BIND_PASSWORD=<strong-password>
LDAP_USER_SEARCH_BASE=DC=corp,DC=example,DC=com
LDAP_USER_FILTER=(sAMAccountName={username})
LDAP_ADMIN_GROUP_DN=CN=rimae/scan-Admins,OU=Security Groups,DC=corp,DC=example,DC=com
LDAP_ANALYST_GROUP_DN=CN=rimae/scan-Analysts,OU=Security Groups,DC=corp,DC=example,DC=com
LDAP_READONLY_GROUP_DN=CN=rimae/scan-Readers,OU=Security Groups,DC=corp,DC=example,DC=com
FreeIPA Example¶
LDAP_SERVER_URL=ldaps://ipa.example.com:636
LDAP_BIND_DN=uid=rimae-scan,cn=sysaccounts,cn=etc,dc=example,dc=com
LDAP_BIND_PASSWORD=<strong-password>
LDAP_USER_SEARCH_BASE=cn=users,cn=accounts,dc=example,dc=com
LDAP_USER_FILTER=(uid={username})
LDAP_ADMIN_GROUP_DN=cn=rimae-scan-admins,cn=groups,cn=accounts,dc=example,dc=com
Warning: Always use
ldaps://in production. IfLDAP_REQUIRE_TLSistrue(the default), rimae/scan will reject plaintextldap://connections.
OIDC / SSO Integration¶
rimae/scan supports OpenID Connect for single sign-on with providers like Keycloak, Authentik, Azure AD, Okta, and Google Workspace.
Configuration¶
| Setting | Description | Example |
|---|---|---|
OIDC_ENABLED |
Enable OIDC authentication | true |
OIDC_ISSUER_URL |
Issuer URL (must serve /.well-known/openid-configuration) |
https://keycloak.example.com/realms/corp |
OIDC_CLIENT_ID |
Client ID registered with the provider | rimae-scan |
OIDC_CLIENT_SECRET |
Client secret | (secret) |
OIDC_SCOPES |
Requested scopes | openid profile email |
OIDC_ROLE_CLAIM |
JWT claim containing role information | roles |
OIDC_ADMIN_CLAIM_VALUE |
Claim value that maps to admin role | admin |
OIDC_ANALYST_CLAIM_VALUE |
Claim value that maps to analyst role | analyst |
Authorization Flow¶
- Frontend calls
GET /api/auth/oidc/authorizeto obtain the authorization URL, state, and nonce - User is redirected to the OIDC provider's login page
- After authentication, the provider redirects back to
/loginwith an authorization code - Frontend sends the code, state, and nonce to
POST /api/auth/oidc/callback - rimae/scan exchanges the code for tokens at the provider's token endpoint
- The ID token is validated using the provider's JWKS (RS256 signing)
- Nonce is verified to prevent replay attacks
- Claims are mapped to a rimae/scan role
- User is provisioned or updated in the database with
auth_provider=oidc - rimae/scan issues its own JWT tokens (access + refresh)
Role Mapping¶
The role claim (default: roles) is read from the ID token. It can be a string or an array:
{
"sub": "user-123",
"preferred_username": "jdoe",
"email": "jdoe@example.com",
"roles": ["admin"]
}
Mapping priority:
1. If the claim contains the OIDC_ADMIN_CLAIM_VALUE, assign admin
2. If the claim contains the OIDC_ANALYST_CLAIM_VALUE, assign analyst
3. Otherwise, assign read_only
JWKS and Discovery Caching¶
Both the OIDC discovery document and the JWKS are cached in memory for 1 hour to minimize latency. If the signing key rotates, the cache refreshes automatically on the next token validation.
Keycloak Example¶
- Create a client in Keycloak with Client authentication enabled
- Set the Valid redirect URIs to
https://rimae-scan.example.com/login - Create a client scope or mapper that includes a
rolesclaim - Configure rimae/scan:
OIDC_ENABLED=true
OIDC_ISSUER_URL=https://keycloak.example.com/realms/corp
OIDC_CLIENT_ID=rimae-scan
OIDC_CLIENT_SECRET=<client-secret>
OIDC_ROLE_CLAIM=roles
OIDC_ADMIN_CLAIM_VALUE=rimae-scan-admin
OIDC_ANALYST_CLAIM_VALUE=rimae-scan-analyst
Auth Mode¶
The AUTH_MODE environment variable controls which internal authentication methods are active:
| Mode | Behavior |
|---|---|
internal |
Only internal password auth is enabled on the login endpoint |
all |
Both internal and LDAP are tried (internal first, then LDAP fallback) |
OIDC operates independently via its own endpoints (/api/auth/oidc/authorize and /api/auth/oidc/callback) and is controlled by the OIDC_ENABLED flag.
Checking Available Providers¶
The GET /api/auth/providers endpoint returns which methods are currently enabled:
{
"internal_enabled": true,
"ldap_enabled": false,
"oidc_enabled": true,
"oidc_provider_name": "keycloak.example.com"
}
The frontend uses this response to display the appropriate login options.
Related Documentation¶
- Settings Reference -- Full settings panel documentation
- API Reference -- Auth endpoint details and examples
- Troubleshooting -- Common auth issues and solutions