Skip to content

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 Conflict once 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:

{
  "sub": "<user-uuid>",
  "role": "admin",
  "exp": 1711641600,
  "type": "access"
}

Login Flow

  1. Client sends POST /api/auth/login with username and password
  2. Server checks AUTH_MODE setting to determine which providers to try
  3. If AUTH_MODE is internal or all, tries internal password verification
  4. If internal auth fails and LDAP is enabled, attempts LDAP authentication
  5. On success, returns access token, refresh token, and user info
  6. The last_login_at timestamp 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_only permissions
  • 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 analyst permissions
  • 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-Key HTTP 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:

  1. Bearer JWT token first
  2. Falls back to X-API-Key if no Bearer token is provided
  3. Returns 401 Unauthorized if 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

  1. Service bind -- rimae/scan binds to the LDAP server using the service account credentials
  2. User search -- Searches for the user entry using the configured filter (with LDAP injection prevention via escape_filter_chars)
  3. User bind -- Attempts a simple bind with the user's DN and provided password
  4. Group resolution -- Checks group membership to determine the rimae/scan role
  5. Provisioning -- Creates or updates the user in the rimae/scan database with auth_provider=ldap

Role Mapping

Group membership is checked in priority order:

  1. If the user is a member of LDAP_ADMIN_GROUP_DN, they receive the admin role
  2. If the user is a member of LDAP_ANALYST_GROUP_DN, they receive the analyst role
  3. If the user is a member of LDAP_READONLY_GROUP_DN (or no group matches), they receive the read_only role

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. If LDAP_REQUIRE_TLS is true (the default), rimae/scan will reject plaintext ldap:// 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

  1. Frontend calls GET /api/auth/oidc/authorize to obtain the authorization URL, state, and nonce
  2. User is redirected to the OIDC provider's login page
  3. After authentication, the provider redirects back to /login with an authorization code
  4. Frontend sends the code, state, and nonce to POST /api/auth/oidc/callback
  5. rimae/scan exchanges the code for tokens at the provider's token endpoint
  6. The ID token is validated using the provider's JWKS (RS256 signing)
  7. Nonce is verified to prevent replay attacks
  8. Claims are mapped to a rimae/scan role
  9. User is provisioned or updated in the database with auth_provider=oidc
  10. 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

  1. Create a client in Keycloak with Client authentication enabled
  2. Set the Valid redirect URIs to https://rimae-scan.example.com/login
  3. Create a client scope or mapper that includes a roles claim
  4. 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.